Chat Completions
The OpenAI-compatible endpoint — streaming, vision, tools, web search, thinking levels, and routing preferences.
POST /ai/chat/completions is a drop-in replacement for OpenAI's chat
completions endpoint. Everything your OpenAI SDK sends works here — plus
ZapAPI additions (sats billing, routing suffixes, web search, PII-safe
options).
Basic request
curl https://api.zapapi.com/api/v1/ai/chat/completions \
-H "Authorization: Bearer zap_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-6.1-sol",
"messages": [
{"role": "system", "content": "You are concise."},
{"role": "user", "content": "Summarize the Lightning Network in two sentences."}
]
}'The response shape is identical to OpenAI's (choices[0].message.content,
usage with native token counts). Token counts are what you're billed on.
Streaming
curl -N https://api.zapapi.com/api/v1/ai/chat/completions \
-H "Authorization: Bearer zap_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"model": "openai/gpt-6.1-sol",
"stream": true,
"messages": [{"role": "user", "content": "Write a short poem about sats."}]
}'SSE keep-alive comments (: OPENROUTER PROCESSING) may appear — skip lines
starting with : before parsing. The final data: frame before [DONE]
carries the usage object used for billing.
Vision (image input)
On vision-capable models, send content parts with images as HTTPS URLs or base64 data URLs:
{
"model": "openai/gpt-6.1-sol",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "What does this diagram show?" },
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBOR…" } }
]
}
]
}Web search
Two ways to ground answers with real-time web results. A flat fee per search-enabled request applies (shown in your price breakdown).
{
"model": "anthropic/claude-sonnet-5.5",
"plugins": [{ "id": "web", "max_results": 5 }],
"messages": [{ "role": "user", "content": "What are today's top Lightning Network updates?" }]
}{
"model": "anthropic/claude-sonnet-5.5",
"tools": [{ "type": "web_search" }],
"messages": [{ "role": "user", "content": "Who won the latest Boltz update?" }]
}Or simply append :online to the model id.
Thinking levels
Reasoning models accept an effort hint. Higher effort = more reasoning tokens (billed as output):
{
"model": "anthropic/claude-opus-5.5",
"reasoning": { "effort": "medium" },
"messages": [{ "role": "user", "content": "Prove there are infinitely many primes." }]
}Supported efforts are listed per model in the catalog (reasoning.supported_efforts),
e.g. low / medium / high / xhigh / max. Some models make reasoning mandatory.
Routing preferences
Pass provider routing through unchanged:
{
"model": "deepseek/deepseek-v4.1-flash",
"provider": {
"sort": "throughput",
"zdr": true,
"data_collection": "deny"
},
"messages": [{ "role": "user", "content": "Hello" }]
}Or use the model-id suffixes: :nitro, :floor, :exacto, :online,
:thinking, :extended.
Tools & structured output
tools, tool_choice, response_format (JSON schema / json_object), and
parallel_tool_calls are forwarded to the provider. Add
provider.require_parameters: true to only route to providers that support
every parameter you send.
Errors
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Missing/invalid model or messages |
| 401 | unauthorized | Bad or missing API key |
| 402 | insufficient_balance | Not enough AI credit — includes required_sats and balance_sats |
| 404 | model_not_found | Unknown id / stale catalog |
| 404 | model_retired | Model was retired upstream |
| 429 | upstream_rate_limited | Provider rate limit (common on free tiers) — retry or switch models |
| 502 | upstream_error | Provider returned an error (never billed) |
| 503 | ai_upstream_unavailable | Gateway upstream temporarily down — retry shortly |
Errors use the OpenAI error envelope: { "error": { "message", "code" } }.
Failed calls are never billed
If the upstream errors before producing a completion, the charge is $0 and
the query is logged with an errorCode for your audit trail. See
Billing & Sats Pricing.