Quotes and protocol compatibility
Confirm an exact quote before using task or text compatibility APIs.
Save the complete request as request.json, using model, input and optional callBackUrl from the live model schema. A quote creates no task and reserves no funds. It binds the principal, model and exact request for five minutes.
curl https://api.spicyapi.ai/api/v1/jobs/quote \
-H "Authorization: Bearer $SPICY_API_KEY" \
-H "Content-Type: application/json" \
--data-binary @request.jsonestimatedCost, maxCharge and quantity are decimal strings; currency is USD. Show the amount, maximum charge and expiresAt. After confirmation, submit the same request with quoteId and expectedCost. Changed inputs, expiry or a price change return 40901 on new acceptance; quote and confirm again.
After a lost response, recover with the original Idempotency-Key. Do not create another task with a fresh key. An accepted replay remains valid after quote expiry. Read cost and settled in recordInfo for the final charge; an estimate or text-end marker does not prove settlement.
SDK, CLI and MCP
CLI tasks create quotes before confirmation; non-interactive execution requires explicit --yes. MCP spicyapi_task_quote only quotes. spicyapi_task_create binds the quote into signed request state and asks the user through protocol elicitation. An agent must not confirm on the user’s behalf.
spicyapi tasks quote --model "$SPICY_MODEL" --input-file input.json
spicyapi tasks create --model "$SPICY_MODEL" --input-file input.json \
--idempotency-key "$SPICY_IDEMPOTENCY_KEY" --waitText and video compatibility
The OpenAI-format base URL is https://api.spicyapi.ai/v1. For the Anthropic and Google GenAI SDKs, set the base URL to https://api.spicyapi.ai, and they append /v1 or /v1beta themselves. Every compatibility API uses the same API key, sent in the Authorization: Bearer header. The x-api-key header used by the Anthropic SDK and the x-goog-api-key header used by the Google GenAI SDK are also accepted; a ?key= in the URL is not. Select an exact chat model from the live catalog; tools, image messages and generation options depend on its schema. Responses use the corresponding protocol envelope instead of the platform JSON envelope. For per-protocol parameter mapping, how streams end and error shapes, see Text and streaming.
| Protocol | Endpoint |
|---|---|
| Models | GET /v1/models |
| Chat Completions | POST /v1/chat/completions |
| Responses | POST /v1/responses |
| Messages | POST /v1/messages |
| Gemini generateContent | POST /v1beta/models/{model}:generateContent |
| Gemini streamGenerateContent | POST /v1beta/models/{model}:streamGenerateContent |
| Videos | POST /v1/videos |
| Video status | GET /v1/videos/{videoId} |
| Video content | GET /v1/videos/{videoId}/content |
Chat models that expose reasoning text may return an optional string in message.reasoning_content, or delta.reasoning_content when streaming. When continuing after a tool call, you can preserve it in the corresponding assistant message where the live model schema supports it. usage.completion_tokens_details.reasoning_tokens describes the reasoning portion already included in completion_tokens; do not add it again. Reasoning text and token details are not returned by every model.
Responses requires the full conversation in input; previous_response_id is unsupported. Videos accepts JSON with mapped model, prompt, input_reference, seconds and size fields. Its content endpoint redirects with HTTP 302 to a short-lived signed URL. See OpenAPI for complete fields and states.
Quote credentials quoteId and expectedCost apply to jobs/createTask and jobs/stream. The /v1 and /v1beta compatibility APIs use the price at acceptance; use the native task API when the workflow must confirm a charge limit.
Streaming with the official OpenAI client
For Chat Completions, use the official openai client directly; @spicyapi/sdk handles native tasks, quotes and uploads. Install openai separately. Run this example on your server, with an exact callable chat model ID and one persistent idempotency key per user action.
npm install openaiimport OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.SPICY_API_KEY,
baseURL: "https://api.spicyapi.ai/v1",
maxRetries: 0,
});
const signal = AbortSignal.timeout(120_000);
const stream = await client.chat.completions.create({
model: process.env.SPICY_MODEL,
messages: [{ role: "user", content: "Explain a rainbow in one sentence." }],
stream: true,
stream_options: { include_usage: true },
}, {
signal,
headers: { "Idempotency-Key": process.env.SPICY_IDEMPOTENCY_KEY },
});
try {
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
if (chunk.usage) process.stderr.write(JSON.stringify(chunk.usage) + "\n");
}
} finally {
stream.controller.abort();
}The abort signal covers stream consumption as well as connection setup. Aborting stops the local stream; it does not cancel an accepted task or promise a refund. With stream: false, read choices[0].message.content. In a tool conversation, accumulate tool-call fragments by index and preserve the complete assistant message before adding matching tool_call_id results. Only enable tools or reasoning fields when the model schema supports them.
CLI and MCP currently submit and track native tasks; they do not expose live chat token streaming. Use this client path for a token-by-token interface, or native jobs/stream when you need quote confirmation.
Spicy Schema contract
The shared request envelope, canonical fields, form schema, async lifecycle, errors, result storage and compatibility rules.
Text and streaming
Call text models in the official OpenAI, Anthropic or Google Gemini format, and handle conversations, tools, streams and costs correctly.

