Kernconcepten
Klanten
Een klant is een eindgebruiker die meedoet aan het loyaliteitsprogramma van een handelaar. Klanten sparen punten met transacties en wisselen ze in voor beloningen.
Klantgegevens
| Veld | Type | Beschrijving |
|---|---|---|
id | integer | Uniek klant-ID |
first_name | string | Voornaam van de klant |
last_name | string | Achternaam van de klant |
email | string | E-mailadres (uniek per handelaar) |
phone | string | Telefoonnummer |
date_of_birth | date | Geboortedatum |
customer_since | date | Optionele startdatum van de klantrelatie. Laat je hem leeg, dan telt Puntjes vanaf de dag waarop het record werd aangemaakt. |
locale | string | Voorkeurstaal (nl of en, standaard: nl) |
status | string | Huidige status: active, deactivated of anonymized |
Identifiers
Elke klant heeft een of meer identifiers: waarden waarmee je de klant aan de kassa terugvindt tijdens een transactie. Er zijn twee types:
| Type | Beschrijving |
|---|---|
loyalty_card | Een code van 8 tekens met hoofdletters en cijfers (A-Z, 0-9). Puntjes geeft er automatisch een uit, of je maakt vooraf een reeks aan en laat die op fysieke kaarten drukken. |
email | Het e-mailadres van de klant. |
Identifierwaarden zijn uniek binnen één handelaar. Hoofdletters maken bij het opzoeken geen verschil.
Je eigen ID's
Met een identifier herkent Puntjes een klant. Je external_id staat daar los van: dat is jouw
eigen sleutel voor die klant (het recordnummer in je kassa of webshop), bewaard bij de klant en
uniek binnen je zaak. Puntjes verzint er nooit een, en scannen doe je er niet mee.
Stel hem in bij de registratie. Bij klanten die al bestonden voordat je koppelde, voeg je hem
later toe met POST /customers/link-external-id. Eenmaal gekoppeld lees
en update je die klant op je eigen ID, en hoef je het onze niet te bewaren.
Klantenkaarten
Elke klant krijgt een klantenkaart. Je hoeft geen kaartnummer te verzinnen: geef je bij de
registratie geen kaart mee, dan geeft Puntjes er een uit en krijg je de code terug als
loyalty_card_code.
Wil je fysieke kaarten, dan maak je eerst een reeks aan in het adminportaal, exporteer je de codes als CSV voor de drukker en deel je de gedrukte kaarten aan de kassa uit. Scan je zo'n kaart tijdens de registratie, dan krijgt de klant precies die kaart. Zie Klanten beheren voor de werkwijze.
Een klant kan uiteindelijk meer dan één kaart hebben (maximaal vijf), meestal omdat hij er een
verloor en een vervangende kaart kreeg. Precies één daarvan is de kaart die hij scant: wijs je in
het adminportaal een kaart toe, dan wordt dat de scankaart, dus in de praktijk is het de laatst
toegewezen kaart. Die staat in loyalty_card_code en op zijn wallet-pas. Zijn oudere kaarten
blijven actief en werken nog bij het scannen, dus wat je eerder uitdeelde wordt nooit onbruikbaar.
De e-mailidentifier beheert Puntjes voor je
De e-mailidentifier is een afspiegeling van het e-mailadres in het klantprofiel. Puntjes maakt hem aan, past hem aan bij elke latere wijziging van het adres en verwijdert hem zodra je het adres wist. Los bewerken of deactiveren kan niet: wijzig het e-mailadres van de klant, dan volgt de identifier vanzelf.
Status van een identifier
Identifiers van het type loyalty_card zet je los van elkaar aan of uit. Met een gedeactiveerde identifier zoek je geen klant op en dien je geen transactie in.
Oudere identifierwaarden blijven werken
Puntjes aanvaardde vroeger meerdere andere identifiertypes, voor verschillende scantechnologieën. Die types zijn
samengevoegd tot loyalty_card. De bestaande waarden verhuisden mee en worden nog altijd gevonden bij het opzoeken,
dus kaarten die klanten al op zak hebben blijven werken. Nieuwe waarden van die types kun je niet meer aanmaken, en
een API-client die een vervallen type meestuurt krijgt een validatiefout. Zie
Foutafhandeling.
Statussen van een klant
Active → Deactivated
Active → Anonymized
| Status | Beschrijving |
|---|---|
| Active | Klant kan gewoon punten sparen en inwisselen |
| Deactivated | Klant staat uit: geen nieuwe transacties of inwisselingen |
| Anonymized | Persoonsgegevens gewist voor de AVG; klant valt standaard buiten elke query |
Anonimisering is onomkeerbaar
Anonimiseer je een klant, dan zijn de persoonsgegevens definitief weg. Geanonimiseerde klanten vallen buiten elke API-response en elke query. Je kunt dit niet terugdraaien.
Samengevoegde klanten
Een zaak kan in het beheerportaal twee accounts van dezelfde persoon samenvoegen. Eén account blijft, het andere
wordt gesloten. Het gesloten account antwoordt als een gedeactiveerde klant: is_deactivated is true en het saldo
is 0. De actieve klantenkaarten en de aankopen horen nu bij het account dat blijft, dus een lookup of een verkoop
met een van die kaarten vindt dat account. Heeft het account dat blijft een eigen e-mailadres, dan antwoordt een
lookup met het e-mailadres van het gesloten account 404 CUSTOMER_NOT_FOUND. Hadden beide accounts een
external_id, dan houdt het gesloten account het zijne: zoek je op dat id, dan krijg je het gesloten account terug
met is_deactivated: true en saldo 0, en werk je de klant bij via dat id, dan krijg je 404 EXTERNAL_ID_NOT_FOUND.
Pas je de wallet van een gesloten account aan, of download je de wallet-pas ervan, dan krijg je 422 CUSTOMER_DEACTIVATED.
Registratie
Registreer een nieuwe klant via de API met zijn persoonsgegevens. Een identifier hoeft niet. Puntjes geeft een klantenkaart uit en stuurt de code terug:
POST /api/v1/customers
{
"first_name": "Jan",
"last_name": "De Vries",
"email": "jan@example.com",
"phone": "+31612345678",
"date_of_birth": "1990-05-15",
"locale": "nl"
}
Wil je een voorgedrukte kaart meegeven, scan die dan en stuur de code mee:
{
"first_name": "Jan",
"last_name": "De Vries",
"identifiers": [{ "type": "loyalty_card", "value": "K7M2QX4P" }]
}
Elke nieuwe klant krijgt een wallet, die op 0 punten begint. De eerste aankoop levert de eerste punten op. Een zaak op Plus of hoger kan met een campagne een welkomstcadeau geven bij die eerste aankoop.
Marketingtoestemming
Campagnemail (een verjaardagsbericht, een jubileumbeloning) gaat alleen naar klanten die er
uitdrukkelijk om vroegen. Eén vlag bepaalt dat, marketing_consent, en die staat uit bij elke
klant tot iemand hem op true zet. Niemand komt er met terugwerkende kracht bij: klanten die al
bestonden voor de vlag er was, staan uitgeschreven, en elke geïmporteerde klant ook, behalve een
klant die het importbestand als ingeschreven aanduidt, als wie de import uitvoerde bevestigde dat
die gegevens aan te tonen zijn (zie Klanten beheren).
Puntjes bewaart niet alleen de keuze, maar ook waar ze vandaan komt. Een opt-in legt het moment
vast, het kanaal waarlangs die binnenkwam, wie ze noteerde en de tekstversie die de klant zag
(marketingConsentStatementVersion). Een toestemming uit een Piggy-import heeft de klant nooit
een tekst van Puntjes getoond, dus daar staat piggy-import-attestation: met de datum van de
import: de dag waarop de zaak bevestigde dat de klant in Piggy als ingeschreven stond. Een
ITReflex-import doet hetzelfde met itreflex-import-attestation: en de datum: de dag waarop de
zaak de mailinglijst van de kassa bevestigde.
Trekt iemand de toestemming later in, dan krijgt dat zijn eigen moment en kanaal, en blijft de
eerste vastlegging staan. Toestemming die je niet kunt
dateren en toeschrijven, kun je ook niet aantonen. En dat is precies de situatie waarin een
AVG-verzoek je zet.
| Kanaal | Betekenis |
|---|---|
portal | Iemand van je team vinkte het vakje aan in het adminportaal |
api | Jouw integratie stuurde marketing_consent mee |
email | De klant gebruikte de uitschrijflink in een e-mail |
import | Een import met aangevinkte verklaring, genoteerd door wie de import uitvoerde |
Drie kanalen kunnen de vlag wijzigen: jouw integratie, via marketing_consent op
POST /customers of het update-endpoint; iemand van je team, via
Klant bewerken in het adminportaal; en de klant zelf, via de uitschrijflink in campagnemail. Die
link is ondertekend en verloopt nooit, dus een mail van een jaar oud werkt nog altijd, en erop
klikken vraagt geen account en geen wachtwoord.
Uitschrijven werkt meteen en vraagt geen bevestiging. marketingConsent leest bij de volgende
request false, en het moment van toekenning blijft staan waar het stond, zodat je nog altijd
ziet wanneer de klant zich had ingeschreven.
De vlag weglaten bij een update is iets anders dan false sturen
Laat je marketing_consent weg op PUT|PATCH /customers/by-external-id/{external_id}, dan blijft de opgeslagen
keuze staan. Alleen een expliciete false trekt hem in. Een nachtelijke kassasync die namen en telefoonnummers
pusht, kan de klanten die hij aanraakt dus niet uitschrijven. Zie Klant-endpoints voor de
volledige regel, inclusief wat een expliciete null betekent.
Opzoeken
Zoek een klant op via een van zijn actieve identifiers:
GET /api/v1/customers/lookup?identifier=K7M2QX4P
De response bevat het profiel van de klant en zijn huidige walletsaldo. Dit is de voornaamste manier waarop kassasystemen een klant herkennen bij het afrekenen.
Zie Klant-endpoints voor de volledige API-referentie.