Getting Started · Customers

Customers & consent

Before you act for a customer, for example to take a payment, they must be registered with Waffy, linked to your organization and have given consent.

What you need

An org token (see Authentication). Every call on this page uses it as the bearer. A client admin token or a customer token is rejected with 401.

Consent status

StatusMeaning
PENDINGLinked, but the customer has not agreed yet.
VERIFIEDThe customer agreed. You can act for them.
REJECTEDThe customer declined. A fresh consent link, OTP verification or checkout login can reverse it.

Until consent is established, calls that act for the customer fail with consent_required (or consent_rejected after a decline).

1. Register or link a customer

One call covers every case. A new phone number is registered and linked, an existing Waffy customer is just linked, and one already linked is returned as is. You never need to check first.

bash
export CUSTOMER_PHONE=+9665XXXXXXXX

curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/customers" \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"phoneNumber\":\"$CUSTOMER_PHONE\",\"firstName\":\"Sara\",\"lastName\":\"Al-Otaibi\"}"
json
{ "waffyUserId": 2264, "userIdentification": 39311497,
  "consent": { "status": "VERIFIED", "type": "CUSTOMER_APPROVED",
               "required": false, "autoAccept": false, "linkSent": false } }
  • phoneNumber is required, in the form +9665XXXXXXXX. firstName, lastName and email are optional.
  • Keep waffyUserId. You need it for bank account and address calls and for contracts.
  • The other party of a contract (the provider) is registered with the exact same call. There is no separate type or role.

The consentMethod field

ValueWhat happens
"sms"Sends the signed consent link by SMS in the same call. Only the first call that creates the link sends it; use the resend call below later.
"otp"Accepted, but it does nothing in this call. Send the OTP yourself with otp/send (path B).
empty or omittedNothing is sent and the customer stays PENDING. Exception: if your client has automatic consent enabled (a Waffy-managed setting, ask Waffy), the customer is linked as already consented and nothing more is needed.

Do you need to ask for consent?

The registration response tells you, so you never ask a customer twice. Each field is about this customer and the client whose token you use:

FieldMeaning
statusPENDING, VERIFIED or REJECTED, as stored.
typeCUSTOMER_APPROVED, AUTO_CONTRACTUAL or LIVE_OTP_VERIFIED; null until verified.
requiredTrue unless VERIFIED: you must get consent before you can act for the customer.
autoAcceptThis client's automatic-consent setting, read live. Each of your clients has its own value. Do not cache it: Waffy staff can change it.
linkSentTrue when the consent SMS was accepted for sending on this call (consentMethod: "sms", first call only).
  1. Call the registration endpoint.
  2. If consent.required is false, carry on. This is also what a second contract with the same customer sees: nothing is asked again.
  3. If it is true, get consent with the SMS link (Path A) or your own OTP screen (Path B), then confirm with the same call or the lookup below.

If you sent consentMethod: "sms" and the SMS could not be accepted for sending, the customer is still registered: you get 201 with linkSent: false and required: true. Call the resend endpoint to retry.

Look up the status without registering anyone

bash
curl -s "$ID_BASE_URL/realms/waffy/waffy-partner/customers/consent?phoneNumber=%2B9665XXXXXXXX" \
  -H "Authorization: Bearer $ORG_TOKEN"
json
{ "linked": true, "status": "PENDING", "type": null, "required": true }

Read-only: nothing is created and nothing is sent. A phone with no Waffy account and a phone not linked to your client both answer linked: false. Write the + as %2B in the URL. It shares the hourly limit of the resend call.

Read your client's settings

bash
curl -s "$ID_BASE_URL/realms/waffy/waffy-partner/client" \
  -H "Authorization: Bearer $ORG_TOKEN"
json
{ "clientId": "wasetk_Portal_...", "autoAcceptConsent": false, "checkoutLoginMode": "ticket" }

2. Establish consent

Pick the path that fits your integration.

