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

VeldTypeBeschrijving
idintegerUniek klant-ID
first_namestringVoornaam van de klant
last_namestringAchternaam van de klant
emailstringE-mailadres (uniek per handelaar)
phonestringTelefoonnummer
date_of_birthdateGeboortedatum
customer_sincedateOptionele startdatum van de klantrelatie. Laat je hem leeg, dan telt Puntjes vanaf de dag waarop het record werd aangemaakt.
localestringVoorkeurstaal (nl of en, standaard: nl)
statusstringHuidige 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:

TypeBeschrijving
loyalty_cardEen 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.
emailHet 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
StatusBeschrijving
ActiveKlant kan gewoon punten sparen en inwisselen
DeactivatedKlant staat uit: geen nieuwe transacties of inwisselingen
AnonymizedPersoonsgegevens 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.

KanaalBetekenis
portalIemand van je team vinkte het vakje aan in het adminportaal
apiJouw integratie stuurde marketing_consent mee
emailDe klant gebruikte de uitschrijflink in een e-mail
importEen 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.