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#

JSON
{
  "error": {
    "code": "NOTFOUND",
    "message": "Entry not found",
    "requestId": "0f6c1d2e-3b4a-4c5d-8e9f-a0b1c2d3e4f5"
  }
}
Câmp
codeUn cod care poate fi procesat automat (mai jos).
messageO 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.
detailsPrezent atunci când mai sunt lucruri de spus: probleme pe câmpuri sau lista mesajelor de validare.
requestIdIdentifică 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.

curl
# 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#

StatusSemnificațieReîncercare?
200, 201Succes. Scrierile răspund cu 201.
303Un formular HTML simplu a fost acceptat; urmați redirecționarea.
304Nemodificat: ETag-ul dumneavoastră din If-None-Match este actual.
400Ceva din cerere este greșit: un parametru, un filtru, corpul, un captcha, un interval deja rezervat.Nu, corectați cererea.
401Cheia API lipsește, este necunoscută sau a fost revocată.Nu.
403Cheia nu are voie să facă acest lucru (status=draft cu o cheie ck_pub_) sau originea nu are voie să trimită acest formular.Nu.
404Nu există o astfel de colecție, înregistrare, formular sau spațiu de lucru, ori GraphQL este dezactivat pentru spațiul de lucru.Nu.
413Corpul cererii este prea mare.Nu.
429A fost atinsă o limită de rată.Da, mai târziu.
500Eroare din partea noastră. Mesajul este generic; requestId duce la detalii.Da, cu backoff.
503Indisponibil 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.

codeStatusUnde
BADREQUEST400Orice 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.
UNAUTHORIZED401Conținut și GraphQL: nicio cheie sau o cheie invalidă ori revocată.
FORBIDDEN403Ciorne solicitate cu o cheie ck_pub_.
NOTFOUND404Colecție sau înregistrare necunoscută, slug de spațiu de lucru necunoscut.
VALIDATION_FAILED400Formulare: câmpurile nu respectă regulile formularului; details este [{ field, message }].
ORIGIN_NOT_ALLOWED403Formulare: Origin nu se află printre site-urile permise ale formularului.
FORM_UNAVAILABLE404Formulare: formularul nu este activ sau modulul Formulare este dezactivat.
RATE_LIMITED429Formulare: a fost depășită limita orară a formularului per IP sau per formular.
FORMS_PAUSED503Formulare: trimiterile sunt suspendate temporar la nivelul întregii platforme.
ENTITY_TOO_LARGE413Corpul depășește limita de dimensiune.
INTERNAL_SERVER_ERROR500O eroare neașteptată. Reîncercați mai târziu și comunicați requestId echipei de suport.
TOO_MANY_REQUESTS429A 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:

JSON
{
  "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ă:

JSON
{
  "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ă#

CeLimităNumărată per
API de conținut și GraphQLImplicit 300 de cereri pe minutCheie API, în ferestre fixe de un minut. REST și GraphQL o împart.
Trimitere contact, rezervare, trimitere formularImplicit 10 pe minut și 60 pe orăAdresa IP a vizitatorului, pentru fiecare endpoint.
Trimiteri de formulareImplicit 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) sau Retry-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.

TypeScript 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.