Tasks

Run a text model and stream the answer

Text models only. Applies the same validation, quota, pricing and hold as createTask, then keeps the connection open and returns the model answer as a Server-Sent Events stream. Each event is a data: line carrying one JSON chunk; the stream ends with data: [DONE].

The hold is settled when the stream completes. If generation fails within the first few seconds, before anything has been sent, the response is a normal JSON error and the hold is released. While a long reasoning model has not produced anything yet, and whenever the stream goes quiet, the connection carries SSE comment lines (: keep-alive) so the network edge does not close it as idle; clients must ignore them, as the SSE format requires. A failure after that point, or mid-stream, ends the stream with an error event and the hold is still released — a truncated answer is never charged as a completed one. The reverse also holds: when the model has already finished the answer (every choice has a finish_reason and the final usage has arrived) and only then reports an error or drops the connection, the answer is complete, the stream ends with [DONE] as usual, and the delivered usage is charged.

Non-streaming calls to the compatible endpoints are kept open too. A call that finishes within about 30 seconds is answered exactly as before. A longer one commits a 200 response with Content-Type: application/json and the X-Spicy-Keepalive: 1 header after about 30 seconds, then sends a newline every 15 seconds until the answer is ready; JSON allows leading whitespace, so standard parsers read the body unchanged. Because the status is already sent, a failure after that point arrives as the protocol's own error object in the body of the 200 response, with the same code and message it would otherwise have had, and the hold is still released. The whitespace is not model output: disconnecting after it follows the usual disconnect rules, and an answer that ends up empty or refused is still refunded.

Generation models (image, video, audio) are asynchronous and must use createTask with recordInfo polling; calling this endpoint for them returns 503.

post/api/v1/jobs/stream

Request

  • Base URL: https://api.spicyapi.ai
  • URL: https://api.spicyapi.ai/api/v1/jobs/stream
  • Auth: HTTP bearer

Headers

Idempotency-Keystring

Stable key for one logical task submission; retained for 24 hours per account and bound to both the submitting API key and normalized request fingerprint. A sibling key receives 409 without the original task ID.

X-Spicy-Retentionstring

Retention for this one task, in whole seconds. It applies to both the generated outputs and the stored request text. The effective value is always min(header, account setting, platform maximum): a request can only shorten retention, never extend it. 0 is valid and means the outputs are removed as soon as the task reaches a terminal state. Values that cannot be applied never fail the request: a negative number is clamped to 0, a value above the ceiling is clamped to the ceiling, and a value that is not a decimal integer is ignored so the account setting applies. The effective result is always reported back in retention on the task record. Accepted by createTask and stream. retry inherits the source task's effective value and ignores this header, so one task family never ends up with two different expiry times. quote does not accept it because it does not create a task.

Request body

modelstring required

Exact model value from the model catalog.

inputobject required

Validated against the selected model's inputSchema. Declared image fields accept public HTTPS URLs, committed spicy:// file URIs, legacy persona image references spicy://p/<id> (personas became characters in your personal asset library on 2026-10-12; these references keep resolving to the same images, only in your personal library and only with API keys you created in your personal workspace, so team workspace keys, another account's id and an unknown id all get the same rejection, and they are refused in video, audio and file fields), saved assets as spicy://a/<id> in the media field of the matching kind (the asset must be in the library of the key's workspace: a personal key uses your personal library, a team key uses that team's library; any other asset gets the same rejection as an unknown id), or standard Base64 Data URIs (image/jpeg, image/png, image/webp, image/gif). Inline images are limited to 1048576 decoded bytes and 8388608 pixels each, 8192 pixels per side, and 16 images / 16777216 pixels in total. The complete JSON request must fit within 2097152 bytes. Model-specific limits still apply. Bare Base64, SVG and inline audio/video are not accepted; use HTTPS or file uploads instead. Inline images are stored as account-bound uploaded files; returned input contains file URIs, never the original Base64 bytes. Quote validation does not upload or reserve funds. If the model's inputSchema declares seed and you omit it, we pick a random seed for this task, so two identical requests do not come back with the same output. The chosen seed is returned in the task's input; pass it back to hold the draw steady (a fixed seed keeps runs comparable, it does not guarantee an identical result). On the few models that cannot honour seed on every request, we still vary it where it applies but do not echo it. A seed you send yourself is always used as given. Models that offer an economy route declare the boolean official_fallback (default true): the request runs on the economy route first and, if that fails and the field is true, is retried once on the official route. The hold is the highest price the request can be billed at (the official price while the fallback is allowed); you are billed the price of the route that actually produced the result and the rest of the hold is released. With false, only the economy route is tried and the hold is the economy price.

callBackUrlstring uri

Optional public HTTPS endpoint for terminal task delivery. http:// URLs are rejected: the delivery carries the prompt and signed result links. Explicit ports other than 443 and 80 are rejected, and URL credentials are rejected. The hostname must resolve to public IP addresses and is checked again when connecting. Invalid values return HTTP 400 with code 400, msg "Invalid callback URL", and request_id.

quoteIdstring

Signed quote returned by jobs/quote for this same account, API key and request. Does not replace Idempotency-Key.

expectedCoststring

Decimal USD amount encoded as a string to avoid binary floating-point loss.

Response

Server-Sent Events stream of the model answer.

Changes

No recorded changes to this operation across all 1 revision of this API.