Users & IBANs
Every participant in a contract must exist in Waffy and be linked to your client. One endpoint handles all cases — you never need to check state first.
- 1Auth
- 2Users
- 3Contract
- 4Payment
- 5Settle
Step 3 — Sign up / link user
Call this for every user (buyer and seller) before creating a contract. One call handles all three cases automatically:
- •User not registered → registers them → links them → returns customer token
- •User registered but not linked → links them → returns customer token
- •User registered and already linked → returns a fresh customer 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"
}'Response:
{
"data": {
"id": 99001,
"phoneNumber": "+966XXXXXXXXX",
"preExistingUser": false,
"clientUserToken": "eyJhbGc..."
}
}Save data.id as seller_id or buyer_id. Call it twice — once for each party.
Store clientUserToken securely
This is the user's Waffy password — not a temporary token despite the name. Store it encrypted at rest, never log it, never expose it to the browser. You'll use it as the password in an OAuth password-grant to fetch a fresh customer_token at payment time. Do not send password in the sign-up body — Waffy generates and returns it.
preExistingUser: true
Means the user already existed in Waffy. The endpoint linked them to your client automatically — nothing extra needed. You still get a fresh clientUserToken in the response.
Step 4 — Add an IBAN
Required for anyone who will receive money — the seller, and the buyer in case of a refund. Also required alongside a valid address for bank transfer cash-out. Saudi format: SA + 22 digits.
curl -s "$WAFFY_AUTH_URL/api/users/$SELLER_ID/IBAN" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"iban": "SA0380000000608010167519",
"currency": "SAR",
"beneficiaryName": "Ahmed Al-Ghamdi",
"nationalId": "1000000000",
"accountType": "PERSONAL"
}'
# Repeat for buyer with their own IBAN + nationalIdStep 5 — Add an address
Required for bank transfer cash-out alongside IBAN. Use user_token (org admin token).
curl -s "$WAFFY_AUTH_URL/api/profiles/$SELLER_ID/addresses" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addressLabel": "HOME",
"street": "King Fahd Road",
"district": "Al Olaya",
"city": "Riyadh",
"countryCode": "SA",
"postalCode": "12271"
}'
# Repeat for buyerAbsher identity verification (optional — KYC)
Two-step flow only needed if your org 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 (may differ from their Waffy phone).
Step 1 — Submit national ID
Waffy forwards the ID to Absher. If valid, Absher sends an OTP to the user's Absher-registered phone. nationalId must be exactly 10 digits.
curl -s -X PATCH "$WAFFY_AUTH_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 "$WAFFY_AUTH_URL/api/external/otps/validate" \
-H "Authorization: Bearer $USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "ABSHER_OTP",
"phoneNumber": "+966XXXXXXXXX",
"otp": 123456
}'Response:
{
"data": {
"valid": true
}
}| OTP type | Use |
|---|---|
WAFFY_OTP | Standard Waffy OTP verification |
ABSHER_OTP | Saudi national ID verification via Nafath/Absher |