### npx skills add spicyapi-ai/spicy-skill with --agent, -g, and -y flags Source: https://docs.spicyapi.ai/docs/skill Non‑interactive example invocations of the installer. Use `--agent` to name the assistant, `-g` for a global install, and `-y` to accept the defaults; the three lines are commented examples, not a single command. ```bash # Claude Code, this project only npx skills add spicyapi-ai/spicy-skill --agent claude-code # Codex, every project npx skills add spicyapi-ai/spicy-skill --agent codex -g # Claude Code and Codex, every project, no questions npx skills add spicyapi-ai/spicy-skill --agent claude-code codex -g -y ``` -------------------------------- ### listModels usage example Source: https://docs.spicyapi.ai/docs/sdk Example that lists video image-to-video models, filters out disabled or unavailable ones, and logs model name, display name, and starting price. ```typescript const { items } = await client.listModels({ modality: "video", task: "image-to-video" }); for (const item of items) { if (!item.enabled || !item.available) continue; const from = item.startingPrice ? `from $${item.startingPrice.price} ${item.startingPrice.unit}` : ""; console.log(item.model, "|", item.displayName, "|", from); } ``` -------------------------------- ### Install spicy-go SDK Source: https://docs.spicyapi.ai/docs/sdk-go Installs the spicy-go SDK module directly from its repository. Requires Go 1.23 or newer. ```bash go get github.com/spicyapi-ai/spicy-go ``` -------------------------------- ### Fetch live catalog and select a model with a validated example Source: https://docs.spicyapi.ai/docs/models Fetches the authenticated model catalog with schemas and examples, then selects the first enabled and available model that has at least one validated example. The resulting `createTaskBody` uses the selected model's `model` and `input` from the example. Replace `MODEL_ID_FROM_CATALOG` with a real model value from your own live catalog. ```javascript const response = await fetch( 'https://api.spicyapi.ai/api/v1/models?includeSchema=1&includeExamples=1', { headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` } }, ); const envelope = await response.json(); if (!response.ok || envelope.code !== 200) throw new Error(envelope.msg); const selected = envelope.data.items.find( (item) => item.enabled && item.available && item.examples?.length, ); if (!selected) throw new Error('No callable model with a validated example'); const createTaskBody = { model: selected.model, input: selected.examples[0].input, }; ``` -------------------------------- ### Set up Go client with SPICY_API_KEY and copy spicy_client.go Source: https://docs.spicyapi.ai/examples/README.md Exports the API key, creates the internal/spicy directory, copies the client file, and runs go vet. Requires Go 1.21+ and no external dependencies. ```bash export SPICY_API_KEY="sk-spicy-..." mkdir -p internal/spicy && cp go/spicy_client.go internal/spicy/ go vet ./internal/spicy ``` -------------------------------- ### Create project and install SDK Source: https://docs.spicyapi.ai/docs/sdk Run these commands one at a time to create a project folder, initialize package.json, set ES module type, and install the @spicyapi/sdk. Works on macOS, Linux, and Windows PowerShell. ```bash mkdir spicy-demo cd spicy-demo npm init -y npm pkg set type=module npm install @spicyapi/sdk ``` -------------------------------- ### GET /api/v1/models Source: https://docs.spicyapi.ai/docs/tasks Fetches the model catalog. Use includeExamples=1 to get example inputs that have already passed each model's schema. This helps you pick a valid model and input for createTask. ```APIDOC ## GET /api/v1/models ### Description Fetches the model catalog. Use includeExamples=1 to get example inputs that have already passed each model's schema. This helps you pick a valid model and input for createTask. ### Method GET ### Endpoint https://api.spicyapi.ai/api/v1/models ### Parameters #### Query Parameters - **modality** (string) - Required - Filter by modality: image, video, or audio. - **includeExamples** (integer) - Optional - Set to 1 to include example inputs. ### Request Example ``` curl -s "https://api.spicyapi.ai/api/v1/models?modality=image&includeExamples=1" \ -H "Authorization: Bearer $SPICY_API_KEY" \ | jq -c '.data.items[] | select(.enabled and .available) | {model, input: .examples[0].input}' ``` ### Response #### Success Response (200) - **data.items** (array) - List of models. - **model** (string) - Model ID. - **input** (object) - Example input for the model, or null if none stored. #### Response Example ``` {"model":"model-id","input":{...}} ``` ``` -------------------------------- ### Run first task with SpicyClient Source: https://docs.spicyapi.ai/docs/sdk-java Builds a client from the environment, quotes a task, runs it, and prints text or asset URLs. Quoting is free; run is createTask plus waitForTerminal. Check outputText() before assets() because some endpoints return text only. ```java SpicyClient client = SpicyClient.builder().apiKeyFromEnvironment().build(); // SPICY_API_KEY CreateTaskRequest request = CreateTaskRequest.of( "MODEL_ID_FROM_CATALOG", Map.of("prompt", "a lantern in fog")); TaskQuote quote = client.quote(request); // free; reserves nothing System.out.println("this will cost at most " + quote.maxCharge()); TaskRecord task = client.run( // createTask + waitForTerminal request.withQuote(quote), UUID.randomUUID().toString()); task.outputText().ifPresent(System.out::println); // some endpoints answer in text, not files for (TaskAsset asset : task.assets()) { asset.url().ifPresent(System.out::println); } ``` -------------------------------- ### Get a cost quote with spicyapi tasks quote Source: https://docs.spicyapi.ai/docs/cli Use this command to get a cost estimate for a single generation without starting it or setting aside money. The quote is free, requires no confirmation, and is valid for five minutes. You do not need to run it before `tasks create`, which gets its own quote. ```bash spicyapi tasks quote --model --input-file ``` -------------------------------- ### Select a live text-to-image model (requires jq) Source: https://docs.spicyapi.ai/docs Fetches the model catalog with schema and examples, then uses jq to select the first enabled, available model that has at least one example. Requires jq and the SPICY_API_KEY environment variable. ```bash CATALOG_JSON="$(curl --fail-with-body \ "https://api.spicyapi.ai/api/v1/models?modality=image&task=text-to-image&includeSchema=1&includeExamples=1" \ -H "Authorization: Bearer $SPICY_API_KEY")" MODEL_ID="$(printf '%s' "$CATALOG_JSON" | jq -er \ '[.data.items[] | select(.enabled == true and .available == true and (.examples | length > 0))][0].model')" MODEL_INPUT="$(printf '%s' "$CATALOG_JSON" | jq -cer \ '[.data.items[] | select(.enabled == true and .available == true and (.examples | length > 0))][0].examples[0].input')" printf 'Selected %s\n' "$MODEL_ID" ``` -------------------------------- ### GET /api/v1/models/{modelId} Source: https://docs.spicyapi.ai/docs/models Fetches a single model record including its input schema and validated examples. The response contains an inputSchema object with properties and a required list, plus examples that are server-validated against the current schema. ```APIDOC ## GET /api/v1/models/{modelId} ### Description Fetches a single model record including its input schema and validated examples. The response contains an inputSchema object with properties and a required list, plus examples that are server-validated against the current schema. ### Method GET ### Endpoint `https://api.spicyapi.ai/api/v1/models/{modelId}` ### Parameters #### Path Parameters - **modelId** (string) - Required - The exact `model` value from the catalog. #### Headers - **Authorization** (string) - Required - Bearer token with your SpicyAPI key. ### Request Example ``` const modelId = 'MODEL_ID_FROM_CATALOG'; const res = await fetch(`https://api.spicyapi.ai/api/v1/models/${modelId}`, { headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` }, }); ``` ### Response #### Success Response (200) - **data** (object) - Contains the model record. - **data.inputSchema** (object) - JSON Schema with `properties` and `required`. - **data.examples** (array) - Complete input examples validated against the current schema. #### Response Example ``` { "data": { "inputSchema": { "properties": {}, "required": [] }, "examples": [] } } ``` ``` -------------------------------- ### List image-to-video models with CLI Source: https://docs.spicyapi.ai/docs/guide-image-to-video Lists all image-to-video models available to your account. Use the --json flag to get machine-readable output. The response includes pricing, timeouts, and other model details. ```bash spicyapi models list --modality video --task image-to-video --json ``` -------------------------------- ### Get model settings with CLI Source: https://docs.spicyapi.ai/docs/guide-image-to-video Reads the full settings for a specific model, including inputSchema and examples. Use the model ID from the list command. ```bash spicyapi models get MODEL_ID_FROM_CATALOG --json ``` -------------------------------- ### spicyapi tasks create Source: https://docs.spicyapi.ai/docs/cli Documentation for the `spicyapi tasks create` CLI command, which starts an image or video generation task. It includes all options, behavior, and examples. ```APIDOC ## `spicyapi tasks create` ### Description Starts an image or video generation task. This operation costs money; the CLI always shows the price and asks for confirmation before proceeding. ### Command `spicyapi tasks create --model --input-file [options]` ### Options - `--model ` (string) - Required - The exact model ID. - `--input-file ` (string) - Required (use this or `--input-json`) - Read the input from a JSON file. `-` reads from piped input, which also requires `--yes`. - `--input-json ` (string) - Required (use this or `--input-file`) - Give the input directly as JSON text. - `--wait` (boolean) - Optional - Stay until the task finishes, then print the result. Default: off (print task ID and return). - `--yes` (boolean) - Optional - Skip the confirmation question. Default: off (ask). - `--idempotency-key ` (string) - Optional - A name for this one generation; reusing the same key within 24 hours returns the same task. Up to 128 characters. Default: a new random key each run. - `--retention ` (string) - Optional - Delete this task's generated media, result payload, prompt and other input text sooner than usual: `30m`, `1h`, `7d` or a number of seconds. It can only shorten. `0` deletes them once the task finishes. Billing records are always kept. Default: your account setting. - `--callback-url ` (string) - Optional - A public address starting with `https://` that SpicyAPI calls when the task finishes. Plain `http://`, `localhost` and private network addresses are refused. Only useful if you run a server; see Webhooks. Default: none. - `--poll-interval-ms ` (integer) - Optional - With `--wait`: check every this many milliseconds, from 100 to 60000. Default: starts at 2 seconds and slows down to 10 seconds. - `--wait-timeout-ms ` (integer) - Optional - With `--wait`: stop waiting after this long, from 1 to 86400000. The task keeps running. Default: `600000` (10 minutes). ### Behavior 1. The CLI reads your input and checks that it is a JSON object. If you gave no input, it stops here. 2. If nobody can answer a question, for example in a script, and you did not pass `--yes`, it stops here. 3. It gets a quote and prints the estimated charge, the maximum charge, when the quote expires and the idempotency key. 4. It asks `Continue? [y/N]`. Only `y` or `yes` continues. The default is **no**. 5. It creates the task at the quoted price. The estimated amount is set aside from your balance, and that amount is also the most the task can cost. 6. Without `--wait`, it prints `idempotencyKey`, `taskId`, `state` (`queued`), `estimatedCost` and `deadlineAt`, then returns. With `--wait`, it prints `Accepted: ` and a recovery command straight away, waits, then prints `idempotencyKey`, `accepted` and the finished `task`. ### Examples ``` spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --wait ``` On macOS and Linux you can also give the input inline: ``` spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-json '{"prompt": "A paper lantern on a rainy street"}' ``` ### Notes - `deadlineAt` is the latest time the task can finish before it ends as `expired`. It is not when your download link or files expire. - If waiting fails, the task is still running. A wait can end early because of the time limit, a network problem or **Ctrl + C**. The task itself carries on and is charged normally. The `Accepted:` line printed at the start has its ID; continue with `spicyapi tasks wait `. Do not simply run the same create command again without `--idempotency-key`: that starts, and charges for, a second generation. - When the wait fails with an error (rather than **Ctrl + C**), the last lines repeat everything you need, so you do not have to scroll back for the `Accepted:` line: ``` Error: task job_01k3m8x9q2z4v7n5p6r8s0t1w3 did not reach a terminal state within 600000ms Task job_01k3m8x9q2z4v7n5p6r8s0t1w3 was accepted and may still be running; only the wait stopped. Recover: spicyapi tasks get job_01k3m8x9q2z4v7n5p6r8s0t1w3 To replay the same request without creating a second task, reuse --idempotency-key 4f6755a5-0d72-4420-9f6b-9faf0e2b0241. ``` - If the error was one with a known fix, such as `429` or a server error, a `Next:` line follows. With `--json`, the same facts are in the error object as `taskId`, `idempotencyKey` and `recover`. ``` -------------------------------- ### Run first-result.mjs with and without --yes Source: https://docs.spicyapi.ai/docs/sdk Commands to run the example script. The first run without --yes only reads and charges nothing; the second with --yes creates an image task and charges if it succeeds. ```bash node first-result.mjs node first-result.mjs --yes ``` -------------------------------- ### Create a task with spicyapi tasks create Source: https://docs.spicyapi.ai/docs/cli Starts an image or video generation. The CLI always shows the price and asks for confirmation before creating the task. ```bash spicyapi tasks create --model --input-file [options] ``` -------------------------------- ### Quote output: quoteId, estimatedCost, maxCharge Source: https://docs.spicyapi.ai/docs/guide-image-to-video Example output from the quote command. Nothing is started or charged. The quote is valid for five minutes and only for this exact input. ```text quoteId: eyJ2IjoxLCJtIjoi… model: MODEL_ID_FROM_CATALOG estimatedCost: … maxCharge: … currency: USD quantity: 5 unit: per_second expiresAt: 2026-09-17T08:05:00Z ``` -------------------------------- ### GET /api/v1/models/{model} Source: https://docs.spicyapi.ai/docs/models Retrieves a single model by its ID. The response always includes `inputSchema` and `examples`. Returns 404 if the model does not exist or is not currently offered. ```APIDOC ## GET /api/v1/models/{model} ### Description Retrieves a single model by its ID. The response always includes `inputSchema` and `examples`. Returns 404 if the model does not exist or is not currently offered. ### Method GET ### Endpoint /api/v1/models/{model} ### Parameters #### Path Parameters - **model** (string) - Required - The model ID from the catalog. Slashes can stay as they are; percent-encode only if your HTTP client treats a path parameter as a single segment. ### Response #### Success Response (200) - **code** (integer) - Response code, e.g., 200. - **msg** (string) - Response message, e.g., "success". - **data** (object) - Contains model details including `inputSchema` and `examples`. - **request_id** (string) - Unique request identifier. #### Response Example (Not provided in source) ### Error Handling - **404** - Model does not exist or is not currently offered. ``` -------------------------------- ### Workflow diagram: upload to download Source: https://docs.spicyapi.ai/docs/guide-image-to-video ASCII diagram showing the SpicyAPI task lifecycle: upload picture to get a temporary address, combine with sentence and settings to get a quote, start the task, and track it through queued, running, succeeded/failed/expired states, ending with a download link after about 20 minutes. ```text your picture ──upload──▶ spicy:// address (usable for one day) │ your sentence + settings ──────────┴──▶ quote (free) ──▶ start the task (money set aside) │ queued ──▶ running ──▶ succeeded / failed / expired │ download link (about 20 minutes) ──▶ your file ``` -------------------------------- ### Check price and generate video with spicyapi Source: https://docs.spicyapi.ai/docs/cli Checks the price, then generates the video. Videos are usually charged per second, so the length you choose changes the price. Videos can take several minutes, so this example waits up to 30 minutes instead of the default 10. Download the .mp4 from the url as in Your first result. ```bash spicyapi tasks quote --model MODEL_ID_FROM_CATALOG --input-file input.json spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --wait --wait-timeout-ms 1800000 ``` -------------------------------- ### GET /api/v1/models Source: https://docs.spicyapi.ai/docs/models Fetches the authenticated live catalog of callable models, including their schemas and examples. The response is the only source of truth for callable model IDs and input schemas. ```APIDOC ## GET /api/v1/models ### Description Fetches the authenticated live catalog of callable models, including their schemas and examples. The response is the only source of truth for callable model IDs and input schemas. ### Method GET ### Endpoint https://api.spicyapi.ai/api/v1/models ### Parameters #### Query Parameters - **includeSchema** (integer) - Optional - Set to 1 to include the input schema for each model. - **includeExamples** (integer) - Optional - Set to 1 to include validated input examples for each model. ### Request Example ``` const response = await fetch( 'https://api.spicyapi.ai/api/v1/models?includeSchema=1&includeExamples=1', { headers: { Authorization: `Bearer ${process.env.SPICY_API_KEY}` } }, ); ``` ### Response #### Success Response (200) - **code** (integer) - Response code, expected to be 200. - **msg** (string) - Response message, used for error details. - **data.items** (array) - List of model items. - **model** (string) - The callable model ID. - **enabled** (boolean) - Indicates if the model is enabled. - **available** (boolean) - Indicates if the model is available. - **examples** (array) - List of validated input examples. - **input** (object) - A complete input that has been validated against the current schema. #### Response Example ``` { "code": 200, "msg": "OK", "data": { "items": [ { "model": "MODEL_ID_FROM_CATALOG", "enabled": true, "available": true, "examples": [ { "input": {} } ] } ] } } ``` ### Error Handling - If the response is not OK or the code is not 200, an error is thrown with the message from `envelope.msg`. ``` -------------------------------- ### run(request, options?) Source: https://docs.spicyapi.ai/docs/sdk The easiest way to generate something: it calls createTask, then waitForTask, and returns the finished task. ```APIDOC ## run(request, options?) ### Description The easiest way to generate something: it calls `createTask`, then `waitForTask`, and returns the finished task. ### Method run ### Signature `run(request: CreateTaskInput, options?: RunTaskOptions): Promise` ### Parameters #### Request (CreateTaskInput) Same as for `createTask`. #### Options (RunTaskOptions) All options from `createTask`, plus: - **timeoutMs** (number) - Optional - Timeout in milliseconds. - **intervalMs** (number) - Optional - Polling interval in milliseconds. - **onAccepted** (function) - Optional - Callback when the task is accepted. - **onUpdate** (function) - Optional - Callback on task updates. ### Return Value Returns the finished task, with the fields described under `getTask`. For a successful task it also waits until the result files have finished copying, so `output.assets[].url` is ready to download. ### Costs Yes, exactly like `createTask`. A failed task is **returned, not thrown** — check `task.state`. ### Errors Everything `createTask` can throw, plus: - `SpicyWaitTimeoutError` when `timeoutMs` runs out after the task was accepted. The task **keeps running** on SpicyAPI. Call `waitForTask(error.taskId)` later to collect it. - `SpicyTimeoutError` when time runs out before SpicyAPI confirmed the task. Send the same request with the same idempotency key to find out. - Any error thrown inside your own `onAccepted` or `onUpdate` stops the waiting; the task itself keeps running. - `TypeError` for an invalid `timeoutMs` or `intervalMs`. These are checked **before** anything is created. ### Request Example See Your first result for a complete example. ``` -------------------------------- ### Run SpicyAPI MCP server with npx Source: https://docs.spicyapi.ai/docs/mcp Every app runs this same command to start the SpicyAPI MCP server. The first start downloads the package, which can take a few seconds. If run by hand, it waits silently for the app to talk to it, which looks like a hang but is normal; press Ctrl+C to stop it. ```bash npx --yes --package=@spicyapi/mcp spicyapi-mcp ``` -------------------------------- ### Webhook payload example - succeeded (v2) Source: https://docs.spicyapi.ai/docs/webhooks Example of a v2 webhook payload for a succeeded task. The shape matches GET /jobs/recordInfo with the envelope {code, msg, data, request_id}. The data includes taskId, model, state, input, output.assets, cost, settled, and timestamps. The model field uses MODEL_ID_FROM_CATALOG as a placeholder. ```json { "code": 200, "msg": "success", "request_id": "whd_01k3m8x9q2z4v7n5p6r8s0t1w4", "data": { "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3", "model": "MODEL_ID_FROM_CATALOG", "state": "succeeded", "input": { "prompt": "a folded paper lantern, hard side light" }, "output": { "assets": [ { "key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/9f3c1d0a7b4e2f68c5a1d3e9b0472fa1.png", "url": "https://example.r2.cloudflarestorage.com/results/result.png?X-Amz-Signature=SIGNATURE_FROM_RESPONSE", "expiresAt": "2026-08-28T09:32:11Z", "mime": "image/png", "width": 1024, "height": 1024, "bytes": 1483920 } ] }, "cost": "0.008", "settled": true, "createdAt": "2026-08-28T09:12:04Z", "completedAt": "2026-08-28T09:12:11Z" } } ``` -------------------------------- ### Get quote with spicyapi tasks quote Source: https://docs.spicyapi.ai/docs/guide-image-to-video Requests a quote for the task using the model ID from the catalog and the input file. The quote runs the same checks as starting the task; a 400 means invalid input, 40201 means insufficient balance. ```bash spicyapi tasks quote --model MODEL_ID_FROM_CATALOG --input-file input.json ``` -------------------------------- ### New(opts Options) (*Client, error) Source: https://docs.spicyapi.ai/examples/go/spicy_client.go Constructs a SpicyAPI client. Requires an API key, either from the Options or the SPICY_API_KEY environment variable. Validates the base URL and applies default timeouts and retry settings. ```APIDOC ## New(opts Options) (*Client, error) ### Description Constructs a SpicyAPI client. Requires an API key, either from the Options or the SPICY_API_KEY environment variable. Validates the base URL and applies default timeouts and retry settings. ### Method Constructor ### Parameters #### Options - **APIKey** (string) - Optional - API key. If empty, the SPICY_API_KEY environment variable is used. - **BaseURL** (string) - Optional - Base URL for the API. Defaults to APIBaseURL. Must be an absolute URL using HTTPS, or HTTP only for loopback addresses. - **HTTPClient** (HTTPDoer) - Optional - Custom HTTP client. Defaults to a standard http.Client. - **RequestTimeout** (time.Duration) - Optional - Timeout for regular requests. Defaults to DefaultRequestTimeout. - **UploadTimeout** (time.Duration) - Optional - Timeout for uploads. Defaults to DefaultUploadTimeout. - **WaitTimeout** (time.Duration) - Optional - Timeout for waiting operations. Defaults to DefaultWaitTimeout. - **MaxRetries** (int) - Optional - Maximum number of retries. Defaults to DefaultMaxRetries. Negative values are treated as 0. - **Now** (func() time.Time) - Optional - Function to get current time. Defaults to time.Now. - **Rand** (func() float64) - Optional - Function for random numbers. Defaults to rand.Float64. - **Sleep** (func(ctx context.Context, d time.Duration) error) - Optional - Function to sleep, must return context error if context ends first. Defaults to sleepWithContext. ### Returns - **client** (*Client) - The constructed client. - **error** (error) - Error if API key is missing or base URL is invalid. ### Errors - Returns error if API key is empty. - Returns error if BaseURL is not an absolute URL. - Returns error if BaseURL uses HTTP and is not loopback. ``` -------------------------------- ### Get task ID from response header (Python) Source: https://docs.spicyapi.ai/docs/chat-recipes Use the OpenAI Python client with `with_raw_response` to access the `x-spicy-task-id` header, which identifies the task for cost lookup. The example sends a chat completion request and prints the response content and task ID. ```python import os from openai import OpenAI client = OpenAI(api_key=os.environ["SPICY_API_KEY"], base_url="https://api.spicyapi.ai/v1") raw = client.chat.completions.with_raw_response.create( model=os.environ["SPICY_MODEL"], messages=[{"role": "user", "content": "Say hello in one sentence."}], ) reply = raw.parse() # the usual ChatCompletion object print(reply.choices[0].message.content) print("task:", raw.headers.get("x-spicy-task-id")) ``` -------------------------------- ### Install SpicyAPI CLI and check version Source: https://docs.spicyapi.ai/docs/guide-image-to-video Installs the @spicyapi/cli package globally via npm and prints the installed version. If installation fails with EACCES, use 'npx @spicyapi/cli' instead of 'spicyapi'. ```bash npm install -g @spicyapi/cli spicyapi --version ```