PathHowBest for
A. Signed linkThe customer gets an SMS link and approves on a Waffy page. Send it with consentMethod: "sms" or the resend call.The simplest option. No UI of your own.
B. Your own OTP screenWaffy sends a code, your UI collects it, you verify it server to server (otp/send, otp/verify).You want the customer to stay on your pages.
C. Checkout loginThe customer enters a verification code on Waffy’s checkout page when they pay. No extra API call, but you must have registered or linked the customer first, and the contract must list them as a CUSTOMER party.Consent is only needed at payment time.

Path A: send or resend the consent link

consentMethod: "sms" only sends on the first call. To send again, because the customer missed it or declined and you want to ask once more, use this call. It works for PENDING and REJECTED customers. For a customer who already consented it sends nothing:

bash
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/consent/send" \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"phoneNumber\":\"$CUSTOMER_PHONE\"}"
json
{ "sent": true }
HTTPMeaning
400This customer is not linked to your organization yet. Register or link them first.
404No Waffy account exists for this phone number.
429Your organization’s hourly consent-link limit was reached. It is counted per client and separately from the OTP limit.
502The SMS could not be accepted for sending. The link the customer already holds keeps working. Retry.

sent: false is not a failure; it says why nothing was sent:

AnswerWhen
{ "sent": false, "reason": "ALREADY_VERIFIED", "status": "VERIFIED", "type": "..." }The customer already consented. No SMS is sent.
{ "sent": false, "reason": "RECENTLY_SENT", "retryAfterSeconds": 41 }A link was sent for this customer and client less than 60 seconds ago. That link still works.

sent: true means accepted for sending, not delivered. A new link replaces the previous one only after the SMS was accepted.

The link can be used once. Opening it again, approving or declining twice, shows a "link no longer valid" page.

Path B: verify an OTP yourself

Send the code. This works even if the customer is not registered yet:

bash
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/otp/send" \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"phoneNumber\":\"$CUSTOMER_PHONE\"}"

Collect the code in your own UI, then verify it. The call records consent. If you already registered the customer, send only the phone and the code:

bash
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/otp/verify" \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"phoneNumber\":\"$CUSTOMER_PHONE\",\"otp\":\"123456\"}"

For a customer with no Waffy account yet, add the details and the same call registers them too. They are used only when the account is created; an existing customer's details are not changed:

bash
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/otp/verify" \
  -H "Authorization: Bearer $ORG_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{\"phoneNumber\":\"$CUSTOMER_PHONE\",\"otp\":\"123456\",\"firstName\":\"Sara\",\"lastName\":\"Al-Otaibi\",\"email\":\"sara@example.com\"}"

With only the phone and the code, a phone that has no account yet still gets one, without a name or email. Use the second form for a new customer.

json
{ "waffyUserId": 2264, "userIdentification": 39311497 }
CallHTTPMeaning
otp/send429Your organization’s hourly OTP limit was reached.
otp/send400Phone number missing or not recognizable.
otp/send502Sending the OTP failed downstream. Transient, retry.
otp/verify400Wrong or expired code, or a missing field. Nothing is created or consented on a failed attempt. Send a new OTP and retry.
otp/verify502Creating the customer or recording consent failed downstream. Retry.

The response contains identifiers only, never a token. A successful verification also reverses an earlier decline. To pay, get a payment ticket as for any consented customer (see Authentication).

Testing consent without a phone

In the sandbox you can approve or decline as the customer would, from curl or Postman (the collection's Consent folder). There is no API to read a customer's consent token, because in production it only reaches them by SMS. In the sandbox, ask Waffy for the token of your test phone number.

bash
export CONSENT_TOKEN=<from Waffy>

# View the page (always 200 text/html; check the body, not the status code)
curl -s "$ID_BASE_URL/realms/waffy/waffy-consent/$CONSENT_TOKEN"

# Approve: PENDING -> VERIFIED
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-consent/$CONSENT_TOKEN/decision" \
  --data-urlencode "approved=true"

# Decline: PENDING -> REJECTED
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-consent/$CONSENT_TOKEN/decision" \
  --data-urlencode "approved=false"

Testing only

These calls exist so you can test your own handling of consent_required and consent_rejected. In production the customer decides on their own phone.