Api.Airforce
API REFERENCE

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_KEY

POST /v1/chat/completions

Completamenti chat compatibili con OpenAI. Funziona con il funzionario openai SDK eseguendo l'override base_url A https://api.airforce/v1.

POSThttps://api.airforce/v1/chat/completions

Richiedi corpo

ParameterTypeRequiredDescription
modelstringRequiredID modello. Utilizza GET /v1/models per scoprire gli ID disponibili.
messagesarrayRequiredCronologia 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_tokensintegerOptionalNumero massimo di token da generare. Limitato ai max_output_tokens del modello.
temperaturefloatOptionalTemperatura di campionamento, 0–2. Il valore inferiore è più deterministico. L'impostazione predefinita dipende dal provider upstream.
top_pfloatOptionalCampionamento del nucleo. Utilizza temperature o top_p, non entrambi.
streambooleanOptionalQuando è vero, la risposta è un flusso di eventi inviati dal server. Vedere "Streaming" di seguito.
modelsarrayOptionalFallback 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.
transformsarrayOptionalPrompt 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_optionsobjectOptional{ include_usage: boolean }. L’uso è sempre incluso nell’ultimo chunk dello stream; questo campo è accettato per compatibilità con OpenAI ma non può disattivarlo.
stopstring | arrayOptionalFino a 4 sequenze di arresto. La generazione si interrompe non appena ne viene prodotta una.
toolsarrayOptionalDefinizioni di funzioni che il modello può chiamare. Vedere "Chiamata utensile" di seguito.
tool_choicestring | objectOptional"auto" (predefinito), "none", oppure { type: "function", function: { name } } per forzare una chiamata specifica.
response_formatobjectOptional{ type: "json_object" } forza il modello a emettere JSON valido. Ignorato per i modelli che non lo supportano.
reasoning_effortstringOptionalReasoning depth: "low" | "medium" | "high" | "xhigh" | "max". Any model with supports_reasoning: true (Claude, OpenAI o/GPT-5, Gemini, Qwen, DeepSeek, …). See "Reasoning & thinking".
thinkingstring | objectOptionalCross-model thinking switch. "on" | "off" | "auto"; Anthropic-style { type: "enabled", budget_tokens: N }; hybrid { type: "enabled" | "disabled" }. See "Reasoning & thinking".
thinking_budgetintegerOptionalToken cap per la traccia del ragionamento del modello (quando il provider ne espone uno).
ignore_defaultsbooleanOptionalIgnora i parametri predefiniti per modello salvati dall'utente (configurati nel dashboard) per questa richiesta.
skillstringOptionalID 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.
skillsarrayOptionalArray 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

