Documentazione

Documentazione

API di utilizzo

Consulta i conteggi dei token e i costi relativi alla chiave API usata per la richiesta. Una chiave, i suoi dati: nessun accesso incrociato tra chiavi. Usala per creare dashboard di fatturazione personalizzate, riconciliazioni mensili o avvisi sui costi.

GET /v1/usage restituisce i dati aggregati su token e costi relativi alla chiave API nell’intestazione Authorization. Raggruppa per giorno o ora; facoltativamente, suddividi per modello. Non è possibile leggere i dati di un’altra chiave: per farlo, accedi alla dashboard.

Autenticazione

Passa la tua chiave API Kunavo come token Bearer: deve essere la stessa chiave di cui vuoi consultare l’utilizzo. L’endpoint restituisce solo l’utilizzo addebitato a questa specifica chiave; non esiste un parametro per richiedere i dati di un’altra chiave.

Usa una chiave per progetto. L’approccio consigliato consiste nel creare una chiave API distinta per ogni applicazione di cui fatturi l’utilizzo; le dashboard Kunavo e questo endpoint raggrupperanno quindi automaticamente i dati «per progetto». Gestisci le chiavi in /app/keys.

Richiesta

ParametroObbligatorioPredefinitoNote
start_dateyes—YYYY-MM-DD, UTC. Estremo incluso. Deve essere ≤ oggi (UTC).
end_dateyes—YYYY-MM-DD, UTC. Inclusivo. Una data successiva a oggi viene interpretata come oggi; la risposta ripete il valore end_date utilizzato.
bucketnodayUno tra day, hour.
group_byno(none)Elenco separato da virgole. Valori supportati: model. Se omesso, restituisce una riga per intervallo.
Limiti dell’intervallo. bucket=day accetta fino a 90 giorni; bucket=hour accetta fino a 7 giorni. Se si supera il limite, la richiesta restituisce 400 invalid_request_error: suddividila in più chiamate.
Fuso orario. Gli intervalli sono allineati ai giorni e alle ore UTC. Se ti servono giorni civili in un altro fuso orario, richiedi dati giornalieri e ricalcola gli intervalli parziali sul client. Un futuro parametro tz= eseguirà questa operazione lato server senza modificare i campi esistenti.

Esempi

Totali giornalieri degli ultimi 30 giorni, con tutti i modelli aggregati:

usage_30d.sh
# Daily totals for the last 30 days
curl https://api.kunavo.com/v1/usage \
  -G \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  --data-urlencode "start_date=2026-04-28" \
  --data-urlencode "end_date=2026-05-27"

Una riga per ogni coppia (giorno, modello):

usage_by_model.sh
# Per-model daily breakdown — one row per (day, model)
curl https://api.kunavo.com/v1/usage \
  -G \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  --data-urlencode "start_date=2026-05-01" \
  --data-urlencode "end_date=2026-05-27" \
  --data-urlencode "group_by=model"

Python — somma l’intervallo per ottenere un unico valore:

usage_query.py
import os, datetime as dt, requests

today = dt.date.today()
start = today - dt.timedelta(days=29)  # last 30 days inclusive

r = requests.get(
    "https://api.kunavo.com/v1/usage",
    headers={"Authorization": f"Bearer {os.environ['KUNAVO_API_KEY']}"},
    params={
        "start_date": start.isoformat(),
        "end_date":   today.isoformat(),
        "group_by":   "model",
    },
    timeout=30,
)
r.raise_for_status()
body = r.json()

# body["data"] is one row per (day, model). Sum cost across the window:
total_usd = sum(float(row["cost_usd"]) for row in body["data"])
print(f"Spent ${total_usd:.4f} on key {body['api_key']['name']}")

Risposta

200 OK — application/json con un elenco di righe. Gli intervalli senza attività, il cui valore è zero, vengono omessi; se serve una serie continua, il client può colmare i vuoti.

