Users & IBANs
Every participant in a contract must exist in Waffy and be linked to your organization. Anyone who will receive money also needs a bank account.
- 1Auth
- 2Users
- 3Contract
- 4Payment
- 5Settle
Tokens used on this page
Register or link the user
Call this for every user, buyer and seller, before creating a contract. One call registers a new phone number, or links an existing Waffy customer to your organization:
curl -s -X POST "$ID_BASE_URL/realms/waffy/waffy-partner/customers" \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+9665XXXXXXXX",
"firstName": "Ahmed",
"lastName": "Al-Ghamdi"
}'{ "waffyUserId": 2264, "userIdentification": 39311497 }Save waffyUserId as the buyer or seller id and call it once for each party. The seller (provider) is registered with the same call.
Consent
PENDING until they consent. Establishing consent, by SMS link, your own OTP screen or checkout login, is covered in Customers & consent.Add a bank account (IBAN)
Required for anyone who will receive money: the seller, and the buyer in case of a refund. It is also required, with a valid address, for bank transfer cash-out. Saudi format: SA + 22 digits.
curl -s -X POST "$AUTH_BASE_URL/api/users/external/$SELLER_ID/banks" \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"iban": "SA0380000000608010167519",
"currency": "SAR",
"beneficiaryName": "Ahmed Al-Ghamdi",
"nationalId": "1000000000"
}'
# Repeat for the buyer with their own IBAN and nationalId$SELLER_ID is the waffyUserId from the register call. $AUTH_BASE_URL is the authentication service host for your environment.
Add an address
Required for bank transfer cash-out alongside the IBAN. Only addressLabel (for example HOME or WORK) and countryCode are required; the other fields are optional.
curl -s -X POST "$AUTH_BASE_URL/api/external/profiles/$SELLER_ID/addresses" \
-H "Authorization: Bearer $ORG_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addressLabel": "HOME",
"street": "King Fahd Road",
"district": "Al Olaya",
"city": "Riyadh",
"countryCode": "SA",
"postalCode": "12271"
}'
# Repeat for the buyerAbsher identity verification (optional, KYC)
A two-step flow, only needed if your organization requires Saudi national ID verification. The user enters their national ID, Absher validates it and sends an OTP to the phone registered with that ID in the government system (this may differ from their Waffy phone).
Token for these two calls
user_token. Check with Waffy whether your integration should send the client admin token instead before building on them.Step 1: submit the national ID
Waffy forwards the ID to Absher. If it is valid, Absher sends an OTP to the user's registered phone. nationalId must be exactly 10 digits.
curl -s -X PATCH "$AUTH_BASE_URL/api/users/external/$USER_ID/national-id" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nationalId": "1000000000"
}'Step 2: validate the OTP
curl -s "$AUTH_BASE_URL/api/external/otps/validate" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ABSHER_OTP",
"phoneNumber": "+966XXXXXXXXX",
"otp": 123456
}'{
"data": {
"valid": true
}
}| OTP type | Use |
|---|---|
WAFFY_OTP | Standard Waffy OTP verification |
ABSHER_OTP | Saudi national ID verification via Nafath/Absher |
Legacy user endpoints (deprecated)
Deprecated: do not use for new integrations
app_token. This keeps working while they move to the calls above. Waffy will announce a retirement date.| Legacy call | Token | Replaced by |
|---|---|---|
POST /v2/api/users/sign-up | app_token | Register or link the user |
POST /api/users/{id}/IBAN | user_token | Add a bank account |
POST /api/profiles/{id}/addresses | user_token | Add an address |
# Legacy sign-up / link (app_token)
curl -s "$WAFFY_AUTH_URL/v2/api/users/sign-up" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"phoneNumber": "+966XXXXXXXXX",
"firstName": "Ahmed",
"lastName": "Al-Ghamdi",
"clientUserId": "your_internal_user_id"
}'
# => { "data": { "id": 99001, "preExistingUser": false, "clientUserToken": "eyJhbGc..." } }In the legacy flow data.id is the user id and clientUserToken is the customer's Waffy password, used for the legacy payment-time token. Store it encrypted, never log it and never expose it to a browser.