Aan de slag

Errors en rate limits

Elke error-envelope die de storefront-API teruggeeft, de vorm van de 422-validatiefout, rate limiting en de paginatie-envelope.

Bekijk als Markdown

De storefront-API signaleert fouten met conventionele HTTP-statuscodes en kleine JSON-bodies. Deze pagina catalogiseert elke error-envelope die de API produceert, legt de vorm van validatiefouten uit, documenteert de rate limit en definieert de paginatie-envelope die alle lijst-endpoints gebruiken. Endpoint-referentiepagina's linken hierheen in plaats van deze vormen te herhalen.

Alle error-bodies zijn JSON-objecten. De meeste dragen een message-veld; meerdere bijzondere gevallen wijken af en worden hieronder benoemd: de module-disabled-error gebruikt een error-key, en de suspensie-error, geweigerde cartregels, schendingen van het cart- en checkoutbeleid en sommige weigeringen op offertetokens voegen een machine-leesbare code toe.

401 Unauthenticated

Wordt teruggegeven wanneer de header Authorization: Bearer {api_key} ontbreekt, misvormd is of een ingetrokken key draagt. Wordt ook teruggegeven wanneer de header een ander schema dan Bearer gebruikt.

Response
{
  "message": "Unauthenticated."
}

Oplossing: stuur een geldige, niet-ingetrokken API-key als Authorization: Bearer {api_key}. Verifieer de key met GET /v1/api/me.

403 Forbidden

Drie verschillende condities geven 403 terug. Onderscheid ze aan de vorm van de body.

Tenant geschorst

De winkel waar de key bij hoort is door Borkol geschorst. Elke /v1/api-request faalt met deze body tot de schorsing wordt opgeheven. Het code-veld is stabiel; vertak op code === "tenant_suspended".

Response
{
  "message": "Tenant suspended.",
  "code": "tenant_suspended"
}

Ontbrekende scope

De key is geldig maar draagt niet de scope die het endpoint vereist (bijvoorbeeld het aanroepen van een commerce:write-endpoint met een key die alleen commerce:read heeft).

Response
{
  "message": "Invalid ability provided."
}

Oplossing: maak in het client-dashboard (Settings > API keys) een key aan met de vereiste scope. Scopes kunnen niet aan een bestaande key worden toegevoegd.

Module niet ingeschakeld

De route hoort bij een module die niet is ingeschakeld voor de winkel. Deze error gebruikt een error-key, geen message, en wint van de scope-check: hij wordt zelfs teruggegeven wanneer de key de scope van de module draagt. {key} is de module-key: catalog, commerce, configurator, sales, stock, objects of forms.

De body bevat ook code: "module_disabled" en module (alleen de module-key), zodat een client op code kan vertakken in plaats van error te parsen. error blijft ongewijzigd.

Eén route antwoordt deze body met status 404 in plaats van 403: POST /v1/api/commerce/carts/{id}/quote-request zonder de sales-module geeft 404 {"error":"Module not enabled: sales"}, dezelfde status als offerteaanvragen die in de winkelinstellingen zijn uitgeschakeld, zodat een storefront één "niet beschikbaar"-geval hoeft af te handelen.

Response
{
  "error": "Module not enabled: commerce",
  "code": "module_disabled",
  "module": "commerce"
}

Oplossing: module-inschakeling wordt per winkel door Borkol beheerd; neem contact op met Borkol om de module in te schakelen.

404 Not Found

Wordt teruggegeven voor onbekende routes en voor padparameters die niet naar een bestaand record binnen de winkel verwijzen. De body is {"message": "..."}; bij een mislukte model-lookup is het bericht de standaard van Laravel, bijvoorbeeld:

Response
{
  "message": "No query results for model [Borkol\\Catalog\\Models\\Product] 9c4e7f0a-2b31-4d6e-8f0a-1d2c3b4a5e6f"
}

