Errori
Schema standard delle risposte di errore dell'API REST e codici HTTP usati.
Tutte le risposte di errore dell'API REST seguono lo stesso schema:
{
"error": {
"code": "<codice machine-readable>",
"message": "Messaggio human-readable in italiano"
}
}
In alcuni casi (es. 409 conflict su POST /contacts con email duplicata) il payload include campi extra come existing.
Codici HTTP usati
| Status | Quando | Codice errore tipico |
|---|---|---|
200 | Successo (read, update) | — |
201 | Creato (POST) | — |
400 | Body o query parameter malformati | invalid_body |
401 | Autenticazione assente o non valida | missing_authorization, invalid_key_format, invalid_key |
403 | Autenticato ma scope insufficiente | insufficient_scope |
404 | Risorsa non trovata o non del tenant della chiave | not_found |
409 | Conflitto (es. email già esistente) | conflict |
429 | Rate limit superato (60 req/min) | rate_limit_exceeded |
500 | Errore interno SmartCQ | internal |
Codici specifici
missing_authorization
{ "error": { "code": "missing_authorization", "message": "Header `Authorization: Bearer scq_<key>` mancante." } }
Il client non ha incluso l'header Authorization.
invalid_key_format
{ "error": { "code": "invalid_key_format", "message": "Formato chiave non valido. Atteso `scq_<48hex>`." } }
L'header Authorization è presente ma il valore non è un token SmartCQ valido.
invalid_key
{ "error": { "code": "invalid_key", "message": "Chiave non valida o revocata." } }
La chiave esiste ma è stata revocata, oppure non esiste affatto. Stessa risposta in entrambi i casi (no leak).
insufficient_scope
{ "error": { "code": "insufficient_scope", "message": "Scope richiesti: contacts:write. Posseduti: contacts:read." } }
La chiave è valida ma non ha gli scope necessari per l'endpoint richiesto.
not_found
{ "error": { "code": "not_found", "message": "Contact non trovato" } }
Restituito sia quando la risorsa non esiste sia quando esiste ma appartiene a un tenant diverso da quello della chiave: in entrambi i casi 404 per non far trapelare informazioni cross-tenant.
conflict (solo POST /contacts)
{
"error": {
"code": "conflict",
"message": "Contatto già esistente con questa email",
"existing": { "id": "...", "status": "active" }
}
}
L'email è già nel tenant. Il campo existing.id ti permette di recuperare/modificare il contatto già presente invece di crearne uno nuovo.
rate_limit_exceeded
{ "error": { "code": "rate_limit_exceeded", "message": "Limite di 60 richieste/minuto raggiunto. Riprova fra 35s." } }
Headers: Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset.
unknown_tag (solo POST /contacts)
{ "error": { "code": "unknown_tag", "message": "Tag inesistenti: foo, bar. Crea i tag prima da UI o ometti il campo." } }
I tag passati nel body non esistono nel tenant. SmartCQ non crea i tag on-demand via API per evitare proliferazione di tag duplicati con typo.