Che cosa avvolge davvero un SDK client
L’API di Claude è un’API REST su https://api.anthropic.com, e la superficie che userai quasi sempre è una sola: POST /v1/messages. Ogni richiesta porta x-api-key (oppure Authorization con un token ottenuto via Workload Identity Federation), anthropic-version e content-type. Se usi un SDK ufficiale questi header li manda lui.
Gli SDK client sono sette — Python, TypeScript, C#, Go, Java, PHP e Ruby — più la CLI ant. Quello che aggiungono sopra una chiamata curl è esattamente ciò che altrimenti dovresti riscrivere a mano: header automatici, tipi per richieste e risposte, retry con backoff, streaming, timeout e gestione della connessione, iteratori che seguono da soli la paginazione.
Una distinzione da fissare subito, perché la parola «SDK» copre due livelli molto diversi. I client SDK sono client della Messages API: sei tu a mandare ogni richiesta e a gestire ogni risposta. Claude Code, il Claude Agent SDK e i Claude Managed Agents stanno un livello sopra e forniscono loro il loop dell’agente, l’esecuzione dei tool e il runtime. E c’è un dettaglio che fa perdere tempo a chiunque cerchi la documentazione: quella di Claude Code e del Claude Agent SDK non sta su platform.claude.com, sta su code.claude.com.
Il terzo fatto strutturale è che l’API non tiene stato: «The Messages API is stateless, which means that you always send the full conversational history to the API.» Non esiste un identificativo di conversazione da riprendere. La cronologia la conservi tu e la rimandi intera a ogni turno: da qui discendono i costi, il caching e la gestione della finestra di contesto.
Websocket è il termine della Exam Guide, nella documentazione c’è SSE
La skill ufficiale nomina i websocket fra le pratiche ingegneristiche di base. Vale la pena dirlo per quello che è: nelle pagine Anthropic il trasporto dello streaming non è un websocket, sono i server-sent events. Imposti stream a vero e ricevi eventi HTTP con nome, in questo ordine:
message_start
content_block_start -> content_block_delta ... -> content_block_stop (per ogni blocco)
message_delta
message_stop
In mezzo possono arrivare eventi ping. E qui c’è il punto che rompe le integrazioni ingenue: un errore può arrivare dopo che l’HTTP ha già risposto 200. Nei momenti di carico ricevi un overloaded_error dentro lo stream, dove una chiamata non-streaming avrebbe dato un 529. Il tuo handler deve quindi gestire gli errori in due posti, non in uno. La policy di versioning avverte inoltre che nuovi tipi di evento possono essere aggiunti: ignora con grazia quelli che non conosci invece di sollevare eccezioni.
Anche il canale eventi delle sessioni dei Managed Agents è SSE: si legge in GET con accept: text/event-stream, e per riconnetterti rileggi la history e scarti gli eventi con id già visti. Se nella tua architettura c’è un websocket, sta fra il tuo backend e il tuo front end; verso Anthropic resta una risposta HTTP.
Errore tipico da evitare: leggere la risposta per posizione, con content[0].text, o assumere che il primo content_block_start sia testo. Con il thinking attivo arrivano prima i blocchi thinking. Seleziona i blocchi per il loro campo type.
Errori, retry e richieste lunghe
Gli errori sono JSON con un oggetto error che ha sempre type e message, più un request_id. La tassonomia da conoscere:
400 invalid_request_error 401 authentication_error 403 permission_error
404 not_found_error 413 request_too_large 429 rate_limit_error
500 api_error 504 timeout_error 529 overloaded_error
Gli SDK sollevano eccezioni tipizzate al posto del JSON grezzo: cattura le classi, dalla più specifica alla più generica, invece di fare match sulle stringhe dei messaggi. Sui retry: «Certain errors are automatically retried 2 times by default, with a short exponential backoff.» Sono riprovati errori di connessione, 408, 409, 429 e 5xx, rispettando l’header retry-after; il numero si configura per client o per richiesta, anche a zero se il retry lo vuoi gestire tu.
Il timeout predefinito è di 10 minuti, e gli SDK rifiutano in partenza una richiesta non-streaming che si stima duri di più; impostano anche il keep-alive TCP. Per lavori lunghi la documentazione indica due strade, streaming o Message Batches: le reti lasciano cadere le connessioni inattive, e con i batch fai polling invece di tenere aperta una connessione. Ultima abitudine che ripaga: logga sempre il request-id della risposta, è l’unico appiglio quando apri un ticket.
Versioning e dove gira il tuo codice
L’header anthropic-version: 2023-06-01 è obbligatorio. Per una data versione Anthropic preserva i parametri di input e di output esistenti, ma può aggiungere input opzionali, nuovi valori in output, nuove varianti nei valori enumerati e cambiare le condizioni di certi tipi di errore. Traduzione pratica: il tuo parser deve ignorare i campi che non conosce, non fallire su di essi.
Infine, dove gira il client. L’SDK TypeScript supporta Node, Deno, Bun, Cloudflare Workers e il Vercel Edge Runtime, mentre nel browser è disabilitato di default proprio per non esporre la chiave; si sblocca con dangerouslyAllowBrowser, e il nome dell’opzione è già tutta la documentazione che serve. La chiave sta sul tuo server, sempre. Se invece il carico vive già su un cloud, gli stessi pacchetti offrono client dedicati per Amazon Bedrock, Google Cloud, Microsoft Foundry e Claude Platform on AWS: cambia il client e l’autenticazione, la forma dei messaggi resta quella.