Records die bij een andere winkel horen zijn niet te onderscheiden van niet-bestaande records: beide geven 404 terug, nooit 403.

422 Validatiefout

Wordt teruggegeven wanneer een request body of queryparameter de validatie niet doorstaat. De vorm is altijd:

NaamTypeVerplichtBeschrijving
messagestringaltijdHet eerste validatiefoutbericht (een leesbare samenvatting).
errorsobjectaltijdMap van veldnaam naar een array van één of meer foutberichten voor dat veld. Geneste velden gebruiken puntnotatie (bijvoorbeeld lines.0.quantity).
Response
{
  "message": "The email field is required.",
  "errors": {
    "email": ["The email field is required."],
    "lines.0.quantity": ["The lines.0.quantity must be greater than zero."]
  }
}

De referentiepagina van elk endpoint vermeldt zijn velden met types, verplicht-vlaggen en validatieregels; de 422-body volgt altijd deze envelope.

Weigeringscode voor cartregels

Wanneer POST /v1/api/commerce/carts/{id}/lines een product weigert, voegt de 422-body een code op het hoogste niveau toe naast message en errors:

NaamTypeVerplichtBeschrijving
codestringconditioneelCAPABILITY_INACTIVE (de module die de capability van het product verkoopt is uitgeschakeld), INVALID_CONFIGURATION (variant of configuratie past niet bij het product) of NOT_PURCHASABLE (het product kan niet verkocht worden). Afwezig bij gewone invoervalidatiefouten.
Response
{
  "message": "Product is not available.",
  "errors": {
    "product_id": ["Product is not available."]
  },
  "code": "CAPABILITY_INACTIVE"
}

Behandel de code-enum als open. Het quote-endpoint van de configurator meldt configuratiefouten in de gewone envelope zonder code. Zie Cartregels.

429 Too Many Attempts (rate limiting)

Alle /v1/api-routes delen één rate limit van 120 requests per minuut per winkel. De limiet wordt bepaald per winkel (tenant), niet per API-key of IP: alle keys van één winkel putten uit hetzelfde budget. Ongeauthenticeerde requests naar rate-gelimiteerde routes worden per client-IP geteld. GET /v1/ping valt niet onder deze limiet.

Elke response op een rate-gelimiteerde route bevat:

HeaderBeschrijving
X-RateLimit-LimitHet budget per minuut (120).
X-RateLimit-RemainingResterende requests in het huidige venster.

Wanneer het budget op is, geeft de API HTTP 429 terug met een Retry-After-header (seconden tot het venster reset):

Response
{
  "message": "Too Many Attempts."
}

Clients horen X-RateLimit-Remaining in de gaten te houden, terug te schakelen voordat de teller nul raakt en Retry-After te respecteren bij een 429. Cache voor catalogus-zware storefronts de reads aan jouw kant in plaats van elke paginaweergave naar de API te proxyen.

Formulierinzendingen hebben daarnaast een eigen limiet: elk formulier accepteert een door de merchant ingesteld aantal inzendingen per bezoeker per uur. Daarboven antwoordt POST /v1/api/forms/{key}/submissions met 429 {"message": "Too many submissions. Try again later."}, zonder Retry-After-header. Zie Inzendingen. Bestandsuploads voor formulieren zijn beperkt tot 30 per formulier per bezoeker per uur: daarboven antwoordt POST /v1/api/forms/{key}/uploads met 429 {"message": "Too many uploads. Try again later."}, ook zonder Retry-After. Zie Uploads.

Paginatie-envelope

Elk lijst-endpoint in de storefront-API geeft dezelfde envelope terug: een data-array plus links- en meta-objecten. Dit is hier eenmalig gedocumenteerd; endpoint-pagina's beschrijven alleen de vorm van de objecten binnen data.

Lijst-endpoints accepteren deze queryparameters:

