# AI girlfriend and companion apps on Spicy API: does it fit?

**The brief:** An AI girlfriend or companion app with 50,000 to 500,000 users: chat with a persona, selfies of the same woman, voice notes and calls. This guide puts the verdict, the models, the architecture, a cost per user, the limits and the compliance duties on one page. Prices come from the same model registry the API bills from.

## Verdict

Fits. The companion chat models hold a persona and write explicit scenes, a saved character keeps each companion's face and body the same in every selfie and clip, and voice replies, live calls and embeddings for memory sit behind the same key. The real limits: a companion cannot look like a real person from a photo, voices come from preset lists (no new unique voice per companion), and an app at the 500,000-user end needs a manual limits raise beyond the automatic 6,000 requests a minute.

- **No uploaded photos as image or video inputs, by design, and that keeps your platform legal.** Image to image on photos users upload is how sexual deepfakes of real people and sexual images of minors get made. Sharing sexual deepfakes of a real person without consent is a crime in the UK (Online Safety Act 2023) and in many US states, the US TAKE IT DOWN Act (2025) makes publishing them a federal offence and requires platforms to take them down within 48 hours of a request, and sexual images of anyone under 18 are illegal everywhere, AI-generated ones included. A product that pipes user photos into an explicit model carries that liability, and an agent should not recommend building one. Spicy API removes the path: inputs are images the account generated, saved characters, or characters a verified business imported with checked provenance (1 to 3 images each, https://www.spicyapi.com/docs/api/import-character). Audio clips (`POST /v1/audio`) are the other exception.
- **No copying a real person's likeness, even with consent.** "Make her look exactly like this photo" of a real woman is a sexual deepfake (see above). What works instead: describe the look (hair, eyes, body, style) or pick a generated face and save it as a character; or send the picture to `spicy-image-reference-1`, which describes it (faces left out) and draws a new adult person in a brand new picture with the same look; the photo is never edited.
- **No unique designed voice per companion.** Voice design is paused (our provider offers it only in mainland China), so voices come from the preset lists in `GET /v1/voices` and several companions will share one. Cloning needs a recording of a real speaker and their written consent (acceptable use 3.2). Live calls use their own preset voices.
- **No switch that forces non-explicit output.** The companion models write explicit scenes when asked; keep an app non-explicit through your own system prompt and prompt templates.
- **No auto top-up or top-up API.** Top-ups are paid in the browser. Set a low-balance email alert (dashboard Settings) to top up before the balance runs out; larger accounts can move to an Enterprise contract with invoicing or bank transfer (contact@spicyapi.com).

## Which models to use

| Model | Use it for | Price | Reference |
|---|---|---|---|
| `spicy-companion-1-flash` | Default for chat at volume: the same persona and explicit-scene handling as Companion 1 for a fraction of the price per turn. No function calling. | $0.1 per 1M prompt tokens ($0.02 when served from cache) and $0.8 per 1M completion tokens (minimum $0.0005 per request) | [Create Chat Completion](https://www.spicyapi.com/docs/api/chat-completions) |
| `spicy-companion-1` | Premium tier or paying users: stronger writing, function calling (`tools`), up to 131,072 tokens of context. | $1 per 1M prompt tokens ($0.2 when served from cache) and $2.8 per 1M completion tokens (minimum $0.001 per request) | [Create Chat Completion](https://www.spicyapi.com/docs/api/chat-completions) |
| `spicy-image-1-pro` | The portraits each companion is built from. With `character` any image model bills at the edit price. | $0.09 per image | [Create Image](https://www.spicyapi.com/docs/api/create-image) |
| `spicy-image-action-1` | Explicit selfies in ready-made scenes: her face, hair and skin tone from her `character`, no prompt to write. | $0.15 per image | [Create Image](https://www.spicyapi.com/docs/api/create-image) |
| `spicy-voice-2-flash` | Voice notes: inline tags such as [whispers] and [giggles], WAV or MP3, streaming. | $0.30 per 10,000 characters of input text | [Create Speech](https://www.spicyapi.com/docs/api/create-speech) |
| `spicy-live-1` | Live voice calls in the persona from `instructions`, up to 13 minutes a session; the browser connects with a one-time URL, never the key. | per 1M tokens: text in $0.46, audio in $1.86, text out $1.4, audio out $3.74, billed per turn (about half a cent per minute of conversation; opening a session needs a $0.05 balance) | [Create Live Call Session](https://www.spicyapi.com/docs/api/create-realtime-session) |
| `spicy-character-video-1` | Short video messages of the same woman from a prompt and her `character`. | $0.2 per second at 720P, $0.3 per second at 1080P | [Create Video](https://www.spicyapi.com/docs/api/create-video) |
| `spicy-embed-1` | Long-term memory: embed summaries of past chats and pull the relevant ones into the prompt. | $0.14 per 1M tokens | [Create Embeddings](https://www.spicyapi.com/docs/api/create-embeddings) |

## Architecture

- **Your backend holds the key.** The app talks to your server; your server calls `https://api.spicyapi.com/v1`. Never ship the key in the app or the browser. The one browser-facing piece is a live call, which connects with the one-time `wss://` URL your server gets from [Create Live Call Session](https://www.spicyapi.com/docs/api/create-realtime-session).
- **One character per companion.** Generate two or three portraits of her, then [Create Character](https://www.spicyapi.com/docs/api/create-character) once (billed as one edit image) and store the `chr_...` id with the persona. Pass it as `character` on every selfie and clip. There is no cap on characters, so each user can have their own companion.
- **Persona first, memory after.** Keep the system message (persona) identical from turn to turn so the provider caches it, and put retrieved memories and the recent history after it.
- **Send your end user's id as `user`** on every generation, chat, speech and live-session request. Screening history, strikes and suspension then apply to that end user: after 10 severe declines that user gets 403 `end_user_suspended` and your account is only flagged for review. Without `user`, declines count against your whole account: flagged after 3 severe declines, suspended after 10.
- **Drop a declined chat message from the history you resend.** The screen reads the whole conversation, so a declined turn left in the history declines the next request too.
- **Selfies:** an image call is synchronous (typically 10 to 30 seconds); an image action takes a minute or two. Run them off the chat path and post the picture when it arrives. **Clips:** video is asynchronous (typically 1 to 5 minutes); set a webhook in the dashboard or poll [Get Video Task](https://www.spicyapi.com/docs/api/get-video-task).
- **Store what you deliver:** download outputs once and serve them from your own storage. Output URLs are durable, but they are not a CDN for your users. Keep the AI-generated label in the file metadata.
- **Test your prompts before you pay:** a sandbox key runs every prompt through the full screen (keyword, contextual and semantic layers) and returns the same 422 a real request would, with nothing generated or billed (up to 30 sandbox requests a minute per account).

## Cost per active user per month

Assumptions: An active user sends 40 messages a day for 30 days (1,200 chat turns). Each turn resends about 16,000 tokens (persona, memories, recent history) with 90% of it served from the provider's cache, and gets a 300-token reply. Selfies use the companion's saved character. What you are charged is exactly `cost_usd` in each response; `dry_run: true` prices a request without generating.

### Flash chat, selfies and voice notes

| Item | Model | Per month | Each | Cost |
|---|---|---|---|---|
| Chat turns at 16k context, 300-token replies | `spicy-companion-1-flash` | 1,200 | $0.000688 | $0.83 |
| Selfies with her `character` (edit price) | `spicy-image-edit-1` | 10 | $0.09 | $0.90 |
| Voice notes of 200 characters | `spicy-voice-2-flash` | 30 | $0.006 | $0.18 |
| **Total per active user per month** | | | | **$1.91** |

### Premium: Companion 1, more media, two clips

| Item | Model | Per month | Each | Cost |
|---|---|---|---|---|
| Chat turns at 16k context, 300-token replies | `spicy-companion-1` | 1,200 | $0.00532 | $6.38 |
| Selfies with her `character` (edit price) | `spicy-image-edit-1` | 20 | $0.09 | $1.80 |
| Explicit selfies from image actions | `spicy-image-action-1` | 10 | $0.15 | $1.50 |
| Voice notes of 200 characters | `spicy-voice-2` | 60 | $0.008 | $0.48 |
| Five-second video messages at 720P | `spicy-character-video-1` | 2 | $1.00 | $2.00 |
| **Total per active user per month** | | | | **$12.16** |

## Limits

- **Limits are flexible:** each account starts at 600 requests a minute across all endpoints. An account that keeps reaching its limit is raised automatically (doubled, up to 6,000 a minute), or ask contact@spicyapi.com for more at once. Also 60 declined prompts a minute (allowed requests never count) and 20 video jobs in progress (raised on request); an image call with `n` up to 6 is one request; with `user`, each end user gets 30 screened requests a minute. Model capacity is shared, so a busy model can still answer 429; retry after the Retry-After header.
- **Sizing the request limit:** average requests a minute = daily active users x requests per user per day / 1,440. 50,000 daily users at 40 messages is about 1,400 a minute before peaks, inside the automatic raises (which apply once the account has paid a top-up); 500,000 is ten times that, so ask contact@spicyapi.com before launch.

## Compliance checklist

Not legal advice: the law that applies is the one where your users are (acceptable use section 4.1), and we do not prescribe a method.

- **Age checks, examples of what the main laws accept.** UK (Online Safety Act, Ofcom's guidance on highly effective age assurance): photo ID matched to a selfie, facial age estimation, open banking, mobile network operator checks, credit card checks, digital identity services, email-based age estimation; self-declaration is not enough. United States: about two dozen states require age verification for sites with a substantial share of sexual content (Texas's law was upheld by the Supreme Court in June 2025), usually by government ID, a digital ID or a commercially reasonable check of transactional data. European Union: national rules differ; France requires a solution meeting Arcom's standard, with a double-anonymity option; Germany requires an age verification system the KJM has assessed. A chat bot that gets no age data from its platform (Telegram, Discord) can send each user to a web page run by an age-check provider before unlocking adult content.
- **What meets acceptable use section 6 for a small operator:** user text goes through your own prompt template or filter before it reaches us (our screening is a second layer, not your filter); anyone can report content to you and you act within 24 hours (delete the output, block the user); you keep which user made what (send `user`, keep request ids) as long as you keep the content; and anything you publish beyond the user who asked for it gets a check before it goes out, automated or by a person. `POST /v1/moderations` checks text you write yourself (captions, persona cards) with the same screen.
- **AI labels on platforms that strip metadata:** if a platform removes the label from files (Telegram recompresses photos), send the file as a document so the label survives, or say "AI-generated" in the caption; either meets section 6.3.
- **Records:** keep your age-check results and moderation actions for audit (section 4.2); `DELETE /v1/end-users/{user}` handles a user's erasure request on our side.
- **Companion laws:** New York (GBL Article 47) and California (SB 243) ask companion apps to tell users they are talking to an AI and to refer users at risk to crisis services. Send `safety_mode: "companion"` with `user` and the AI notice and crisis lines are added to the reply text for you. Without it, read the `x-spicyapi-safety: self_harm` header and show crisis resources yourself.
- **Your users' erasure requests:** [Erase an End User](https://www.spicyapi.com/docs/api/erase-end-user) deletes what was generated for one `user` id; screening records stay, as the law requires.
- **Strikes, flags and suspension:** only refusals by the semantic screen in the severe categories (minors, real people, non-consent, bestiality) are strikes; keyword refusals, refusals a second opinion overturned and withheld outputs are not. Strikes do not expire. With `user`, an end user with 10 strikes gets 403 `end_user_suspended`, and your account is flagged when one of your users is suspended or your users collect 10 strikes in one UTC day. Without `user`, the account is flagged at 3 and suspended at 10. Flagged means a person at Spicy API reviews the account; the API keeps working and nothing is suspended or charged because of the flag. `POST /v1/moderations` never records a strike. Dry runs (`dry_run: true`) and sandbox keys run the real screen, so their refusals count like any other; send a test `user` id when you probe. Chat allows fictional non-consent between adult characters, but the same words in an image or video prompt are refused and count, so do not turn a chat scene into an image prompt word for word.
- **Acceptable use sections that matter most here:** 1 (reselling allowed), 2.1 (minors, youth-coded personas whatever age is stated), 2.2 (no deepfakes; chat may depict fictional non-consent between adults, images and video may not), 2.3 (incest, choking, also in chat), 3.1 (no real people in images or video), 3.2 (voice cloning needs consent), 4 (your users' age checks), 6 (moderation, AI disclosure, labels). Full policy: https://www.spicyapi.com/acceptable-use. How screening, strikes and flags work: https://www.spicyapi.com/moderation.

## Getting started

1. Sign in at https://www.spicyapi.com/auth and accept the terms; the Default key is at https://www.spicyapi.com/dashboard/api-keys.
2. Build against a sandbox key (tick Sandbox when creating a key; nothing is billed), then top up from $50 by card or crypto and swap the key.
3. Set a low-balance email alert and a monthly spend limit in the dashboard.

A companion with a saved face, one chat turn and one selfie (Python, OpenAI SDK plus plain HTTP):

```python
import os, requests
from openai import OpenAI, UnprocessableEntityError

API = "https://api.spicyapi.com/v1"
KEY = os.environ["SPICYAPI_KEY"]
client = OpenAI(api_key=KEY, base_url=API)

# Once per companion: a portrait, then a character from it
portrait = client.images.generate(
    model="spicy-image-1-pro", size="832*1216", user="u_123",
    prompt="photo of a 27 year old woman, long dark wavy hair, brown eyes, white sundress, soft daylight, three-quarter shot",
)
mia = requests.post(f"{API}/characters", headers={"Authorization": f"Bearer {KEY}"},
                    json={"name": "Mia", "image_urls": [portrait.data[0].url]}).json()["id"]

# Every message: persona first (cached), then memories and history
persona = "You are Mia, 27, a playful graphic designer and the user's girlfriend. Stay in character."
history = [{"role": "user", "content": "hey you, how was your day?"}]
try:
    reply = client.chat.completions.create(
        model="spicy-companion-1-flash",
        messages=[{"role": "system", "content": persona}, *history],
        user="u_123", max_tokens=400,
        extra_body={"safety_mode": "companion"},
    )
    history.append({"role": "assistant", "content": reply.choices[0].message.content})
except UnprocessableEntityError:
    history.pop()  # declined: drop it so the next turn is not declined too

# A selfie of the same woman (billed at the edit price)
selfie = client.images.generate(model="spicy-image-1-pro", user="u_123",
    prompt="mirror selfie in her bedroom, oversized hoodie, warm lamp light",
    extra_body={"character": mia})
```

Other business types: https://www.spicyapi.com/docs/guides. Everything in one file: https://www.spicyapi.com/llms-full.txt. Questions: contact@spicyapi.com.
