OpenAI-compatible NSFW API
Spicy API speaks the OpenAI wire format for image generation and chat, so the official OpenAI SDKs work once you change the base URL and the key. The difference is the content policy: explicit content between consenting adults is allowed, where OpenAI, Anthropic and Google refuse it. Images from $0.06, chat from $0.575 per 1M tokens, video from $0.10 per second, billed per generation with no subscription.
The two-line change
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)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.spicyapi.com/v1", apiKey: process.env.SPICYAPI_KEY });
const img = await client.images.generate({ model: "spicy-image-1", prompt: "..." });
console.log(img.data[0].url);No OpenAI account or OpenAI key is involved; requests go only to https://api.spicyapi.com.
What is compatible and what is not
| OpenAI SDK call | Spicy API endpoint | Status |
|---|---|---|
client.images.generate | POST /v1/images/generations | Drop-in. n 1 to 4, size written with an asterisk ("1024*1024", the allowed sizes are on each model), returns data[].url plus cost_usd. URLs only, no b64_json. |
client.chat.completions.create | POST /v1/chat/completions | Drop-in, including stream=True. |
client.models.list | GET /v1/models | Drop-in, with prices and limits added to each model. |
client.images.edit | POST /v1/images/edits | JSON body with image_urls rather than a file upload: inputs must be images this account generated. Call it over HTTP. |
| (none) | POST /v1/videos/generations | Not an OpenAI endpoint. Two plain HTTP calls: start a task, poll GET /v1/videos/tasks/{id}. |
| Embeddings, audio, assistants, files | (none) | Not offered. |
Models you can name in the SDK
| Model | Kind | Price |
|---|---|---|
spicy-image-1 | image | $0.06 per image |
spicy-image-1-pro | image | $0.09 per image |
spicy-chat-1 | chat | $0.575 per 1M tokens (minimum $0.0005 per request) |
Video and edit models: /pricing.
Video from the same key
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": "<a URL from /v1/images/generations>", "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"Errors look like OpenAI's
{"error": {"message": "...", "type": "insufficient_balance"}} with 401 bad key, 402 balance, 400 invalid parameters, 422 prompt blocked by moderation (never charged), 429 model at capacity. SDK retry and error classes behave as they do against OpenAI.
What "uncensored" does not mean
Minors in any form, real people without consent, non-consensual scenarios and the rest of the prohibited list are blocked at the prompt, before any charge: /acceptable-use. Your product must age-gate its users.
Start
Sign in at /auth, take the Default key, try a sandbox key for free fixture responses, then top up from $50. Full guide: /docs. Letting a coding agent wire it up: /docs/mcp.
For AI agents
Machine-readable overview: /llms.txt. OpenAPI: /openapi.json. MCP endpoint: /api/mcp (Claude Code: claude mcp add --transport http spicyapi https://www.spicyapi.com/api/mcp --header "Authorization: Bearer sk-spicy-..."; OAuth clients need only the URL; guide: /docs/mcp). Skills: /skills/index.json. A sandbox key answers everything from fixtures with nothing billed.