NaamTypeVerplichtBeschrijving
pageintegerNeePaginanummer, beginnend bij 1. Standaard 1.
per_pageintegerNeeItems per pagina. Elk endpoint documenteert zijn standaard en maximum (doorgaans standaard 25, maximum 100); waarden buiten het toegestane bereik worden begrensd.

De envelope:

NaamTypeBeschrijving
dataarrayDe pagina met resources.
links.firststringURL van de eerste pagina.
links.laststringURL van de laatste pagina.
links.prevstring of nullURL van de vorige pagina, null op de eerste pagina.
links.nextstring of nullURL van de volgende pagina, null op de laatste pagina.
meta.current_pageintegerHuidig paginanummer.
meta.frominteger of null1-gebaseerde index van het eerste item op deze pagina, null wanneer de pagina leeg is.
meta.last_pageintegerTotaal aantal pagina's.
meta.linksarrayPaginator-linkobjecten (url, label, active) voor het bouwen van paginanavigatie.
meta.pathstringBasis-URL van het endpoint zonder paginatieparameters.
meta.per_pageintegerEffectieve paginagrootte.
meta.tointeger of null1-gebaseerde index van het laatste item op deze pagina, null wanneer de pagina leeg is.
meta.totalintegerTotaal aantal overeenkomende items.
Response
{
  "data": [
    { "id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" }
  ],
  "links": {
    "first": "https://api.borkol.com/v1/api/commerce/products?page=1",
    "last": "https://api.borkol.com/v1/api/commerce/products?page=4",
    "prev": null,
    "next": "https://api.borkol.com/v1/api/commerce/products?page=2"
  },
  "meta": {
    "current_page": 1,
    "from": 1,
    "last_page": 4,
    "links": [
      { "url": null, "label": "« Previous", "active": false },
      { "url": "https://api.borkol.com/v1/api/commerce/products?page=1", "label": "1", "active": true }
    ],
    "path": "https://api.borkol.com/v1/api/commerce/products",
    "per_page": 25,
    "to": 25,
    "total": 87
  }
}

Endpoints die één object teruggeven (zoals GET /v1/api/me) geven het kale JSON-object terug zonder data-wrapper, tenzij hun referentiepagina anders vermeldt.

Samenvatting foutafhandeling voor clients

StatusHerken aanActie
401message == "Unauthenticated."Key ontbreekt of is ingetrokken; regel een geldige key. Niet opnieuw proberen.
403code == "tenant_suspended"Winkel geschorst; stop met aanroepen tot dit is opgelost.
403message == "Invalid ability provided."Key mist de scope; geef een key uit met de juiste scopes. Niet opnieuw proberen.
403code == "module_disabled" (of error beginnend met "Module not enabled:")Module uitgeschakeld voor de winkel. Niet opnieuw proberen.
404message aanwezig, of error beginnend met "Module not enabled:"Route of record bestaat niet in deze winkel, of (alleen offerteaanvraag) de sales-module is uitgeschakeld.
422code is CAPABILITY_INACTIVE, INVALID_CONFIGURATION of NOT_PURCHASABLE, met errorsCartregel geweigerd; branch op code, toon errors.
422code aanwezig, geen errorsBeleids- of bedrijfsweigering; toon message. Codes: cart_constraint (cartregels), login_required, guest_only, b2b_approval_required, b2c_only, min_order_value (checkout), SIGNATURE_REQUIRED, SIGNATURE_INVALID (offerte accepteren).
422errors-object aanwezigCorrigeer de genoemde velden en stuur opnieuw.
429message == "Too Many Attempts."Wacht Retry-After seconden en probeer opnieuw.
429message == "Too many submissions. Try again later."Limiet voor formulierinzendingen van deze bezoeker; vraag de bezoeker het later opnieuw te proberen.
429message == "Too many uploads. Try again later."Limiet voor formulieruploads van deze bezoeker; vraag de bezoeker het later opnieuw te proberen.
5xxelkeServerfout; probeer opnieuw met exponentiële backoff.