Guest checkout with loyalty opt-in
Question: A customer is buying without an account. Your checkout offers to join the loyalty club. What should happen?
The rule
Section titled “The rule”No consent, no member. No member, no transaction.
There is no way to “provisionally” enrol someone and tidy it up later. We
reject a member without gdpr_accepted: true, and that is the correct
behaviour — a purchase is not agreement to marketing.
Two paths
Section titled “Two paths”Order of operations
Section titled “Order of operations”Create the member after payment succeeds but before posting the transaction. You need the member id for the transaction, and you do not want a member created for an order that failed.
STORE_ID below is the id you read from GET /stores at setup.
async function completeGuestCheckout(order, loyaltyOptIn) { const payment = await takePayment(order); if (!payment.ok) return { ok: false };
if (!loyaltyOptIn?.membershipConsent) { return { ok: true, memberId: null }; // nothing goes to Diller }
// They may already be a member from a previous visit. let member = await findMemberByPhone(order.phone);
if (!member) { const res = await dillerFetch(`/api/v2.0/stores/${STORE_ID}/members`, { method: 'POST', body: JSON.stringify({ phone: splitPhone(order.phone), first_name: order.firstName, last_name: order.lastName, email: order.email, department_ids: [DEPARTMENT_ID], consent: { gdpr_accepted: true, save_order_history: !!loyaltyOptIn.purchaseHistoryConsent, receive_sms: !!loyaltyOptIn.smsConsent, receive_email: !!loyaltyOptIn.emailConsent, }, origin: ORIGIN, }), }); if (res.ok) { member = await res.json(); } else if (res.status === 400 && /already registered/i.test(await res.text())) { member = await findMemberByPhone(order.phone); // race: created meanwhile } }
if (member) { await postTransaction(member.id, order); } return { ok: true, memberId: member?.id ?? null };}What the checkout must show
Section titled “What the checkout must show”The consent checkbox is a legal artefact, not a UI decoration.
- Unticked by default. A pre-ticked box is not consent.
- The membership consent is required to join; purchase-history, SMS and email consents are separate and optional.
- Send all four flags. A marketing flag you leave out of the create
request defaults to
true, opting the customer in to messages they never chose. The code above sends each one from its own box. - Link the merchant’s privacy policy —
privacy_policy_urlfromGET /stores/{storeId}. - Use the merchant’s own wording. Do not write your own summary of what they will do with the data.
A workable pattern:
☐ I am joining the customer club at
{store}. See the terms (link toprivacy_policy_url)☐ Send me offers by SMS
☐ Send me offers by email
☐ I would like offers and benefits suited to me, based on my preferences and purchase history.
The first is required and maps to gdpr_accepted. The others map to
receive_sms, receive_email and save_order_history.
Some merchants’ terms bundle SMS and email marketing into joining the club,
with a single box. That is the merchant’s call — but then send
receive_sms: true and receive_email: true explicitly when that box is
ticked, rather than leaving them out and relying on the default.
Do not
Section titled “Do not”- Create a member with
gdpr_accepted: truebecause “they bought something”. They did not consent. - Store the order in Diller under a shared placeholder member. It corrupts the merchant’s reporting and attributes one person’s purchases to a fiction.
- Silently enrol on a later visit because you recognise the phone number.
See also: Signup and login, Transactions.
