Production integration
A launch checklist for a recoverable integration — the right model, protected keys and balance, confirmed costs, durable task tracking, reliable callbacks and the tests to run before going live.
Use this page as a checklist before real users or real money depend on your integration. Each section says what to do, why it matters and where the details are. If you haven't made a first call yet, start with Account setup and the quickstart.
Choose a model and protocol
- Pick a model your key can actually call. Call
GET /api/v1/modelswith your API key and use only models where bothenabledandavailablearetrue. Read the model'sinputSchema(the list of fields it accepts) andexamplesfrom the same response. A model page on the website tells you what a model can do; it doesn't prove your key may call it right now. See Models. - Use the right entry point. Image, video and other media tasks use the task API under
/api/v1(createTask, thenrecordInfoor a callback). Text models can also be called through OpenAI- or Anthropic-compatible clients under/v1, or Gemini-compatible clients under/v1beta. See Text and streaming. - Authenticate with an API key only. A console sign-in cookie is not an API credential and must never be copied into code.
Protect your keys and your balance
- Keep the key on your server. Put it in an environment variable (
SPICY_API_KEY) on your backend, never in browser code, mobile apps or a public repository. See Authentication. - One key per environment and service. Name each key after what uses it (for example "production-worker"), so you can revoke one without stopping the others.
- Set caps on the production key: a daily cap sized to a bad day, a monthly budget, allowed models and — for server-side calls — an IP allowlist. See per-key restrictions. When editing a key, remember that a blank cap means no limit.
- Check expiry dates. A key with an expiry date stops working at the end of that day (UTC) and returns the same
401as a revoked key. Put the date in your calendar, or don't set one for a long-lived backend. - Don't run out of money mid-batch. A task refused for balance returns
40201and is never queued. Turn on the Low balance alert under Notifications, and consider auto top-up. - Team limits apply too. If your key belongs to a team, the team's daily and monthly limits can stop tasks with
40202even when the key's own caps haven't been reached, and every task is paid from the team owner's balance. See Spend caps. - Plan webhook signing key rotation. Rotating the key in the console has no overlap: the old key stops signing immediately. Deliveries still being retried are signed with the new key. Rotate in a quiet period, deploy the new key to your receiver straight away, and recover anything missed with
recordInfo. See Webhooks.
Prepare input on your server
- Validate against the current schema. Follow the field types, allowed values and conditional requirements in
inputSchema, and validate again after switching models — each model has its own. - Send media the supported way. Use a publicly reachable
https://URL or a supported Base64 input. For local files, request an upload URL,PUTthe bytes, callfiles/{fileId}/commit, then pass the returnedspicy://URI in the model's input field. See Media. - Use each uploaded file within its lifetime. A
spicy://URI works until theexpiresAtin its commit response (1 day by default). Don't request upload URLs in bulk that you never use — unused ones count against a limit. See Rate limits.
Quote before accepting a charge
- Show the price before spending money. Send the complete
model,inputandcallBackUrltoPOST /api/v1/jobs/quote. ShowestimatedCost,maxCharge, the currency (USD) andexpiresAtto the person paying. A quote is free: it creates no task and holds no funds. - Submit what was confirmed. A quote lasts five minutes. After confirmation, send the same request to
createTaskwithquoteIdandexpectedCostadded. - Handle
40901. It means the quote expired, the input changed or the price changed since the quote. Get a new quote and show the new amount; never silently accept a higher one. See Quotes. - Keep money exact. Amounts are decimal strings such as
"0.008". Store and add them with decimal arithmetic, not floating point. See Billing.
Persist the business operation
Your own records are what let you recover when a network call fails halfway.
- Save before sending: your own order or operation ID, a short description of the request that contains no secrets or full prompts (enough to recognise it later), and the
Idempotency-Keyyou will send. - Save after acceptance: the
taskIdandrequest_idfrom the response. - Reuse the key for the same submission. Send the original
Idempotency-Keyagain for the same account, API key and request within 24 hours; you get the original task back instead of a second charge. See Idempotency. - Treat a timeout as "unknown", not "failed". Recover the original submission with its key before deciding to create a new one. See Troubleshooting.
- Know what a retry costs. Retrying a task that already failed creates a new task at current conditions and prices.
Handle callbacks and results reliably
- Verify every callback. Check the signature and timestamp against the original request bytes before parsing, then deduplicate and store the event. See Webhooks.
- Acknowledge quickly. Answer with a
2xxright away and do slow work in your own queue. - Expect duplicates and delays. Decide what to do from the task's
state, not from the order callbacks arrive in. - Keep polling as a fallback. If a callback is late, read
recordInfowith growing pauses rather than every second. - Read the right signal. HTTP
202fromcreateTaskmeans the task was accepted.state: "succeeded"means generation finished.settled: truemeans the charge is final.
Bound concurrency and retain results
- Limit tasks in flight per account and give your own requests deadlines. Every accepted task holds funds until it settles.
- Follow
Retry-Afteron429, and avoid many clients polling in lockstep every second. See Rate limits. - Cache catalog data briefly and privately, and never treat a quote as a permanent price list.
- Archive results you need to keep. Download links last 20 minutes; generated media is kept for about 14 days at most and uploads for one day. You can shorten those periods, or delete a task's content sooner with
POST /api/v1/jobs/purge. Shortening a retention setting can also remove results of tasks you already ran — see Retention. - Don't rely on disconnecting to stop work. An accepted task keeps running and can't be canceled.
Validate before launch
Start with the free calls: the catalog (GET /api/v1/models), your balance (GET /api/v1/chat/credit) and a quote. Then run one small real generation through your own cost-confirmation flow — it is billed like any other task. Check that your integration handles each of these:
| Scenario | How to cause it | What your integration should do |
|---|---|---|
| Success | A normal small task | Store the result, show the final cost once settled is true |
| Invalid input | Send a value outside the schema | Show the problem; don't retry (400) |
| Unsupported combination | A setting the model can't serve (if one exists) | Ask for a different value; don't retry (40004) |
| Insufficient balance | A key on an account with too little balance | Tell the user to add funds; don't retry (40201) |
| Spend limit reached | A key with a very small daily cap | Show which limit was hit; don't retry (40202) |
| Revoked or expired key | Revoke a test key and call with it | Alert an operator; don't retry (401) |
| Timeout after sending | Cut the connection right after createTask | Resend with the same Idempotency-Key and get the original task back |
| Model declines content | Hard to cause on demand: simulate a recordInfo response with state: "failed" and errorCode: "content_rejected" in your tests | Show the reason from errorMessage; don't retry automatically |
| Duplicate callback | Replay a callback you received | Process it once |
| Expired download link | Wait more than 20 minutes | Request a new link |
Log request_id, taskId, the time, the state and the amounts. Keep API keys and full prompts out of general logs.
Related workflows
Quotes and protocol compatibility · Model catalog and schemas · Media · Webhooks · Errors · Troubleshooting and recovery · Billing · Retention