ParameterTypeRequiredDescription
idstringOptionalID di completamento stabile, ad es. "chatcmpl-abc123".
objectstringOptional"chat.completion" per non in streaming, "chat.completion.chunk" per in streaming.
createdintegerOptionalTimestamp Unix (secondi).
modelstringOptionalEco dell'ID del modello richiesto.
choicesarrayOptionalArray di candidati di completamento: [{ index, message: { role, content, tool_calls? }, finish_reason }].
choices[].finish_reasonstringOptional"fermare" | "lunghezza" | "chiamate_strumento" | "filtro_contenuto".
usageobjectOptional{ 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

· live

Parametri canonici

ParameterTypeRequiredDescription
reasoning_effortstringOptional"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.
thinkingstring | objectOptionalThree 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_budgetintegerOptionalMaximum 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:

  • ClaudeThinking 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.
  • Geminithinking_config / budget mapped internally.
  • Qwen / Xiaomi / Alibabathinking + enable_thinking-style controls.
  • DeepSeek (generic)Hybrid on/off is especially clear: thinking: { type: enabled|disabled } plus optional reasoning_effort.
  • Resellers / otherOften 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.

ParameterTypeRequiredDescription
reasoning.formatstringOptional"separate" (default) puts the trace in message.reasoning (and delta.reasoning while streaming). "inline" keeps the legacy inline <think>…</think> form inside content.
reasoning.excludebooleanOptionalWhen 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

· live
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": [
        {"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

· live

Richiesta

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.

POSThttps://api.airforce/v1/messages

Richiedi corpo

ParameterTypeRequiredDescription
modelstringRequiredID modello (formato Anthropic o alias instradato).
messagesarrayRequiredOgni voce: { role: "user" | "assistant", content: string | array }.
max_tokensintegerRequiredRichiesto da Anthropic. Limite token per la risposta.
systemstring | arrayOptionalPrompt di sistema. Passa un array di blocchi { type: "text", text, cache_control? } per contrassegnare i segmenti di prefisso memorizzati nella cache. Vedi "Prompt caching".
temperaturefloatOptional0–1.
top_pfloatOptionalCampionamento del nucleo.
top_kintegerOptionalLimita il pool di campionamento ai token top-K.
stop_sequencesarrayOptionalFino a 4 sequenze di arresto.
streambooleanOptionalQuando è vero, emette un flusso di eventi SSE in stile Anthropic (vedi "Streaming").
fallbacksarrayOptionalFallback 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.
toolsarrayOptionalDefinizioni degli strumenti Anthropic: { name, description, input_schema }. La risposta può contenere blocchi di contenuto tool_use.
tool_choiceobjectOptional{ type: "auto" | "any" | "tool", name? }.
thinkingobjectOptionalPensiero 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

ParameterTypeRequiredDescription
idstringOptionalID del messaggio, ad es. "msg_01ABCxyz".
typestringOptionalSempre "messaggio".
rolestringOptionalSempre "assistente".
contentarrayOptionalArray di blocchi di contenuto: { type: "text" | "tool_use" | "thinking", … }.
modelstringOptionalEco del modello richiesto.
stop_reasonstringOptional"fine_turno" | "max_token" | "stop_sequenza" | "strumento_uso".
usageobjectOptional{ 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.

POSThttps://api.airforce/v1/messages/count_tokens
curl 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.

POSThttps://api.airforce/v1/responses

POST /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).

POSThttps://api.airforce/v1beta/models/{model}:generateContent

Authentication

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_KEY

Request body

ParameterTypeRequiredDescription
contentsarrayRequiredConversation 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.
systemInstructionobjectOptionalSystem prompt: { parts: [{ text }] }.
generationConfigobjectOptional{ temperature, maxOutputTokens, topP, stopSequences } — mapped to the canonical sampling parameters.
toolsarrayOptionalTool definitions: [{ functionDeclarations: [{ name, description, parameters }] }]. functionDeclarations are flattened across entries.
toolConfigobjectOptionalTool-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

ParameterTypeRequiredDescription
candidatesarrayOptionalGenerated turns: [{ content: { role: "model", parts }, finishReason, index }]. Only the first candidate is populated.
candidates[].finishReasonstringOptional"STOP" | "MAX_TOKENS" | "SAFETY" | "OTHER".
usageMetadataobjectOptional{ promptTokenCount, candidatesTokenCount, totalTokenCount, cachedContentTokenCount? }. cachedContentTokenCount appears when the upstream reported a cache read.
modelVersionstringOptionalEcho 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/models

Notes: 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.

ParameterTypeRequiredDescription
400invalid_request_errorOptionalJSON non valido, campo obbligatorio mancante, modello sconosciuto.
401invalid_request_error / auth_requiredOptionalChiave API mancante o non valida.
402insufficient_quotaOptionalIl modello richiede un abbonamento attivo o un saldo Pay-as-you-Go positivo.
403model_access_denied / insufficient_scopeOptionalLe autorizzazioni per piano o per chiave negano questa richiesta.
404model_not_foundOptionalIl modello richiesto non esiste o non hai accesso ad esso.
429rate_limit_errorOptionalLa tariffa della richiesta o il limite massimo di token giornaliero è stato superato.
503api_error / moderation_unavailableOptionalTutte 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"