Convenzioni
Convenzioni
Le regole valide su ogni endpoint, enunciate una volta qui invece di essere ripetute venticinque volte.
Idempotenza
Gli endpoint che modificano qualcosa accettano un'intestazione Idempotency-Key. Ripetere una richiesta con la stessa chiave riproduce la risposta originale invece di ripetere l'effetto, perciò un nuovo tentativo dopo un timeout non può creare un secondo passaporto. Le chiavi appartengono a una sola organizzazione, così due clienti non collidono mai sullo stesso valore. Prova e produzione restano separate: una chiave già usata in un modo viene rifiutata nell'altro anziché riprodotta. Un'eccezione, che è una capacità e non un fatto: l'URL di caricamento firmato restituito da `POST /documents` viene riemesso alla ripetizione finché il file non è arrivato, e omesso una volta arrivato — riprodurre un URL scaduto non restituirebbe nulla di utilizzabile.
Una chiave resta in memoria per 30 giorni. Dopo viene dimenticata del tutto, e un nuovo tentativo che la porta viene eseguito di nuovo invece di essere riprodotto: un processo di riconciliazione che potrebbe partire più tardi dovrebbe quindi generare una chiave nuova.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports" \
-X POST \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"category":"textile"}'Impaginazione
Le raccolte si impaginano a cursore, mai a scostamento. Uno scostamento è sbagliato in presenza di scritture concorrenti: un record inserito fra due pagine sposta tutti quelli successivi, e un client salta o duplica righe senza accorgersene.
Rimandi next_cursor come cursor per ottenere la pagina successiva. Un cursore codifica i filtri con cui è stato emesso, perciò inviarlo con filtri diversi viene rifiutato invece di restituire una pagina che in silenzio significherebbe altro.
{
"object": "list",
"data": [],
"has_more": true,
"next_cursor": "eyJjIjoiMjAyNi0wOC0wMVQxNDowMzoyMi41MDFaIn0"
}Scritture condizionali
La lettura di un passaporto restituisce un ETag con la sua versione. Lo rimandi come If-Match su un PATCH e la scrittura verrà rifiutata se nel frattempo il passaporto è cambiato: è l’unico modo per rendere sicura una sequenza leggi-modifica-scrivi di fronte a un editor concorrente.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
-X PATCH \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "If-Match: \"4\"" \
-H "Content-Type: application/json" \
-d '{"data":{"recycled_content_percentage":38}}'Limiti di frequenza
Su ogni richiesta autenticata girano tre contatori insieme e decide il più stretto. I valori pubblicati sono punti di partenza deliberatamente prudenti, non soglie ottimizzate.
| Contatore | Richieste | Finestra |
|---|---|---|
| key_org | 1000 | 60s |
| organization | 3000 | 60s |
| credential | 10000 | 60s |
| destructive | 50 | 3600s |
Ogni risposta contabilizzata porta le intestazioni RateLimit e RateLimit-Policy, che nominano il contatore arrivato più vicino al proprio limite. Un rifiuto aggiunge Retry-After: attenda quel tempo invece di tirare a indovinare.
Una richiesta che arriva senza una chiave utilizzabile viene misurata da un contatore a sé, molto più stretto: 60 richieste al minuto per indirizzo client. Non si applica mai a una chiave valida.
Dimensione della richiesta
Un corpo che supera il tetto del proprio endpoint viene rifiutato con payload_too_large prima che qualcosa venga letto verso il database. Il tetto è controllato due volte: prima sul Content-Length dichiarato, che non costa nulla, poi sui byte che arrivano davvero, così anche una richiesta che non dichiara alcuna lunghezza resta limitata.
| Endpoint | Tetto |
|---|---|
| Ogni endpoint che scrive un singolo record | 256 KiB (262144 bytes) |
| Importazione massiva e lotti di unità | 4 MiB (4194304 bytes) |
Il tetto dei lotti nasce dal lotto più grande che questa API accetta, non da una cifra tonda: 500 righe di importazione con ogni campo di una categoria compilato, oppure 1000 unità serializzate. Nessuno dei due entra nel tetto standard, ed è esattamente il motivo per cui quei due endpoint ne hanno uno proprio.
Il corpo deve arrivare come application/json; è accettato anche application/merge-patch+json. Qualsiasi altro tipo viene rifiutato con unsupported_media_type invece di fallire dentro il parser: il caso da conoscere è curl -d, che invia application/x-www-form-urlencoded se non gli si dice altro. Un corpo inviato senza alcun Content-Type viene letto come JSON.
Metodi HTTP
Un endpoint risponde solo ai metodi che documenta. Qualunque altro metodo viene rifiutato con method_not_allowed e un'intestazione Allow che nomina quelli che funzionano, così un client che sbaglia verbo impara quello giusto dal rifiuto stesso. HEAD funziona ovunque funzioni GET, e OPTIONS funziona ovunque.
HTTP/1.1 405 Method Not Allowed
Allow: GET, HEAD, PATCH, OPTIONS
Content-Type: application/json
{
"error": {
"code": "method_not_allowed",
"documentation_url": "https://passportcraft.com/docs/api/errors#method_not_allowed",
"request_id": "req_9Fv2KpQ0aXbT4Lmn",
"details": { "method": "DELETE", "allowed": ["GET", "HEAD", "PATCH", "OPTIONS"] }
}
}Operazioni distruttive
Ritirare un passaporto e spostarne uno nel cestino tolgono entrambi dal mercato un record pubblicato, perciò attingono a un tetto separato oltre al normale limite di frequenza. Un ciclo di richieste economiche e ben formate non deve poter spegnere un intero catalogo.
Allegare un documento a un campo
Alcuni campi di tipo url accettano un file caricato al posto di un collegamento: per esempio un rapporto di prova o una dichiarazione di conformità. Carichi prima il file, poi faccia puntare il campo al documento scrivendone l’identificativo nella chiave associata a quel campo, dentro `data`. Il campo può restare vuoto: un campo che accetta documenti risulta compilato non appena vi è allegato un documento, quindi un passaporto con l’url vuota resta validabile e pubblicabile.
Non deve mai comporre quella chiave a mano. Un campo che accetta documenti porta due attributi nello schema della categoria: `document_types`, che elenca i tipi ammessi, e `document_id_key`, che indica la chiave esatta da scrivere. Legga la chiave dallo schema invece di affidarsi alla regola di denominazione: è l’unico modo supportato. La chiave associata è una proprietà del campo e non un campo a sé, perciò non compare mai nell’elenco `fields` dello schema.
Una regola che lo schema non esplicita: l’`access_tier` del documento deve coincidere con quello del campo. Un documento pubblico non può soddisfare un campo di livello «authority»; l’associazione viene rifiutata con `access_tier_mismatch`, perché un documento con livello diverso da quello del campo non verrebbe mostrato dove il campo è mostrato. Crei il documento con l’`access_tier` indicato dal descrittore del campo.
curl "https://passportcraft.com/api/v1/organizations/{organization}/passports/{id}" \
-X PATCH \
-H "Authorization: Bearer $PASSPORTCRAFT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"data":{"conformity_declaration_url__document_id":"doc_123"}}'Svuoti la chiave associata per staccare il documento; il file resta nella sua libreria finché non lo elimina. Se elimina un documento a cui un campo punta ancora, la risposta indica che cosa è stato staccato, e tale segnalazione raggiunge soltanto il chiamante che ha effettuato la richiesta.
L'`upload_state` di un documento è `ready`, `pending` oppure `unknown`. `unknown` significa che non siamo riusciti a stabilire se i byte siano nell'archivio: o l'archivio non ha risposto, oppure la riga era oltre i 25 documenti privi di byte che una richiesta verifica. Lo consideri indeterminato, non assente: in pubblicazione `unknown` produce `storage_unavailable` invece di dichiarare mancante un file, e una lettura successiva di norma lo risolve.
Identificativi di richiesta
Ogni risposta porta un'intestazione Request-Id, tanto in caso di successo quanto di errore. Lo citi in una richiesta di assistenza e la chiamata esatta potrà essere ritrovata.
Il flusso degli eventi conserva 30 giorni di storico. Un'integrazione che interroga più di rado perderà dei cambiamenti e dovrebbe piuttosto riconciliarsi con l'elenco dei passaporti.