Referință
Erori și limite de rată
Fiecare eroare REST are același corp scurt. Tratați mai întâi statusul HTTP, apoi code, și menționați requestId atunci când ne cereți ajutorul.
Corpul erorii#
{
"error": {
"code": "NOTFOUND",
"message": "Entry not found",
"requestId": "0f6c1d2e-3b4a-4c5d-8e9f-a0b1c2d3e4f5"
}
}| Câmp | |
|---|---|
code | Un cod care poate fi procesat automat (mai jos). |
message | O explicație pentru oameni, de obicei în engleză; unele mesaje de rezervare sunt în bulgară, așa cum le văd vizitatorii. La validarea corpului cererii este o listă de mesaje. |
details | Prezent atunci când mai sunt lucruri de spus: probleme pe câmpuri sau lista mesajelor de validare. |
requestId | Identifică cererea în jurnalele Citron. |
GraphQL raportează erorile de interogare în propriul tablou errors; consultați erorile GraphQL.
Identificatori de cerere#
Fiecare eroare conține requestId, la fel ca meta.requestId în răspunsurile reușite pentru contact și rezervări. Trimiteți propriul antet X-Request-Id și API-ul îl va folosi, astfel încât să puteți corela jurnalele dumneavoastră cu ale noastre. Includeți-l ori de câte ori contactați suportul.
# Send your own id and it comes back as requestId (and in the API's logs)
curl https://api.console.citronos.com/v1/content/nope \
-H "Authorization: Bearer $CITRON_API_KEY" \
-H "X-Request-Id: my-site-7f3a"
# {"error":{"code":"NOTFOUND","message":"Collection \"nope\" not found","requestId":"my-site-7f3a"}}Coduri de status#
| Status | Semnificație | Reîncercare? |
|---|---|---|
200, 201 | Succes. Scrierile răspund cu 201. | |
303 | Un formular HTML simplu a fost acceptat; urmați redirecționarea. | |
304 | Nemodificat: ETag-ul dumneavoastră din If-None-Match este actual. | |
400 | Ceva din cerere este greșit: un parametru, un filtru, corpul, un captcha, un interval deja rezervat. | Nu, corectați cererea. |
401 | Cheia API lipsește, este necunoscută sau a fost revocată. | Nu. |
403 | Cheia nu are voie să facă acest lucru (status=draft cu o cheie ck_pub_) sau originea nu are voie să trimită acest formular. | Nu. |
404 | Nu există o astfel de colecție, înregistrare, formular sau spațiu de lucru, ori GraphQL este dezactivat pentru spațiul de lucru. | Nu. |
413 | Corpul cererii este prea mare. | Nu. |
429 | A fost atinsă o limită de rată. | Da, mai târziu. |
500 | Eroare din partea noastră. Mesajul este generic; requestId duce la detalii. | Da, cu backoff. |
503 | Indisponibil temporar, de exemplu trimiterile de formulare sunt suspendate. | Da, mai târziu. |
Coduri de eroare#
Majoritatea erorilor folosesc un cod generic derivat din status. Câteva endpoint-uri adaugă unul specific. Comparați codurile exact așa cum sunt scrise: cele generice nu au caracter de subliniere.
code | Status | Unde |
|---|---|---|
BADREQUEST | 400 | Orice cerere greșită: un câmp sau operator de filtru necunoscut, o limbă necunoscută, o valoare richtext incorectă, mai mult de 10 filtre, un captcha respins, un corp care nu trece validarea, un interval tocmai ocupat. |
UNAUTHORIZED | 401 | Conținut și GraphQL: nicio cheie sau o cheie invalidă ori revocată. |
FORBIDDEN | 403 | Ciorne solicitate cu o cheie ck_pub_. |
NOTFOUND | 404 | Colecție sau înregistrare necunoscută, slug de spațiu de lucru necunoscut. |
VALIDATION_FAILED | 400 | Formulare: câmpurile nu respectă regulile formularului; details este [{ field, message }]. |
ORIGIN_NOT_ALLOWED | 403 | Formulare: Origin nu se află printre site-urile permise ale formularului. |
FORM_UNAVAILABLE | 404 | Formulare: formularul nu este activ sau modulul Formulare este dezactivat. |
RATE_LIMITED | 429 | Formulare: a fost depășită limita orară a formularului per IP sau per formular. |
FORMS_PAUSED | 503 | Formulare: trimiterile sunt suspendate temporar la nivelul întregii platforme. |
ENTITY_TOO_LARGE | 413 | Corpul depășește limita de dimensiune. |
INTERNAL_SERVER_ERROR | 500 | O eroare neașteptată. Reîncercați mai târziu și comunicați requestId echipei de suport. |
TOO_MANY_REQUESTS | 429 | A fost atinsă o limită de rată per cheie sau per IP. Așteptați și reîncercați. (Versiunile anterioare datei de 24 septembrie 2026 trimiteau INTERNAL_SERVER_ERROR cu statusul 429, așa că tratarea după status funcționează peste tot.) |
Erori de validare#
Formularele explică fiecare câmp:
{
"error": {
"code": "VALIDATION_FAILED",
"message": "Please check the highlighted fields",
"details": [{ "field": "email", "message": "Enter a valid email" }],
"requestId": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f"
}
}Endpoint-urile de contact și rezervări validează strict corpul JSON și enumeră fiecare problemă, inclusiv câmpurile pe care nu le acceptă:
{
"error": {
"code": "BADREQUEST",
"message": ["mode must be one of the following values: online, in_office"],
"details": ["mode must be one of the following values: online, in_office"],
"requestId": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b"
}
}Limite de rată#
| Ce | Limită | Numărată per |
|---|---|---|
| API de conținut și GraphQL | Implicit 300 de cereri pe minut | Cheie API, în ferestre fixe de un minut. REST și GraphQL o împart. |
| Trimitere contact, rezervare, trimitere formular | Implicit 10 pe minut și 60 pe oră | Adresa IP a vizitatorului, pentru fiecare endpoint. |
| Trimiteri de formulare | Implicit 30 per IP pe oră și 500 per formular pe oră | Se configurează pentru fiecare formular în consolă. |
- Peste limită, răspunsul este
429. Limitele per IP adaugăRetry-After-short(fereastra de un minut) sauRetry-After-long(fereastra de o oră) cu numărul de secunde de așteptat. Limita per cheie se resetează la începutul minutului următor. - Serverul propriului site preia de obicei conținutul de pe un singur IP; API-ul de conținut este limitat per cheie, nu per IP, așa că randarea paginilor nu este niciodată încetinită de vizitatori.
- Dacă trimiterile trec prin serverul dumneavoastră, transmiteți mai departe
x-forwarded-for, astfel încât fiecare vizitator să aibă propriul buget. - Folosiți cache de partea dumneavoastră (ETag-uri, revalidare Next.js, webhook-uri) în loc să preluați conținutul la fiecare afișare a paginii.
În SDK#
SDK-ul transformă fiecare corp de eroare într-un CitronError și reîncearcă automat la 429 și 5xx. Consultați erorile în SDK.
import { CitronGraphQLError, isCitronError } from '@citron/sdk';
try {
await citron.collection('products').get('does-not-exist');
} catch (err) {
if (err instanceof CitronGraphQLError) {
console.error(err.errors, err.data); // GraphQL errors and partial data
} else if (isCitronError(err)) {
console.error(err.status, err.code, err.message, err.requestId, err.details);
if (err.isNotFound) { /* render your 404 */ }
if (err.isRetryable) { /* 0, 408, 429 or 5xx; err.retryAfter when the server said */ }
} else {
throw err;
}
}Această referință acoperă doar API-ul public și respectă contractul de compatibilitate al API-ului: răspunsurile publice pot doar să primească câmpuri noi. Descrierea OpenAPI a acestor rute se află la /developers/openapi.json.