Riferimento dell'API AI
Tutti gli endpoint su api.nodion.ai/v1, con limiti ed errori.
URL di base: https://api.nodion.ai/v1. L'API segue il formato OpenAI, quindi gli SDK di OpenAI funzionano
se li configuri con questo URL di base. Per chiavi, credito prepagato e schede della dashboard vedi
AI Inference. Modelli, provider e prezzi sono nel catalogo dei modelli.
pythonimport os
from openai import OpenAI
client = OpenAI(
base_url="https://api.nodion.ai/v1",
api_key=os.environ["NODION_AI_KEY"],
)
reply = client.chat.completions.create(
model="<model>",
messages=[{"role": "user", "content": "Hello"}],
)
print(reply.choices[0].message.content) Autenticazione
Invia una chiave di inferenza (nodion_ai_…) come bearer token in ogni richiesta. Le chiavi della piattaforma
(nodion_…) qui non funzionano. GET /v1/models è l'unica chiamata che non richiede una chiave.
httpAuthorization: Bearer nodion_ai_… Se la chiave viene rifiutata, la risposta è 401 con uno di questi messaggi:
missing bearer tokeninvalid api keyapi key expiredaccount disabledaccount under review
Ogni risposta contiene un header X-Request-ID. Indicalo quando contatti il supporto.
I body JSON delle richieste possono arrivare a 25 MiB (tool 1 MiB, System One 512 KiB). Base64 aggiunge un terzo, quindi un file inviato
inline nel JSON, come un'immagine, un PDF o un documento OCR, può pesare circa 18 MiB. Gli upload multipart verso
/v1/audio/transcriptions e /v1/audio/voices possono arrivare a 25 MiB, con
file di trascrizione fino a 20 MiB e file di campioni vocali fino a 10 MiB (11 MiB per l'intero
form).
Endpoint
| Endpoint | Cosa fa | Addebito per |
|---|---|---|
GET /v1/models | Elenca i modelli con prezzo a token | Gratis |
POST /v1/chat/completions | Chat, tool, output strutturato | Token di input e di output |
POST /v1/responses | OpenAI Responses API, ad esempio per Codex | Token di input e di output |
POST /v1/embeddings | Embedding vettoriali | Token di input |
POST /v1/rerank | Ordina documenti in base a una query | Token di input |
POST /v1/systemone | System One: decisioni tipizzate con probabilità | Token di input |
POST /v1/ocr | OCR di documenti e immagini | Pagine |
POST /v1/audio/transcriptions | Da voce a testo | Secondi di audio |
GET /v1/audio/transcriptions/realtime (WebSocket) | Da voce a testo in tempo reale | Secondi di audio |
POST /v1/audio/speech | Da testo a voce | Caratteri |
GET, POST /v1/audio/voices | Elenca e crea voci clonate | Gratis |
GET, DELETE /v1/audio/voices/{id} | Legge o elimina una voce clonata | Gratis |
POST /v1/images/generations | Generazione di immagini | Immagini |
POST /v1/tools/web_search, web_news, web_fetch, web_images, web_videos, web_places, web_maps, web_shopping, web_lens | Tool web | Chiamate, più ogni pagina scaricata da un web_search |
Audio, immagini e tool sono descritti con esempi in AI Inference. Il resto è qui sotto.
Prima di ogni chiamata viene riservato sul credito l'importo massimo previsto per la richiesta. Il costo viene poi calcolato in base all'utilizzo riportato,
mai oltre l'importo riservato, e il resto viene liberato. Se una risposta andata a buon fine non riporta l'utilizzo, viene addebitato
l'intero importo riservato. Una sessione di trascrizione in tempo reale riserva il max_audio_seconds del modello (1.800 secondi
se il modello non lo imposta), quindi il credito deve coprire in anticipo una sessione intera.
Modelli
GET /v1/models restituisce {"object": "list", "data": [...]} ed elenca i modelli chat,
embeddings e rerank. I modelli OCR, vocali, di immagini e i tool non ci sono; il catalogo
pubblico su https://api.nodion.com/v2/public/ai/models elenca tutti i tipi. Campi utili per ogni modello:
id: il valore permodelnelle richieste.kind:chat,embeddingsorerank.context_lengthemax_output_lengthin token.pricing: USD per token come stringhe decimali.pricing_eurcontiene i prezzi in EUR.supported_sampling_parametersesupported_features(ad esempiotools,json_mode,structured_outputs,reasoning).reasoning_efforts: i valori direasoning_effortche questo modello accetta (ad esempionone,low,high). Vuoto quando i livelli non sono configurabili.is_ready:falsesignifica che al momento nessuna route è funzionante. Il modello resta in elenco.lifecycle:gaopreview.serving:hosted(i pesi girano su Nodion) orouted(inoltrato a un provider).supports_decisions: il modello risponde a System One.coding_plan: Codion può offrire questo modello chat. Sempretrueofalse. Non è il coding plan della fatturazione.free_until: presente durante il periodo gratuito di un modello servito solo da Nodion. In quel periodo i prezzi dei token risultano 0.
Chat completions
POST /v1/chat/completions accetta il body di OpenAI Chat Completions: model,
messages e i campi facoltativi che il modello elenca in supported_sampling_parameters
e supported_features, come tools o response_format.
Invia reasoning_effort solo quando reasoning_efforts non è vuoto, e solo con un valore di quella lista.
bashcurl https://api.nodion.ai/v1/chat/completions \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<model>",
"stream": true,
"max_tokens": 512,
"messages": [
{"role": "system", "content": "Answer in one sentence."},
{"role": "user", "content": "What is an embedding?"}
]
}' Cosa fa il gateway con la richiesta e la risposta:
- Senza
max_tokens(omax_completion_tokens) il gateway impostamax_tokensalmax_output_lengthdel modello. I valori più alti vengono ridotti a quel limite. - Con
"stream": truela risposta arriva come server-sent events (righedata: {...}, poidata: [DONE]). Il gateway impostastream_options.include_usage, quindi di norma l'ultimo chunk contiene l'utilizzo. Se la connessione upstream si interrompe a metà stream, un ultimo chunk contiene un oggettoerrorefinish_reason: "error", seguito dadata: [DONE]. - Il campo
modelnella risposta è l'id che hai inviato. Il testo di reasoning, quando un modello lo restituisce, si trova inreasoning_content.
Puoi inviare i PDF direttamente nella richiesta come blocchi di contenuto file con una data URI in base64. Il gateway converte le prime
20 pagine in immagini prima della chiamata, quindi serve solo con i modelli che accettano immagini in input. I riferimenti
file_id vengono rifiutati.
json{
"role": "user",
"content": [
{"type": "text", "text": "Summarize this contract."},
{"type": "file", "file": {"file_data": "data:application/pdf;base64,JVBERi0..."}}
]
}
Addebito: token di input e di output al prezzo del modello, input in cache al relativo prezzo dove la route
lo riporta. L'importo riservato conta ogni byte della richiesta come un token di input, più max_tokens. Per le richieste
con immagini o PDF la parte di input viene portata alla context length del modello, o ad almeno 128.000 token
se la richiesta supera il contesto. Durante la finestra gratuita di un modello
(free_until), le chat completions sulle route ospitate sono gratuite.
Responses API
POST /v1/responses accetta il body della OpenAI Responses API: model, input
(testo o una lista di item) e i campi facoltativi instructions, tools,
tool_choice, parallel_tool_calls, text.format, reasoning.effort,
max_output_tokens, max_tool_calls, temperature, top_p,
top_logprobs, include e stream. Il gateway
traduce la richiesta in una chat completion, quindi valgono anche qui le regole della sezione chat completions:
il limite di output, i reasoning_efforts consentiti, i PDF e l'addebito.
bashcurl https://api.nodion.ai/v1/responses \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<model>",
"instructions": "Answer in one sentence.",
"input": "What is an embedding?"
}'
Con "stream": true la risposta è lo stream di eventi della Responses API, come response.created,
response.output_text.delta e response.function_call_arguments.delta, che termina con
response.completed e il relativo usage. Se lo stream si interrompe, l'ultimo evento è
response.failed. Il testo di reasoning arriva in un item reasoning come reasoning_text.
Rimanda quell'item nelle richieste successive: il reasoning dall'ultimo messaggio dell'utente torna al modello,
quello più vecchio solo con reasoning.context: "all_turns".
Il gateway esegue web_search da solo, tramite la ricerca web di Nodion. Quando il
modello cerca, il gateway recupera i risultati, li passa al modello e lo richiama. La risposta contiene un
item web_search_call con la query e gli URL delle fonti, trasmesso in streaming con gli eventi
response.web_search_call.in_progress, searching e completed.
Addebito: ogni ricerca come una chiamata a /v1/tools/web_search, ogni passaggio del modello come una chat completion,
e usage è la somma di tutti i giri. Una Response conta una sola volta per il limite di richieste della chiave. Al massimo
max_tool_calls ricerche per Response (valore predefinito 10, massimo 20); max_output_tokens vale per
tutti i giri insieme. filters.allowed_domains, user_location (città, regione, paese) e
search_context_size (5, 10 o 20 risultati) vengono applicati. La ricerca restituisce solo risultati dell'indice di ricerca (titolo,
URL, snippet) e non apre pagine, nemmeno con external_web_access: true.
Le logprob sono disponibili in output_text con top_logprobs (fino a 20) o include: ["message.output_text.logprobs"],
se il modello le restituisce.
Con questa configurazione Codex CLI funziona con Nodion, ricerca web inclusa:
toml# ~/.codex/config.toml
model = "<model>"
model_provider = "nodion"
[model_providers.nodion]
name = "Nodion"
base_url = "https://api.nodion.ai/v1"
env_key = "NODION_AI_KEY"
wire_api = "responses" Cosa cambia rispetto a OpenAI:
- Nodion non salva le risposte.
storeviene ignorato e la risposta riportastore: false. Non esistonoprevious_response_id,conversation,item_referencenéGET /v1/responses/{id}. Invia l'intera conversazione ininput, come fa Codex. - Tool:
function,custom,namespaceeweb_search. Gli altri tool ospitati, comefile_searchocode_interpreter, vengono rifiutati con 400. - I risultati della ricerca non vengono salvati. Un
web_search_callnella conversazione arriva al modello come chiamata con una nota, non con i vecchi risultati.annotations(citazioni) resta vuoto; le fonti sono nelweb_search_call. - Immagini e file negli output dei tool non arrivano al modello; al loro posto c'è una nota nel testo.
- Non supportati (400):
background,prompt,truncation: "auto",file_idefile_url. Invia le immagini comeimage_url(un URL o una data URI) e i PDF comeinput_fileconfile_data.
Embeddings
POST /v1/embeddings accetta il body di OpenAI (model, input come stringa o
array) e restituisce una risposta per gli embeddings nel formato OpenAI. Niente streaming. Addebito su usage.prompt_tokens.
Usa un modello con kind: "embeddings".
bashcurl https://api.nodion.ai/v1/embeddings \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "<embeddings-model>", "input": ["first text", "second text"]}' Rerank
POST /v1/rerank assegna un punteggio ai documents rispetto a una query. Il parametro facoltativo
top_n limita i risultati. La risposta contiene results con index (posizione
in documents) e relevance_score, più usage.prompt_tokens, su cui si basa
l'addebito. Usa un modello con kind: "rerank".
bashcurl https://api.nodion.ai/v1/rerank \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "<rerank-model>",
"query": "How do I reset my password?",
"documents": ["Billing FAQ", "Account recovery guide", "Release notes"],
"top_n": 2
}' System One
POST /v1/systemone risponde a domande tipizzate su un insieme di dati (lo stato). Il modello assegna un punteggio a ogni
risposta possibile invece di scrivere testo, quindi ricevi probabilità, non prosa. Usalo per routing,
triage, moderazione o come controllo prima che un agente esegua un tool. Una chiamata risponde fino a 16 domande sullo
stesso stato.
System One è disponibile per i modelli con supports_decisions: true su /v1/models. Gira su
route ospitate da Nodion e presso i provider che offrono System One direttamente. Se una route fallisce prima di aver eseguito la
richiesta (rate limit, disservizio), la stessa richiesta passa alla route successiva. La scheda Decisions nel
Playground contiene esempi pronti.
bashcurl https://api.nodion.ai/v1/systemone \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "aleph-alpha/kolibri-1",
"state": {
"customer_tier": "enterprise",
"ticket": "My checkout page shows a blank screen after I click Pay."
},
"questions": {
"is_bug": {
"type": "noul",
"instructions": "Is the customer reporting a software defect?"
},
"team": {
"type": "choice",
"instructions": "Which team should own this ticket?",
"criteria": {
"payments": "Checkout, billing, or payment processing issues.",
"frontend": "Rendering, layout, or browser issues.",
"account": "Login, permissions, or profile issues."
}
},
"urgency": {
"type": "score",
"instructions": "How urgent is this ticket?",
"criteria": [
"Can wait for the next release",
"Should be fixed this week",
"Blocking revenue right now"
]
}
}
}' Richiesta
model(obbligatorio): un modello consupports_decisions.state(obbligatorio): ciò su cui vertono le domande. Una stringa, un oggetto, un array onull.questions(obbligatorio): un oggetto con da 1 a 16 voci. La chiave è il nome che dai alla domanda (fino a 128 caratteri) e torna come chiave inanswers.
Ogni domanda ha un type, delle instructions facoltative e dei criteria che
dipendono dal tipo. I valori di instructions e criteria possono essere una stringa, un oggetto o un array;
null è ammesso ovunque tranne che nei livelli di score.
noul: una domanda sì/no.criteriaè facoltativo e può avere solo le chiavitrueefalse. Unnoulrichiedeinstructionsnon vuote o almeno un criterio non vuoto.choice: scegli un'etichetta.criteriaassocia da 1 a 26 etichette a un valore; le stringhe vuote vengono rifiutate. Le etichette devono essere univoche, senza distinzione tra maiuscole e minuscole, e lunghe al massimo 256 caratteri.score: valuta su una scala.criteriaè un array da 2 a 10 livelli non vuoti, dal più basso al più alto. Gli indici dei livelli partono da 0.
I campi sconosciuti vengono rifiutati. Il body può arrivare a 512 KiB, e lo stato più la domanda più grande devono rientrare nel contesto del modello.
Risposta
json{
"model": "aleph-alpha/kolibri-1",
"answers": {
"is_bug": {"type": "noul", "noul": 0.91},
"team": {
"type": "choice",
"choice": "payments",
"confidence": 0.78,
"probabilities": {"payments": 0.82, "frontend": 0.15, "account": 0.03}
},
"urgency": {
"type": "score",
"score": 1.5,
"confidence": 0.6,
"legend": {
"0": "Can wait for the next release",
"1": "Should be fixed this week",
"2": "Blocking revenue right now"
},
"probabilities": {"0": 0.1, "1": 0.3, "2": 0.6}
}
},
"usage": {"input_tokens": 412, "output_tokens": 0}
} noul: la probabilità che la risposta siatrue, da 0 a 1.choice:choiceè l'etichetta più probabile,probabilitiescontiene ogni etichetta e somma a 1, econfidenceè un valore da 0 a 1.score:scoreè la media degli indici dei livelli ponderata per probabilità (da 0 al numero di livelli meno 1).probabilitieselegendhanno come chiave l'indice del livello;legendassocia ogni indice alla descrizione di un livello.confidenceè un valore da 0 a 1.modelè il modello che ha risposto.usage.output_tokensè sempre 0.
I valori nella risposta di esempio sono illustrativi.
Addebito
Vengono addebitati solo i token di input, al prezzo di input del modello. Il modello legge lo stato una volta per ogni domanda, quindi
usage.input_tokens cresce con il numero di domande. Prima della chiamata viene riservato sul credito
(byte dello stato + byte di tutte le domande + 4.096) × il numero di domande come token di input,
e la richiesta viene addebitata su usage.input_tokens, mai oltre l'importo riservato. Le richieste che falliscono non vengono
addebitate; se ti disconnetti dopo che il modello ha risposto, i suoi token di input vengono addebitati. Le finestre gratuite valgono
come per la chat.
Errori
System One usa un proprio body di errore: {"detail": "message"} e, per il 422, una lista di
item loc / msg / type che indicano il campo.
json{
"detail": [
{"loc": ["body", "questions", "team", "criteria"], "msg": "choice accepts 1 to 26 criteria", "type": "too_long"}
]
} - 401: chiave mancante o non valida.
- 402: la fatturazione ha rifiutato la richiesta per saldo, limiti di spesa, o perché non è stato possibile calcolare il prezzo della richiesta. I motivi sono quelli dei codici 402, qui solo come testo in
detail. - 404:
model not found, anche per i modelli senzasupports_decisions. - 422: body non valido, body oltre 512 KiB, stato e domande oltre il contesto, oppure il modello ha rifiutato la richiesta.
- 429: è stato raggiunto un limite della chiave (
Retry-After: 5), oppure tutte le route dei provider tentate hanno raggiunto il rate limit (Retry-Afterdel provider, al massimo 60 secondi). - 502: il modello non è riuscito a rispondere.
- 503: nessuna route funzionante, nessuna compatibile con le impostazioni privacy del progetto, oppure non è stato possibile caricare le impostazioni.
- 529: tutte le route del modello sono al limite di capacità.
Retry-After: 5.
OCR
POST /v1/ocr segue il formato Mistral OCR. Invia il file inline come data URI in base64;
gli URL remoti vengono rifiutati. Sono supportati PDF, PNG, JPEG e WebP.
bashcurl https://api.nodion.ai/v1/ocr \
-H "Authorization: Bearer $NODION_AI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "mistral/mistral-ocr-4-1",
"document": {
"type": "document_url",
"document_url": "data:application/pdf;base64,JVBERi0..."
}
}' model: un modello OCR del catalogo pubblico (kind: "ocr").document:{"type": "document_url", "document_url": "data:..."}o{"type": "image_url", "image_url": "data:..."}.pages(facoltativo): gli indici delle pagine da leggere, a partire da 0. Non tutti i modelli OCR lo supportano; i modelli OCR ospitati efirecrawl/pdf-inspectorrestituiscono un errore 400.include_image_base64(facoltativo): restituisce le immagini incorporate in base64. Non tutti i modelli OCR restituiscono immagini; alcuni rispondono sempre con una listaimagesvuota.
La risposta contiene pages (ognuna con index, markdown e
images) e usage_info.pages_processed. Addebito per pagina elaborata. L'importo riservato copre
l'intero documento, e i documenti oltre il max_pages del modello vengono rifiutati.
firecrawl/pdf-inspector legge solo PDF generati digitalmente. Per un'immagine restituisce un errore 422; per un PDF con
pagine scansionate restituisce un errore 422 con code: "pages_need_ocr" e le pagine interessate in
pages_needing_ocr.
Errori e limiti
Tutti gli endpoint tranne System One restituiscono gli errori nell'envelope di OpenAI:
json{
"error": {
"message": "insufficient AI balance. Top up in the AI Billing tab.",
"type": "error",
"code": "empty_balance"
}
} message c'è sempre. type, e se code è impostato, variano da
endpoint a endpoint, quindi gestisci prima lo stato HTTP. Chat, embeddings, rerank e i tool web mettono i
codici 402 in code. Quando la route del modello risponde a chat, embeddings o
rerank con un errore HTTP, il body contiene anche request_id. L'header X-Request-ID
c'è sempre.
- 400: JSON non valido,
modelmancante o un modello del tipo sbagliato per l'endpoint (ad esempio un modello OCR su chat). Un body oltre 25 MiB che arriva al processo dell'API usarequest body exceeds 25 MiB. - 401: vedi Autenticazione.
- 402: la richiesta è stata rifiutata per un problema con il credito; vedi i codici qui sotto.
- 404:
model not found, oppure un endpoint che non esiste. - 413: l'host pubblico ha rifiutato un body più grande di 25 MiB prima che l'API venisse eseguita.
- 429: è stato raggiunto un limite della chiave, oppure il modello è sovraccarico. Rispetta
Retry-Afterquando viene inviato. - 502: la route del modello ha restituito un errore. Riprova più tardi.
- 503: nessuna route funzionante per il modello, nessuna compatibile con le impostazioni privacy del progetto (scheda Settings), oppure non è stato possibile caricare le impostazioni.
Codici 402. Chat, embeddings, rerank e i tool web li inviano in code. OCR, audio e immagini
inviano solo il messaggio, System One lo invia come detail.
empty_balance: il saldo AI disponibile non copre l'importo da riservare per questa richiesta. Ricarica nella scheda Billing o attiva la ricarica automatica.daily_quota: la spesa di oggi su questa chiave, più i suoi importi riservati aperti, più questa richiesta supererebbe il limite di spesa giornaliero della chiave.month_quota: la spesa di questo mese, più gli importi riservati aperti, più questa richiesta supererebbe il limite di spesa mensile che hai impostato nella scheda Billing.usage_limit: la spesa di questo mese, più gli importi riservati aperti, più questa richiesta supererebbe il tetto mensile del tuo livello di utilizzo. La scheda Billing mostra il livello e quando si applica il successivo.pricing_unavailableereserve_failed: non è stato possibile calcolare il prezzo della richiesta o riservare l'importo. Riprova, poi contatta il supporto indicando l'id della richiesta.
Limiti predefiniti per chiave:
- 600 richieste al minuto
- 4.000.000 di token al minuto (chat, embeddings, rerank e System One)
- 20 richieste simultanee
- 25 MiB di body della richiesta per chat, embeddings, rerank, OCR, audio e immagini. Per i tool è 1 MiB. Per System One è 512 KiB.
Per chat, embeddings e rerank, una risposta 429 include Retry-After: 5 per la frequenza delle richieste e per il
sovraccarico, 10 per la frequenza dei token e 2 per la concorrenza. System One invia sempre
Retry-After: 5. La creazione di una voce invia Retry-After quando scattano i suoi limiti (troppi
upload in corso, o più di dieci tentativi di creazione all'ora). Gli altri 429 su OCR, audio, immagini, tool web e
voci non lo inviano; aspetta qualche secondo prima di riprovare. Contatta il supporto se ti servono limiti più alti.