Completamenti della chat
Genera risposte chat su oltre 100 modelli da un'unica API. Drop-in compatibile con i completamenti della chat OpenAI, i messaggi Anthropic e le risposte Anthropic.
Airforce parla sia il formato OpenAI Chat Completions sia quello Anthropic Messages sullo stesso insieme di modelli. Scegli l'SDK che già usi e cambia soltanto la base URL — i modelli non-Claude vengono inoltrati in modo trasparente dietro entrambe le interfacce.
Questa pagina copre l'autenticazione, la struttura di richiesta e risposta per entrambe le interfacce, lo streaming, il tool calling, la vision, il reasoning e il prompt caching. Sei nuovo qui? Inizia con l'esempio base qui sotto, fai funzionare una chiamata, poi aggiungi streaming, tools o caching una volta che funziona.
Autenticazione
Ogni richiesta necessita di un token Bearer (la tua chiave API Airforce). Anthropic x-api-key viene accettata anche l'intestazione /v1/messages per la compatibilità dell'SDK.
Authorization: Bearer sk-air-YOUR_API_KEY
# alt for /v1/messages:
x-api-key: sk-air-YOUR_API_KEYPOST /v1/chat/completions
Completamenti chat compatibili con OpenAI. Funziona con il funzionario openai SDK eseguendo l'override base_url A https://api.airforce/v1.
https://api.airforce/v1/chat/completionsRichiedi corpo
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Required | ID modello. Utilizza GET /v1/models per scoprire gli ID disponibili. |
| messages | array | Required | Cronologia della conversazione. Ogni voce ha { role: "system" | "user" | "assistant" | "tool", content }. Il contenuto è una stringa o un array di blocchi di contenuto (vision, vedi sotto). |
| max_tokens | integer | Optional | Numero massimo di token da generare. Limitato ai max_output_tokens del modello. |
| temperature | float | Optional | Temperatura di campionamento, 0–2. Il valore inferiore è più deterministico. L'impostazione predefinita dipende dal provider upstream. |
| top_p | float | Optional | Campionamento del nucleo. Utilizza temperature o top_p, non entrambi. |
| stream | boolean | Optional | Quando è vero, la risposta è un flusso di eventi inviati dal server. Vedere "Streaming" di seguito. |
| models | array | Optional | Fallback models (max 3), e.g. ["deepseek-v3.2", "gpt-4o-mini"]. If every channel of the primary model fails, each candidate is tried in order. You are billed for — and response.model reports — the model that actually answered. Unknown or plan-gated candidates are skipped. With the OpenAI SDK pass it via extra_body. |
| transforms | array | Optional | Prompt transforms. Supported: ["middle-out"] — when the conversation overflows the model's context window, whole messages are dropped from the middle (system prompts, the first message and the most recent turns are kept), so long roleplay or agent histories keep working instead of erroring. Opt-in; off by default. |
| stream_options | object | Optional | { include_usage: boolean }. L’uso è sempre incluso nell’ultimo chunk dello stream; questo campo è accettato per compatibilità con OpenAI ma non può disattivarlo. |
| stop | string | array | Optional | Fino a 4 sequenze di arresto. La generazione si interrompe non appena ne viene prodotta una. |
| tools | array | Optional | Definizioni di funzioni che il modello può chiamare. Vedere "Chiamata utensile" di seguito. |
| tool_choice | string | object | Optional | "auto" (predefinito), "none", oppure { type: "function", function: { name } } per forzare una chiamata specifica. |
| response_format | object | Optional | { type: "json_object" } forza il modello a emettere JSON valido. Ignorato per i modelli che non lo supportano. |
| reasoning_effort | string | Optional | Reasoning depth: "low" | "medium" | "high" | "xhigh" | "max". Any model with supports_reasoning: true (Claude, OpenAI o/GPT-5, Gemini, Qwen, DeepSeek, …). See "Reasoning & thinking". |
| thinking | string | object | Optional | Cross-model thinking switch. "on" | "off" | "auto"; Anthropic-style { type: "enabled", budget_tokens: N }; hybrid { type: "enabled" | "disabled" }. See "Reasoning & thinking". |
| thinking_budget | integer | Optional | Token cap per la traccia del ragionamento del modello (quando il provider ne espone uno). |
| ignore_defaults | boolean | Optional | Ignora i parametri predefiniti per modello salvati dall'utente (configurati nel dashboard) per questa richiesta. |
| skill | string | Optional | ID of a single marketplace skill to apply to this request. The skill transforms your messages/parameters before the upstream call and overrides any installed-skill defaults. Consumed by Airforce, never forwarded upstream. See the Skills catalog at /docs/api/extend. |
| skills | array | Optional | Array of marketplace skill IDs applied in order, for stacking multiple skills on one request. |
Esempio di base
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1-chat",
"messages": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "What is the capital of France?"}
],
"max_tokens": 200,
"temperature": 0.7
}'Forma della risposta
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Optional | ID di completamento stabile, ad es. "chatcmpl-abc123". |
| object | string | Optional | "chat.completion" per non in streaming, "chat.completion.chunk" per in streaming. |
| created | integer | Optional | Timestamp Unix (secondi). |
| model | string | Optional | Eco dell'ID del modello richiesto. |
| choices | array | Optional | Array di candidati di completamento: [{ index, message: { role, content, tool_calls? }, finish_reason }]. |
| choices[].finish_reason | string | Optional | "fermare" | "lunghezza" | "chiamate_strumento" | "filtro_contenuto". |
| usage | object | Optional | { prompt_tokens, completion_tokens, total_tokens, completion_tokens_details?, prompt_tokens_details?, cache_creation_input_tokens?, cache_creation? }. completion_tokens_details.reasoning_tokens viene impostato quando il modello ha prodotto una traccia di ragionamento. I campi cache compaiono quando l'upstream ha restituito informazioni sul prompt caching: prompt_tokens_details.cached_tokens riporta le letture cache (standard OpenAI), cache_creation_input_tokens aggrega le scritture, e cache_creation.ephemeral_5m_input_tokens / ephemeral_1h_input_tokens forniscono la suddivisione per TTL. |
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"created": 1710000000,
"model": "gpt-5.1-chat",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": "The capital of France is Paris."
},
"finish_reason": "stop"
}],
"usage": {
"prompt_tokens": 20,
"completion_tokens": 8,
"total_tokens": 28
}
}Ragionamento e pensiero
Reasoning/thinking is a cross-model feature for every model ID with supports_reasoning: true — Claude, OpenAI o-series/GPT-5, Gemini, Qwen, DeepSeek, and others. You send the same canonical parameters; Airforce maps them to each provider's native shape. This is not a DeepSeek-only API.
Truth source: check supports_reasoning: true su un modello in GET /v1/models (or GET /api/models/{id}/allowed-params). Prefer that flag over guessing from the model name.
Modelli con supporto del ragionamento
…· liveParametri canonici
| Parameter | Type | Required | Description |
|---|---|---|---|
| reasoning_effort | string | Optional | "low" | "medium" | "high" | "xhigh" | "max". Accepted on every model with supports_reasoning: true. Some upstreams only honour a subset (e.g. high/max); others clamp unsupported levels to the nearest served value. |
| thinking | string | object | Optional | Three accepted shapes (we normalise): "on" | "off" | "auto"; Anthropic-style { type: "enabled", budget_tokens: N }; hybrid { type: "enabled" | "disabled" }. Mapped onto Claude extended thinking, OpenAI effort profiles, Gemini thinking_config, Qwen enable_thinking, DeepSeek hybrid, etc. |
| thinking_budget | integer | Optional | Maximum tokens the model may spend reasoning before emitting visible output. Mirrors budget_tokens when the upstream exposes a budget; takes precedence over reasoning_effort when both are sent and a budget is available. |
What differs by family (mapping only)
Parameters are the same everywhere. Only how we map them (and how hard "off" is) differs:
- Claude — Thinking on/off + budget; often also reasoning_effort via the gateway.
- OpenAI (o1/o3, GPT-5) — Mainly reasoning_effort. A full "thinking off" is often not available — you control how strongly the model reasons, not always whether it reasons at all.
- Gemini — thinking_config / budget mapped internally.
- Qwen / Xiaomi / Alibaba — thinking + enable_thinking-style controls.
- DeepSeek (generic) — Hybrid on/off is especially clear: thinking: { type: enabled|disabled } plus optional reasoning_effort.
- Resellers / other — Often generic passthrough of the same canonical fields.
Controlling where the trace appears
An optional reasoning object on the request decides what happens to the thinking trace. It is consumed by Airforce and never forwarded upstream.
| Parameter | Type | Required | Description |
|---|---|---|---|
| reasoning.format | string | Optional | "separate" (default) puts the trace in message.reasoning (and delta.reasoning while streaming). "inline" keeps the legacy inline <think>…</think> form inside content. |
| reasoning.exclude | boolean | Optional | When true, the reasoning trace is dropped entirely from the response. Reasoning tokens are still counted and billed if the model produced them. |
"reasoning": { "format": "separate", "exclude": false }Sforzo di ragionamento (stile OpenAI)
Primary control for o-series and GPT-5: how much the model may reason. Same canonical field as on every other supports_reasoning model — OpenAI is included, but behaviour is not 1:1 with DeepSeek's hard on/off.
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "o3-mini",
"messages": [{"role": "user", "content": "Prove the Pythagorean theorem."}],
"reasoning_effort": "high"
}'Pensiero esteso (stile Anthropic)
Budget-based thinking for Claude (and gateways that accept the Anthropic shape). You can still send reasoning_effort; we map when the channel supports it.
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4.6",
"messages": [{"role": "user", "content": "Plan a 7-day Italy trip."}],
"thinking": {"type": "enabled", "budget_tokens": 4000}
}'Hybrid thinking (e.g. DeepSeek V3.2/V4)
Example of a hybrid model family with a clear Thinking / Non-Thinking switch — not a separate protocol. deepseek-v3.2, deepseek-v4-flash and deepseek-v4-pro accept the same canonical fields as every other supports_reasoning model. Toggle thinking and optionally set effort in one request:
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "deepseek-v4-pro",
"messages": [{"role": "user", "content": "Solve this step by step: integrate x^2 * e^x."}],
"thinking": {"type": "enabled"},
"reasoning_effort": "high"
}'Turn thinking off (faster, cheaper when you only need the final answer) — this hard off is clearer on hybrid models than on many OpenAI o-series profiles:
"thinking": {"type": "disabled"}
// or simply: "thinking": "off"Native docs for this family often list effort levels such as "high" and "max". We accept the full low…max scale and map unsupported levels to the nearest value that reaches the model. Prefer the hybrid IDs above over retired deepseek-chat / deepseek-reasoner names when you need an explicit on/off switch.
La traccia stessa del ragionamento appare in choices[0].message.reasoning (forma OpenAI) o come thinking blocchi dentro content (Formato Anthropic). I gettoni ragionamento vengono fatturati e riportati usage.completion_tokens_details.reasoning_tokens.
Quel dettaglio completion_tokens_details.reasoning_tokens è presente solo quando il provider upstream lo riporta. In una risposta in stream la traccia arriva su delta.reasoning_content per ogni chunk.
Input di visione e immagine
Modelli con supports_vision: true accettare immagini incorporate come blocchi di contenuto. Funziona sia un URL pubblico che un URL di dati base64; i limiti di dimensione dipendono dal modello a monte.
Modelli con supporto visivo
…· livecurl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1-chat",
"messages": [{
"role": "user",
"content": [
{"type": "text", "text": "What is in this image?"},
{"type": "image_url", "image_url": {"url": "https://example.com/cat.jpg"}}
]
}]
}'Chiamata dello strumento
Modelli con supports_tools: true può chiamare le funzioni definite dall'utente. Il modello restituisce a tool_calls vettore; esegui la chiamata, quindi invii il risultato in a tool messaggio.
Modelli con supporto per la chiamata degli strumenti
…· liveRichiesta
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1-chat",
"messages": [{"role": "user", "content": "What is the weather in Paris?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string", "description": "City name"}
},
"required": ["location"]
}
}
}],
"tool_choice": "auto"
}'Risposta con chiamata utensile
{
"id": "chatcmpl-abc123",
"choices": [{
"index": 0,
"message": {
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_1",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris\"}"
}
}]
},
"finish_reason": "tool_calls"
}]
}Follow-up con il risultato dello strumento
{
"model": "gpt-5.1-chat",
"messages": [
{"role": "user", "content": "What is the weather in Paris?"},
{
"role": "assistant",
"content": null,
"tool_calls": [{
"id": "call_1",
"type": "function",
"function": {"name": "get_weather", "arguments": "{\"location\":\"Paris\"}"}
}]
},
{"role": "tool", "tool_call_id": "call_1", "content": "{\"temp_c\": 14, \"sky\": \"cloudy\"}"}
]
}Assistant prefill
End your messages array with an assistant message that already contains some text, and the model continues from it instead of starting a fresh turn. This is a reliable way to force a response to begin a specific way — a leading "{" for JSON, a chosen language, or a fixed prefix. The same trick works on /v1/messages. Providers that reject native prefill are handled automatically: the gateway retries once with a compatible rewrite, so you do not have to special-case them.
{
"model": "claude-sonnet-4.6",
"messages": [
{"role": "user", "content": "List three primary colors as a JSON array."},
{"role": "assistant", "content": "["}
]
}Structured outputs
Set response_format to make the model return JSON. Two modes are supported:
{ "type": "json_object" }— the response is a single valid JSON value.{ "type": "json_schema", "json_schema": { "name", "schema", "strict" } }— the model is steered to produce JSON that matches your JSON Schema.
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1-chat",
"messages": [{"role": "user", "content": "Extract the city and country: I live in Paris, France."}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "location",
"schema": {
"type": "object",
"properties": { "city": {"type": "string"}, "country": {"type": "string"} },
"required": ["city", "country"]
}
}
}
}'Reliability: even when a model wraps its answer in prose or a markdown code fence, Airforce extracts the JSON payload so you always receive parseable content. If no valid JSON can be recovered, the original text is returned unchanged — so the guarantee never makes a response worse. This applies to non-streamed responses; streamed responses are passed through unchanged.
Streaming
Impostato stream: true per ricevere completamenti parziali come eventi inviati dal server. Ogni evento è un blocco JSON con la stessa forma della risposta non trasmessa in streaming, tranne message è sostituito da delta. Lo streaming termina con data: [DONE].
curl https://api.airforce/v1/chat/completions \
-H "Authorization: Bearer sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.1-chat",
"messages": [{"role": "user", "content": "Write a haiku about Berlin."}],
"stream": true,
"stream_options": {"include_usage": true}
}'Formato filo
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1710000000,"model":"gpt-5.1-chat","choices":[{"index":0,"delta":{"role":"assistant"},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1710000000,"model":"gpt-5.1-chat","choices":[{"index":0,"delta":{"content":"Cold "},"finish_reason":null}]}
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1710000000,"model":"gpt-5.1-chat","choices":[{"index":0,"delta":{"content":"stone "},"finish_reason":null}]}
…
data: {"id":"chatcmpl-abc123","object":"chat.completion.chunk","created":1710000000,"model":"gpt-5.1-chat","choices":[{"index":0,"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":12,"completion_tokens":17,"total_tokens":29}}
data: [DONE]Reliability & smart routing
Every model ID resolves to a pool of upstream providers behind the scenes. If the first one errors or times out, the request is automatically retried against the next provider for the same model, in order, before any failure is returned — you do not configure or trigger this. The model field in the response always reports the variant that actually answered. This is independent of the optional models / fallbacks array, which adds your own cross-model candidates on top: first the primary model exhausts its own provider chain, then each fallback model exhausts its chain.
POST /v1/messages
API di messaggistica compatibile con Anthropic. Funziona con il funzionario @anthropic-ai/sdk impostando baseURL A https://api.airforce. Inoltra a OpenAI/Google/ecc. in modo trasparente per i modelli non Claude.
https://api.airforce/v1/messagesRichiedi corpo
| Parameter | Type | Required | Description |
|---|---|---|---|
| model | string | Required | ID modello (formato Anthropic o alias instradato). |
| messages | array | Required | Ogni voce: { role: "user" | "assistant", content: string | array }. |
| max_tokens | integer | Required | Richiesto da Anthropic. Limite token per la risposta. |
| system | string | array | Optional | Prompt di sistema. Passa un array di blocchi { type: "text", text, cache_control? } per contrassegnare i segmenti di prefisso memorizzati nella cache. Vedi "Prompt caching". |
| temperature | float | Optional | 0–1. |
| top_p | float | Optional | Campionamento del nucleo. |
| top_k | integer | Optional | Limita il pool di campionamento ai token top-K. |
| stop_sequences | array | Optional | Fino a 4 sequenze di arresto. |
| stream | boolean | Optional | Quando è vero, emette un flusso di eventi SSE in stile Anthropic (vedi "Streaming"). |
| fallbacks | array | Optional | Fallback models (max 3) in Anthropic form: [{"model": "gpt-4o-mini"}]. If every channel of the primary model fails, each candidate is tried in order; you are billed for — and the response model field reports — the model that actually answered. A plain models string array is accepted too. |
| tools | array | Optional | Definizioni degli strumenti Anthropic: { name, description, input_schema }. La risposta può contenere blocchi di contenuto tool_use. |
| tool_choice | object | Optional | { type: "auto" | "any" | "tool", name? }. |
| thinking | object | Optional | Pensiero esteso Anthropic: { type: "enabled", budget_tokens: N }. |
Esempio
curl https://api.airforce/v1/messages \
-H "x-api-key: sk-air-YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4.6",
"max_tokens": 256,
"system": "You are a helpful assistant.",
"messages": [
{"role": "user", "content": "Hello, Claude!"}
]
}'Forma della risposta
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Optional | ID del messaggio, ad es. "msg_01ABCxyz". |
| type | string | Optional | Sempre "messaggio". |
| role | string | Optional | Sempre "assistente". |
| content | array | Optional | Array di blocchi di contenuto: { type: "text" | "tool_use" | "thinking", … }. |
| model | string | Optional | Eco del modello richiesto. |
| stop_reason | string | Optional | "fine_turno" | "max_token" | "stop_sequenza" | "strumento_uso". |
| usage | object | Optional | { input_tokens, output_tokens, cache_read_input_tokens?, cache_creation_input_tokens?, cache_creation? }. I campi cache compaiono quando è stato usato il prompt caching. cache_creation.ephemeral_5m_input_tokens e ephemeral_1h_input_tokens forniscono la suddivisione delle scritture per TTL. |
Eventi in streaming
Anthropic SSE utilizza eventi denominati anziché blocchi JSON una tantum. Ogni evento ha sia un event: nome e a data: Carico utile JSON.
event: message_start
data: {"type":"message_start","message":{"id":"msg_01","role":"assistant","content":[],"model":"claude-sonnet-4.6","stop_reason":null,"usage":{"input_tokens":12,"output_tokens":1}}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Hello"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":17}}
event: message_stop
data: {"type":"message_stop"}POST /v1/messages/count_tokens
Anthropic-compatible token counting. Send the same system / messages / tools you would pass to /v1/messages and get an input-token estimate back without running the model — nothing is billed.
https://api.airforce/v1/messages/count_tokenscurl https://api.airforce/v1/messages/count_tokens \
-H "x-api-key: sk-air-YOUR_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4.6",
"system": "You are a helpful assistant.",
"messages": [{"role": "user", "content": "Hello, Claude!"}]
}'
# → {"input_tokens": 34}The count is a fast character-based estimate (about 4 characters per token) over system, messages and tools — close enough for context-budget checks, not an exact tokenizer run.
Memorizzazione nella cache immediata
SU /v1/messages con i modelli Claude, contrassegna un prefisso come memorizzato nella cache passando system come un array di blocchi in cui trasporta il segmento memorizzato nella cache cache_control: { type: "ephemeral" }. Le richieste successive che iniziano con lo stesso prefisso addebitano la tariffa di lettura della cache più economica. Modelli con supports_caching: true In /v1/models sostenere questo.
Modelli con memorizzazione nella cache immediata
…· live{
"model": "claude-sonnet-4.6",
"max_tokens": 1024,
"system": [
{"type": "text", "text": "You are a senior staff engineer at Airforce."},
{
"type": "text",
"text": "<repository-snapshot>...</repository-snapshot>",
"cache_control": {"type": "ephemeral"}
}
],
"messages": [
{"role": "user", "content": "Where is rate limiting enforced?"}
]
}Come vengono riportati i conteggi cache nella risposta
I conteggi dei token cache vengono passati nella forma nativa di ogni formato, così gli SDK (openai, @anthropic-ai/sdk, @google/genai) li leggono senza codice personalizzato. I campi vengono omessi quando il valore è zero, mantenendo leggere le risposte non cached.
/v1/chat/completions (forma OpenAI)
"usage": {
"prompt_tokens": 2104,
"completion_tokens": 147,
"total_tokens": 2251,
"prompt_tokens_details": { "cached_tokens": 1980 },
"cache_creation_input_tokens": 124,
"cache_creation": {
"ephemeral_5m_input_tokens": 124,
"ephemeral_1h_input_tokens": 0
}
}/v1/messages (forma Anthropic)
"usage": {
"input_tokens": 2104,
"output_tokens": 147,
"cache_read_input_tokens": 1980,
"cache_creation_input_tokens": 124,
"cache_creation": {
"ephemeral_5m_input_tokens": 124,
"ephemeral_1h_input_tokens": 0
}
}/v1beta/.../generateContent (forma Gemini)
"usageMetadata": {
"promptTokenCount": 2104,
"candidatesTokenCount": 147,
"totalTokenCount": 2251,
"cachedContentTokenCount": 1980
}Dove si applica la cache
I marcatori cache_control espliciti sono rispettati su /v1/messages e /v1/chat/completions per i modelli Claude — mettili sui blocchi di contenuto system o message. Molti altri provider (famiglia OpenAI, DeepSeek, Gemini) mettono in cache automaticamente: non invii marcatori e vedi semplicemente cached_tokens nella risposta quando un prefisso abbastanza lungo viene riutilizzato.
Durata della cache: 5 minuti o 1 ora
Un prefisso in cache vive 5 minuti per impostazione predefinita e il timer si rinnova a ogni hit. Per un prefisso più duraturo, aggiungi ttl: "1h" al marcatore. La risposta riporta ogni TTL separatamente sotto cache_creation.
"cache_control": { "type": "ephemeral", "ttl": "1h" }Esempio: prima write, poi read
Invia esattamente la stessa richiesta due volte (l’esempio di cache sopra). La prima chiamata che vede il prefisso paga una write di cache una tantum; le chiamate identiche entro la TTL pagano la read di cache molto più economica.
Prima chiamata — write di cache (estratto usage):
"usage": {
"input_tokens": 2104,
"output_tokens": 12,
"cache_creation_input_tokens": 1980,
"cache_read_input_tokens": 0
}Seconda chiamata identica entro la TTL — read di cache:
"usage": {
"input_tokens": 2104,
"output_tokens": 12,
"cache_creation_input_tokens": 0,
"cache_read_input_tokens": 1980
}Limiti e costo
- Claude richiede un prefisso minimo memorizzabile (circa 1024 token; di più per alcuni modelli). I prefissi più corti semplicemente non vengono messi in cache.
- Fino a 4 breakpoint di cache per richiesta, e il prefisso in cache deve essere identico byte per byte tra le chiamate — anche una modifica di un carattere manca la cache.
- Le write di cache costano più dell’input normale (5m ≈ 1,25×, 1h ≈ 2×); le read costano molto meno (≈ 0,1×). Vedi i prezzi di cache di ogni modello nella pagina prezzi.
POST /v1/responses
Superficie OpenAI Responses-API per conversazioni stateful. Stessa autenticazione Bearer/x-api-key. I conteggi cache compaiono come input_tokens_details.cached_tokens (lettura) più cache_creation_input_tokens flat + cache_creation.ephemeral_* (scritture) per parità con /v1/chat/completions.
https://api.airforce/v1/responsesPOST /v1beta/models/{model}:generateContent
Google Gemini-compatible endpoint. Works with the official @google/genai SDK and the Gemini CLI by pointing the base URL at https://api.airforce/v1beta. Any routed model works — requests are translated to and from the native Gemini shape, and the model is taken from the URL path (not the body).
https://api.airforce/v1beta/models/{model}:generateContentAuthentication
Pass your Airforce API key any of the three ways Google clients use:
# 1) query parameter (Google default)
?key=sk-air-YOUR_API_KEY
# 2) header
x-goog-api-key: sk-air-YOUR_API_KEY
# 3) bearer token
Authorization: Bearer sk-air-YOUR_API_KEYRequest body
| Parameter | Type | Required | Description |
|---|---|---|---|
| contents | array | Required | Conversation turns. Each: { role: "user" | "model", parts: [...] }. A part is { text }, { functionCall: { name, args } }, or { functionResponse: { name, response } }. "model" is Gemini's term for the assistant role. |
| systemInstruction | object | Optional | System prompt: { parts: [{ text }] }. |
| generationConfig | object | Optional | { temperature, maxOutputTokens, topP, stopSequences } — mapped to the canonical sampling parameters. |
| tools | array | Optional | Tool definitions: [{ functionDeclarations: [{ name, description, parameters }] }]. functionDeclarations are flattened across entries. |
| toolConfig | object | Optional | Tool-choice control: { functionCallingConfig: { mode: "AUTO" | "ANY" | "NONE" } }. ANY forces a call, NONE disables tools. |
Example
curl "https://api.airforce/v1beta/models/gemini-3.1-pro:generateContent" \
-H "x-goog-api-key: sk-air-YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [
{"role": "user", "parts": [{"text": "What is the capital of France?"}]}
],
"systemInstruction": {"parts": [{"text": "You are a helpful assistant."}]},
"generationConfig": {"temperature": 0.7, "maxOutputTokens": 256}
}'Response shape
| Parameter | Type | Required | Description |
|---|---|---|---|
| candidates | array | Optional | Generated turns: [{ content: { role: "model", parts }, finishReason, index }]. Only the first candidate is populated. |
| candidates[].finishReason | string | Optional | "STOP" | "MAX_TOKENS" | "SAFETY" | "OTHER". |
| usageMetadata | object | Optional | { promptTokenCount, candidatesTokenCount, totalTokenCount, cachedContentTokenCount? }. cachedContentTokenCount appears when the upstream reported a cache read. |
| modelVersion | string | Optional | Echo of the requested model. |
{
"candidates": [{
"content": {
"role": "model",
"parts": [{"text": "The capital of France is Paris."}]
},
"finishReason": "STOP",
"index": 0
}],
"usageMetadata": {
"promptTokenCount": 16,
"candidatesTokenCount": 8,
"totalTokenCount": 24
},
"modelVersion": "gemini-3.1-pro"
}POST /v1beta/models/{model}:streamGenerateContent
Streaming uses the :streamGenerateContent action and returns Server-Sent Events. Each data: line is a full Gemini-shaped chunk (not a delta object); the final chunk carries usageMetadata.
data: {"candidates":[{"content":{"role":"model","parts":[{"text":"The capital"}]},"index":0}],"modelVersion":"gemini-3.1-pro"}
data: {"candidates":[{"content":{"role":"model","parts":[{"text":" is Paris."}]},"index":0}],"modelVersion":"gemini-3.1-pro"}
data: {"candidates":[{"content":{"role":"model","parts":[]},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":16,"candidatesTokenCount":8,"totalTokenCount":24}}List models
The catalog is also exposed in Gemini Model-resource shape so Google clients can enumerate models.
curl https://api.airforce/v1beta/modelsNotes: the base URL is https://api.airforce/v1beta (or /v1), not Google's host. The model name comes from the URL path, not the request body. Only the first candidate is returned, and a subset of Gemini fields is translated — safetySettings and cachedContent are currently ignored. Billing, rate limits and smart routing apply exactly as on /v1/chat/completions.
Errori
Airforce restituisce codici di stato HTTP standard e una busta di errore uniforme per entrambi gli endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
| 400 | invalid_request_error | Optional | JSON non valido, campo obbligatorio mancante, modello sconosciuto. |
| 401 | invalid_request_error / auth_required | Optional | Chiave API mancante o non valida. |
| 402 | insufficient_quota | Optional | Il modello richiede un abbonamento attivo o un saldo Pay-as-you-Go positivo. |
| 403 | model_access_denied / insufficient_scope | Optional | Le autorizzazioni per piano o per chiave negano questa richiesta. |
| 404 | model_not_found | Optional | Il modello richiesto non esiste o non hai accesso ad esso. |
| 429 | rate_limit_error | Optional | La tariffa della richiesta o il limite massimo di token giornaliero è stato superato. |
| 503 | api_error / moderation_unavailable | Optional | Tutte le chiavi upstream per il provider richiesto non sono riuscite. |
{
"error": {
"message": "The requested model does not exist or you do not have access to it.",
"type": "model_not_found",
"param": null,
"code": "404"
}
}Lo slug descrittivo si trova in type. code è lo stato HTTP come stringa (es. "404"), e param è null tranne che negli errori di validazione del range dei parametri, dove indica il parametro problematico.
Scopri i modelli
Consulta l'elenco completo degli ID modello e i relativi flag di capacità (visione, strumenti, ragionamento, memorizzazione nella cache, lunghezza del contesto, ...) all'indirizzo /docs/api/models.
curl https://api.airforce/v1/models \
-H "Authorization: Bearer sk-air-YOUR_API_KEY"