Contacten

Contactaccounts

Hoe storefront-contactaccounts, sessietokens en de gastlevenscyclus werken.

Bekijk als Markdown

Contacts geven je storefront contactaccounts: registratie, inloggen, wachtwoordherstel, een profiel en opgeslagen adressen. Alle routes leven onder /v1/api/contacts, met een identieke alias op /v1/api/customers voor integraties die vóór de hernoeming zijn gebouwd. Contacts horen bij elke winkel, dus je hoeft vooraf geen module in te schakelen.

Alias: /v1/api/customers

Elke route hieronder wordt ook, ongewijzigd, aangeboden op het equivalente /v1/api/customers/... pad (bijvoorbeeld POST /v1/api/customers/register naast POST /v1/api/contacts/register). Request- en response-vorm zijn op beide identiek. Deze alias is permanent, geen deprecatievenster: bestaande integraties hoeven nooit te migreren, al zouden nieuwe integraties /v1/api/contacts moeten gebruiken.

Twee tokens, twee headers

Contact-endpoints gebruiken een gelaagd authenticatiemodel:

  1. Tenant-API-key (altijd verplicht). Elk request draagt de API-key van je winkel als Authorization: Bearer {api_key}, precies zoals de rest van de storefront API. De key heeft de contacts:write scope nodig voor alle POST-, PATCH- en DELETE-endpoints en de contacts:read scope voor de GET-endpoints. Een key die vóór de hernoeming is aangemaakt draagt in plaats daarvan customers:write / customers:read, en wordt nog steeds geaccepteerd. Een ontbrekende scope retourneert 403 {"message":"Invalid ability provided."}.
  2. Contactsessietoken (verplicht op contact-geauthenticeerde endpoints). POST /v1/api/contacts/register en POST /v1/api/contacts/login retourneren een token-string. Stuur deze op volgende requests mee in de X-Customer-Token header. Een ontbrekend of ongeldig contacttoken retourneert 401 {"message":"Invalid customer token."}.

De twee headers zijn onafhankelijk en beide verplicht op contact-geauthenticeerde routes:

text
Authorization: Bearer {api_key}
X-Customer-Token: {token}

Welke endpoints wat nodig hebben:

EndpointAPI-key scopeX-Customer-Token
POST /registercontacts:write (customers:write geaccepteerd)Nee
POST /logincontacts:write (customers:write geaccepteerd)Nee
POST /forgot-passwordcontacts:write (customers:write geaccepteerd)Nee
POST /reset-passwordcontacts:write (customers:write geaccepteerd)Nee
POST /logoutcontacts:write (customers:write geaccepteerd)Ja
GET /mecontacts:read (customers:read geaccepteerd)Ja
PATCH /mecontacts:write (customers:write geaccepteerd)Ja
GET /me/addressescontacts:read (customers:read geaccepteerd)Ja
POST /me/addressescontacts:write (customers:write geaccepteerd)Ja
PATCH /me/addresses/{id}contacts:write (customers:write geaccepteerd)Ja
DELETE /me/addresses/{id}contacts:write (customers:write geaccepteerd)Ja

Contactsessietokens verlopen niet op een timer. Ze worden ingetrokken door POST /logout (één token) en door een succesvol wachtwoordherstel (alle tokens van het contact).

Het publieke contactobject

Contactgerichte endpoints retourneren deze vorm (interne velden zoals is_guest, type en customer_group_id worden nooit blootgesteld op de storefront API):

VeldTypeBeschrijving
idstring (uuid)Contact-id. Stabiel over de gast-naar-account-upgrade heen.
namestringVolledige naam.
emailstring of nullE-mailadres, altijd lowercase indien aanwezig. Uniek per winkel. Registreren via de storefront vereist altijd een e-mailadres; een contact kan alleen een null e-mailadres hebben wanneer het door de handelaar is aangemaakt (bijvoorbeeld een zakelijk contact toegevoegd via het klantdashboard of CSV-import) zonder e-mailadres.
phonestring of nullTelefoonnummer.
kindstringperson of company. Alleen-lezen via deze API: wordt door de handelaar ingesteld, niet door de storefront.
company_namestring of nullBedrijfsnaam. Alleen ingesteld wanneer kind company is. Alleen-lezen via deze API.
registration_numberstring of nullKvK-nummer of vergelijkbaar registratienummer. Alleen-lezen via deze API.
vat_idstring of nullBtw-nummer. Alleen-lezen via deze API.
external_idstring of nullDoor de handelaar toegekende identifier, bijvoorbeeld een ERP- of boekhoud-id. Alleen-lezen via deze API.
display_namestringDe bedrijfsnaam wanneer die er is, anders de naam van het contact. Afgeleid, niet opgeslagen.
created_atstring (ISO 8601)Aanmaaktijdstempel, bijvoorbeeld 2026-08-14T10:32:11+00:00.

kind, company_name, registration_number, vat_id en external_id zijn leesbaar op elk contact maar niet schrijfbaar via register of PATCH /me: een storefrontaccount kan zichzelf niet omzetten in een zakelijk contact. De handelaar stelt deze velden in vanuit de Contacten-pagina's van het klantdashboard.

Gastlevenscyclus

E-mailcapture in de winkelwagen (Commerce-module) kan een contactrij aanmaken met alleen een e-mailadres en geen wachtwoord (een gast). Dit is op drie plekken van belang:

  • Registratie upgradet gasten. Registreren met een e-mailadres dat bij een gastrij hoort, upgradet die rij ter plekke: zelfde id, bestelgeschiedenis behouden. Alleen een e-mailadres dat bij een echt (niet-gast) account hoort, faalt met 422 "Email already registered.".
  • Gasten kunnen niet inloggen. Ze hebben geen wachtwoord, dus inloggen faalt met de generieke 422 "Invalid credentials.".
  • Wachtwoordherstel upgradet ook. Het voltooien van een reset zet een wachtwoord, markeert het account als niet-gast, en zet email_verified_at als dat nog niet gezet was. Dit is een tweede pad van gast-checkout naar een volwaardig account.

Rate limits

Alle contact-endpoints delen de storefront-limiet van 120 requests per minuut per winkel (429 met een Retry-After header bij overschrijding). De vier credential-endpoints (register, login, forgot-password, reset-password) dragen een extra limiet van 10 requests per minuut per client-IP om brute-force-pogingen af te remmen.

Fouten

Alle fout-envelopes zijn de standaard storefront-vormen:

StatusBodyOorzaak
401{"message":"Unauthenticated."}Ontbrekende of ongeldige tenant-API-key.
401{"message":"Invalid customer token."}Ontbrekende of ongeldige X-Customer-Token op een contact-geauthenticeerde route.
403{"message":"Invalid ability provided."}API-key mist de vereiste scope.
403{"message":"Tenant suspended.","code":"tenant_suspended"}Winkel geschorst.
404{"message":"..."}Resource niet gevonden (of niet van het geauthenticeerde contact).
422{"message":"...","errors":{"field":["..."]}}Validatiefout.
429{"message":"Too Many Attempts."}Rate limit overschreden.