response.json
{
  "object": "list",
  "api_key": {
    "id": "k_abc123",
    "name": "production",
    "prefix": "sk-kn-aZ8x"
  },
  "start_date": "2026-05-01",
  "end_date":   "2026-05-27",
  "bucket": "day",
  "data": [
    {
      "bucket_start": "2026-05-01T00:00:00.000Z",
      "model": "claude-sonnet-4-6",
      "requests": 1284,
      "errors": 7,
      "input_tokens": 1532890,
      "output_tokens": 245100,
      "cached_input_tokens": 980000,
      "cache_write_tokens": 12000,
      "web_search_requests": 0,
      "cost_usd": "3.452100"
    },
    {
      "bucket_start": "2026-05-01T00:00:00.000Z",
      "model": "gpt-5",
      "requests": 88,
      "errors": 0,
      "input_tokens": 42000,
      "output_tokens": 12300,
      "cached_input_tokens": 0,
      "cache_write_tokens": 0,
      "web_search_requests": 0,
      "cost_usd": "0.210400"
    }
  ]
}
CampoTipoSignificato
bucket_startstringa (ISO 8601, UTC)Inizio del giorno o dell’ora aggregati in questa riga.
modelstringSlug del modello. Presente solo se group_by=model.
requestsnumberChiamate riuscite in questo intervallo.
errorsnumberChiamate terminate con errore, timeout o annullamento. Non fatturate.
input_tokensnumberTotale dei token di input (include i sottoinsiemi relativi alla cache e alle scritture nella cache).
output_tokensnumberTotale dei token di output.
cached_input_tokensnumberSottoinsieme di input_tokens servito dalla cache dei prompt del provider upstream.
cache_write_tokensnumberToken scritti nella cache per questo intervallo (solo Anthropic; 0 altrove).
web_search_requestsnumberRicerche web lato server, ciascuna fatturata in aggiunta ai token: quelle di Claude tramite /v1/messages e lo strumento web_search di OpenAI su un modello GPT tramite /v1/responses (0 negli altri casi).
cost_usdstringImporto addebitato in USD per questo intervallo, con precisione di 6 decimali. È una stringa per preservare la precisione; parseFloat() in modo sicuro.
Perché il costo è una stringa. I costi minimi per chiamata (pochi centesimi di millesimo per il traffico che sfrutta molto la cache) vengono arrotondati a zero con IEEE-754 se li si converte ingenuamente in stringa. Mantenere il formato di trasmissione come stringa con 6 decimali consente al codice di contabilità di analizzarlo con precisione arbitraria (ad es. Decimal()).

Memorizzazione nella cache lato client

L’endpoint imposta Cache-Control: private, max-age=60. La maggior parte dei client (browser, richieste con una sessione e qualsiasi cache HTTP lato tuo) restituirà la stessa risposta per gli stessi parametri entro un intervallo di 60 secondi: una soluzione adatta alle dashboard che eseguono richieste periodiche. Per forzare una lettura aggiornata, varia la stringa di query (ad es. aggiungi un parametro &_=ts ant cache) oppure imposta Cache-Control: no-cache lato tuo.

Errori

StatoCodiceQuando
401authentication_errorChiave Bearer mancante, non valida o revocata.
400invalid_request_errorFormato di start_date/end_date non valido, data finale precedente a quella iniziale, start_date successivo a oggi, intervallo superiore al limite o valore group_by non supportato.
500internal_errorDatabase non raggiungibile o errore imprevisto.

Avvertenze

  • Chiavi eliminate. Quando revochi una chiave API, alle relative righe storiche di utilizzo viene rimosso il campo api_key_id (impostato su null), quindi non è più possibile recuperare i totali storici tramite questo endpoint. I dati sono ancora disponibili nella vista aggregata dell’account nella dashboard. Se ti serve uno storico di audit per chiave non modificabile, recupera e salva i dati prima di revocarla.
  • Quasi in tempo reale. Le righe vengono aggiunte entro pochi secondi dal completamento della chiamata sottostante. Non è garantito alcun limite di ritardo: se ti serve una corrispondenza esatta con la fattura, richiedi una volta al giorno i dati del giorno precedente invece di interrogarli ogni minuto.
  • Il costo è quello fatturato. Il valore cost_usd qui corrisponde all’importo addebitato sul saldo del portafoglio. Include già il minimo max(catalog, upstream × markup) descritto in Fatturazione. Questa risposta non contiene un importo «all’ingrosso» separato.

Prossimi passi