spicyapiDocs
Main content

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/models with your API key and use only models where both enabled and available are true. Read the model's inputSchema (the list of fields it accepts) and examples from 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, then recordInfo or 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 401 as 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 40201 and 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 40202 even 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, PUT the bytes, call files/{fileId}/commit, then pass the returned spicy:// URI in the model's input field. See Media.
  • Use each uploaded file within its lifetime. A spicy:// URI works until the expiresAt in 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, input and callBackUrl to POST /api/v1/jobs/quote. Show estimatedCost, maxCharge, the currency (USD) and expiresAt to 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 createTask with quoteId and expectedCost added.
  • 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-Key you will send.
  • Save after acceptance: the taskId and request_id from the response.
  • Reuse the key for the same submission. Send the original Idempotency-Key again 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 2xx right 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 recordInfo with growing pauses rather than every second.
  • Read the right signal. HTTP 202 from createTask means the task was accepted. state: "succeeded" means generation finished. settled: true means 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-After on 429, 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:

ScenarioHow to cause itWhat your integration should do
SuccessA normal small taskStore the result, show the final cost once settled is true
Invalid inputSend a value outside the schemaShow the problem; don't retry (400)
Unsupported combinationA setting the model can't serve (if one exists)Ask for a different value; don't retry (40004)
Insufficient balanceA key on an account with too little balanceTell the user to add funds; don't retry (40201)
Spend limit reachedA key with a very small daily capShow which limit was hit; don't retry (40202)
Revoked or expired keyRevoke a test key and call with itAlert an operator; don't retry (401)
Timeout after sendingCut the connection right after createTaskResend with the same Idempotency-Key and get the original task back
Model declines contentHard to cause on demand: simulate a recordInfo response with state: "failed" and errorCode: "content_rejected" in your testsShow the reason from errorMessage; don't retry automatically
Duplicate callbackReplay a callback you receivedProcess it once
Expired download linkWait more than 20 minutesRequest a new link

Log request_id, taskId, the time, the state and the amounts. Keep API keys and full prompts out of general logs.

Quotes and protocol compatibility · Model catalog and schemas · Media · Webhooks · Errors · Troubleshooting and recovery · Billing · Retention

On this page