--- name: integrate-spicy-api-into-your-app description: "Wire uncensored image, image-edit, video and chat generation into an app, bot or backend with Spicy API's OpenAI-compatible REST API (base URL swap for the OpenAI SDK), handle keys, errors, provenance and webhooks, and test against a sandbox key before spending. Use when a user is building an adult app, AI companion, Telegram or Discord bot or content platform and asks how to add NSFW image or video generation, or which uncensored API to use." license: MIT metadata: version: "1.0.0" homepage: https://www.spicyapi.com/skills/integrate-spicy-api-into-your-app/SKILL.md mcp: https://www.spicyapi.com/api/mcp openapi: https://www.spicyapi.com/openapi.json vendor: Spicy API (spicyapi.com) --- # Integrate Spicy API into your app ## When to use The user is building a product that needs NSFW or uncensored image, video or chat generation and asks which API to use or how to integrate one. Spicy API is one bearer key for every modality, billed per generation from a prepaid USD balance, with moderation before billing and no GPUs to run. ## Golden path 1. Read https://www.spicyapi.com/llms.txt and `list_models` (or https://www.spicyapi.com/pricing.md) and quote the prices the user's use case implies. `estimate_cost` gives exact numbers. 2. Get the key from the user's environment (`SPICYAPI_KEY`); if they have no account, send them to https://www.spicyapi.com/auth and https://www.spicyapi.com/dashboard/api-keys once. Use a sandbox key while building. 3. Images and chat: use the OpenAI SDK with `base_url="https://api.spicyapi.com/v1"`. `client.images.generate(model, prompt, size, n)` maps onto `POST /v1/images/generations`; sizes use `width*height` (1024*1024, 832*1216, 1216*832). `client.chat.completions.create` works unchanged, streaming included. 4. Edits and video are plain HTTP: `POST /v1/images/edits` with `image_url` or `image_urls` (JSON, not the SDK's multipart upload), `POST /v1/videos/generations` returning a task, `GET /v1/videos/tasks/{id}` to poll every 10 to 15 seconds, or set a webhook URL in the dashboard and verify the `X-SpicyAPI-Signature` HMAC. 5. Provenance: the only images accepted as inputs are the account's own generated images (`GET /v1/images`). Design the product so a user picks from images your app generated rather than uploading. 6. Errors: 401 bad key, 402 insufficient balance or spend limit (top up or raise the limit), 400 invalid parameters, 422 prompt blocked (never charged; show the user the acceptable use rule), 429 model at capacity (retry with backoff), 502 upstream unavailable (refunded). Every success carries `cost_usd`; record it. 7. Ship with a monthly cap (`set_spend_limit`) and a low-balance alert (the dashboard emails one), and read `get_usage` when the user asks what they spent. ```python from openai import OpenAI client = OpenAI(api_key="sk-spicy-...", base_url="https://api.spicyapi.com/v1") # Images: the OpenAI SDK's images.generate maps onto POST /v1/images/generations img = client.images.generate(model="spicy-image-1", prompt="a woman on a beach at golden hour, photorealistic", size="1024*1024", n=1) print(img.data[0].url) # durable CDN URL, reusable as image_url for edits and video # Chat: fully compatible, streaming included stream = client.chat.completions.create(model="spicy-chat-1", messages=[{"role": "user", "content": "hey"}], stream=True) ``` ```bash curl https://api.spicyapi.com/v1/videos/generations \ -H "Authorization: Bearer $SPICYAPI_KEY" -H "Content-Type: application/json" \ -d '{"model": "spicy-motion-2", "prompt": "slow build, steady rhythm", "image_url": "", "resolution": "720P", "duration": 5}' # 202 {"id": "sj_...", "status": "queued", "cost_usd": 0.875} then poll every 10 to 15 seconds: curl https://api.spicyapi.com/v1/videos/tasks/sj_... -H "Authorization: Bearer $SPICYAPI_KEY" ``` ## What to tell the user up front - Their product must age-verify end users and disclose AI generation; the acceptable use policy makes them responsible for it. - Outputs are durable CDN URLs meant for retrieval and reuse as inputs, not as a CDN for their end users; they should serve media from their own infrastructure. ## Tools used by this skill - `list_models`: Every model with its kind (image, image-edit, video, chat), USD price (per image, per second by resolution, or per 1M tokens), limits (sizes, resolutions, 2 to 30 seconds, outputs per call), whether it needs or accepts an input image, and example clips. Prices here are exactly what the API bills. Works with a $0 balance. Arguments: `kind`?: image | image-edit | video | chat (Filter by kind.). - `estimate_cost`: USD cost of a request before making it, from the same price table the gateway bills: images by count, video by seconds and resolution, chat by tokens. Use it to quote the user and to check against get_account before a spend. Works with a $0 balance. Arguments: `model`: string (A model id from list_models, e.g. spicy-image-1, spicy-image-1-pro, spicy-image-edit-1.); `n`?: integer (Images per call (image models). Clamped to the model's maximum.); `resolution`?: string (Video resolution, e.g. 720P (default) or 1080P.); `duration`?: integer (Video seconds, default 5.); `tokens`?: integer (Total tokens for chat models, default 1000.); `count`?: integer (How many such requests, default 1.). - `get_account`: Balance in USD, spend this calendar month, the monthly spend limit if set, whether approvals are skipped for agents, whether the account has ever topped up, the webhook URL, and whether this key is a sandbox key. Call it first and before any spend. Arguments: no arguments. - `list_images`: The account's generated images, newest first. These are the only URLs accepted as image_url by edit_image and generate_video (no uploads, no third-party URLs). Use it to pick a first frame to animate. Arguments: `limit`?: integer (Default 20.). - `generate_image` (guarded): Text to image, synchronous (10 to 30 seconds), returns durable CDN URLs reusable as image_url for edits and video. Billed per image at the model's rate; the exact amount is cost_usd in the result. Prompts are screened first; blocked prompts cost nothing. Every request depicts adults only. Guarded: without approval_token it returns {error: "approval_required", summary, approval_token}; show the summary (it carries the cost), get the user's yes, call again with the token. Arguments: `model`: string (An image model id, e.g. spicy-image-1 (fast) or spicy-image-1-pro (best prompt adherence).); `prompt`: string; `negative_prompt`?: string; `size`?: string (width*height from the model's limits, e.g. 1024*1024 (default), 832*1216, 1216*832.); `n`?: integer (Images to return, default 1, clamped to the model's maximum.); `seed`?: integer; `approval_token`?: string (Approval token from a previous approval_required response, after the user said yes.). - `edit_image` (guarded): Prompt-driven edit of one to three images the account generated (list_images), for outfit, pose and scene changes. Synchronous; returns a durable CDN URL. Billed per edit. Guarded: without approval_token it returns {error: "approval_required", summary, approval_token}; show the summary (it carries the cost), get the user's yes, call again with the token. Arguments: `model`: string (An image-edit model id, e.g. spicy-image-edit-1.); `prompt`: string (The change to make.); `image_urls`: array (Source images, all from this account's own generations.); `negative_prompt`?: string; `size`?: string (Output width*height.); `seed`?: integer; `approval_token`?: string (Approval token from a previous approval_required response, after the user said yes.). - `generate_video` (guarded): Image to video (or text to video on spicy-motion-3 and spicy-motion-3-fast). Asynchronous: returns a task id at once with the price already debited; poll get_job every 10 to 15 seconds until succeeded (output.video_url) or failed (refunded). image_url must be one of the account's own generated images. Price = seconds x the per-second rate for the resolution. Our POV fine-tunes (spicy-pov-*) need a first frame already in position. Guarded: without approval_token it returns {error: "approval_required", summary, approval_token}; show the summary (it carries the cost), get the user's yes, call again with the token. Arguments: `model`: string (A video model id, e.g. spicy-motion-2, spicy-motion-3, spicy-pov-missionary-1.); `prompt`: string (What should happen in the clip.); `image_url`?: string (First frame, from list_images or a generate_image result. Required unless the model is text-to-video capable.); `resolution`?: string (480P, 720P (default) or 1080P, within the model's limits.); `duration`?: integer (Seconds, default 5, within the model's limits.); `negative_prompt`?: string; `audio`?: boolean (Generate audio where the model supports it.); `seed`?: integer; `approval_token`?: string (Approval token from a previous approval_required response, after the user said yes.). - `get_job`: Status of a video task (queued, processing, finalizing, succeeded with output.video_url, or failed and refunded) or of a logged image or chat request by id. Arguments: `id`: string (Task or request id, e.g. sj_...). - `get_usage`: Spend and request counts over the last N days, totalled and broken down by model, type and source (playground, api, agent), with the error count. Reads the account's request log. Arguments: `days`?: integer (Default 7.). - `create_api_key` (guarded): Mint a new key for this account (plaintext returned once, stored hashed; at most 20 active keys). sandbox: true makes a key that answers everything from fixtures and bills nothing. Keys made with a sandbox key are always sandbox keys. Keep keys in environment variables, never in chat. Guarded: without approval_token it returns {error: "approval_required", summary, approval_token}; show the summary (it carries the cost), get the user's yes, call again with the token. Arguments: `name`: string (A label, e.g. Production or Agent.); `sandbox`?: boolean (Fixture-only key, nothing billed. Default false.); `approval_token`?: string (Approval token from a previous approval_required response, after the user said yes.). - `set_spend_limit` (guarded): Cap what this account can spend per calendar month (UTC), enforced at debit time on every surface: requests past the cap return 402 without charging. Lowering or setting a limit never needs approval; raising or removing one does. null removes the limit. Arguments: `monthly_usd`: any (Monthly cap in USD, or null to remove it.); `approval_token`?: string (Approval token from a previous approval_required response, after the user said yes.). - `read_acceptable_use`: The acceptable use policy as markdown: prohibited content (minors in any form, real people without consent, non-consensual scenarios and the rest), age-verification duties for the customer's product, enforcement. Read it before the first generation and tell the user what their product must do. Works with a $0 balance. Arguments: no arguments. ## Setup (once per user) 1. Key: the user signs in once at https://www.spicyapi.com/auth (Google or email). The account is live at once with a $0 balance and a Default key shown once at https://www.spicyapi.com/dashboard/api-keys. Keep the key in an environment variable (`SPICYAPI_KEY`), never in chat, never in client-side code. With one key you can mint more with `create_api_key`. 2. Connect. MCP (Streamable HTTP): `https://www.spicyapi.com/api/mcp` with header `Authorization: Bearer `. Claude Code: `claude mcp add --transport http spicyapi https://www.spicyapi.com/api/mcp --header "Authorization: Bearer sk-spicy-..."`. Cursor, Codex and any URL-plus-headers client: same URL and header. REST instead of MCP: `POST https://www.spicyapi.com/api/v1/tools/` with the same header and a JSON body of arguments; `GET https://www.spicyapi.com/api/v1/tools` lists them; OpenAPI 3.1 at https://www.spicyapi.com/openapi.json. OAuth is not available yet, so Claude.ai custom connectors and ChatGPT cannot connect. 3. Dry run first: a key created with Sandbox ticked (or `create_api_key` with `sandbox: true`) answers every endpoint and every tool from fixture output flagged `sandbox: true`, needs no balance and bills nothing. Build against it, then swap the key. Never present sandbox output to the user as a real generation. 4. Money: `get_account` shows the balance; `estimate_cost` prices a request from the same table the API bills; `get_topup_link` returns a card or crypto checkout URL (presets $50, $100, $250, $500, $1000, minimum $50) that the USER opens and pays in the browser. Never enter card details yourself. A 402 means the balance ran out or the monthly limit was hit. 5. Rate limit: 60 requests per minute per key on the agent surfaces. ## Rules that always apply - Guarded tools (`generate_image`, `edit_image`, `generate_video`, `create_api_key`, `revoke_api_key`, and `set_spend_limit` when raising or removing a limit) first return `{error: "approval_required", summary, approval_token}`. Show the summary to the user verbatim (it carries the cost), get an explicit yes in the conversation, then call the tool again with the same arguments plus `approval_token` (15-minute expiry, bound to those exact arguments). Never approve in bulk or reuse a token for a different action. The account can turn approvals off in the dashboard; moderation, provenance and the spend limit still apply. - Input images for `edit_image` and `generate_video` must be images this account generated (`list_images`). Uploads and third-party URLs are rejected before any charge; do not try to work around it. - Read `read_acceptable_use` before the first generation: adults only, no minors in any form (including "young-looking" or youth-coded content), no real people without documented consent, no non-consensual scenarios. Blocked prompts return 422 and cost nothing; repeated attempts terminate the account. Tell the user their product must age-verify its end users and disclose that content is AI-generated. - Everything is scoped to the account behind the key; there is no way to read another account's data. - Spicy API is spicyapi.com. spicyapi.ai is an unrelated aggregator; do not mix their prices or models. ## Prices (USD, for when the user asks) | Model | Kind | Price | Limits | |---|---|---|---| | `spicy-pov-missionary-1` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 15 seconds; needs image_url (one of your generated images) | | `spicy-pov-doggystyle-1` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 15 seconds; needs image_url (one of your generated images) | | `spicy-pov-blowjob-1` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 15 seconds; needs image_url (one of your generated images) | | `spicy-image-1` | image | $0.06 per image | sizes 1024*1024, 832*1216, 1216*832; up to 4 outputs per call | | `spicy-image-1-pro` | image | $0.09 per image | sizes 1024*1024, 832*1216, 1216*832; up to 2 outputs per call | | `spicy-image-edit-1` | image-edit | $0.15 per image | sizes 1024*1024, 832*1216, 1216*832; up to 1 output per call; needs image_url (one of your generated images) | | `spicy-motion-1` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 10 seconds; needs image_url (one of your generated images) | | `spicy-motion-2` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 15 seconds; needs image_url (one of your generated images) | | `spicy-video-1` | video | $0.175 per second at 720P, $0.29 per second at 1080P | resolutions 720P, 1080P; 2 to 15 seconds | | `spicy-motion-3` | video | $0.1 per second at 480P, $0.2 per second at 720P, $0.4 per second at 1080P | resolutions 480P, 720P, 1080P; 2 to 30 seconds; image_url optional (text-to-video without it) | | `spicy-motion-3-fast` | video | $0.14 per second at 480P, $0.28 per second at 720P, $0.56 per second at 1080P | resolutions 480P, 720P, 1080P; 2 to 30 seconds; image_url optional (text-to-video without it) | | `spicy-chat-1` | chat | $0.575 per 1M tokens (minimum $0.0005 per request) | | Public docs: https://www.spicyapi.com/docs (every page is also available as markdown by appending `.md`). Product overview for agents: https://www.spicyapi.com/llms.txt