Appearance
Onboard a user
Send a user to Zay's onboarding, bring them back to your product, and know when you can pay them.
Want onboarding inside your own page instead of a redirect? See Embed onboarding.
Requirements
| Requirement | Description |
|---|---|
| A user | Created with Create user — you need their onboarding_url |
| A webhook endpoint | Registered and receiving events — see Get started, steps 2–3 |
| A return page | A URL in your product where the user lands afterwards |
How it works
- Take the user's
onboarding_url - Add your
callback_url - Redirect the user
- Handle the user coming back
- Wait until the user can be paid
1. Take the onboarding URL
Every User object carries the onboarding URL for that user in onboarding_url. Take it from the Create user response rather than building it yourself:
https://privy-stag.zay.me/onboarding?merchant_id=<merchant_id>&user_id=<user_id>Onboarding is served from Zay's own host — privy-stag.zay.me on staging, privy.zay.me in production — not from the Merchant API's.
The URL is not a secret. Security rests on the one-time code the user enters during onboarding, not on the URL — a merchant_id / user_id pair alone cannot complete onboarding for someone. The user's phone_number and email are pre-filled, so they don't retype them.
2. Add your callback URL
Append callback_url — where Zay sends the user back once they're done — URL-encoded:
https://privy-stag.zay.me/onboarding?merchant_id=<merchant_id>&user_id=<user_id>&callback_url=https%3A%2F%2Fexample.com%2Fzay%2Fdonehttps URLs and custom app deep-link schemes (yourapp://…) are accepted. javascript:, data:, vbscript: and file: URLs are ignored.
3. Redirect the user
Send the user's browser to the URL — a link, a button, or an HTTP 302 from your server:
html
<a href="https://privy-stag.zay.me/onboarding?merchant_id=…&user_id=…&callback_url=…">
Set up your Zay wallet
</a>The user verifies their phone and email, picks their country, and completes identity verification. Allow a few minutes.
4. Handle the user coming back
When the user reaches the end of the web flow, Zay sends them to your callback_url with a status query parameter:
https://example.com/zay/done?status=card_is_readystatus says where the user left off, so you can choose what to show them — for example card_is_ready (the card is issued and activated), card_issuing_failed, kyc_declined or residence_country_waitlisted.
Coming back does not mean the user can be paid. The user usually returns once their card is issued and activated, but status is a hint for your screen, not a verdict. Don't decide anything from it. Wait for the webhook in the next step.
5. Wait until the user can be paid
Don't poll. When the user's card is ready to spend, Zay sends user.onboarding_completed, carrying the wallet_address to pay. From that moment you can report payouts for them.
json
{
"type": "user.onboarding_completed",
"data": {
"user_id": "2c9596e6-7c48-4fe9-b957-738bd2e04adc",
"wallet_address": "0x742d35cc6634c0532925a3b844bc9e7595f0beb7"
}
}If the user doesn't finish
- They left halfway. Send them to the same
onboarding_urlagain. They sign in with their phone and continue where they stopped. - Verification needs another try. You receive nothing: onboarding asks the user to fix what was refused, and they continue from there. If they left, send them to the same
onboarding_urlagain. - Verification was declined. You receive
user.onboarding_failedwith areason. The user cannot continue; if the reason isregion_not_supported, offer them another way to be paid. - You never hear back. A user who stops stays in
account_stateonboarding; read it with Retrieve user.
Related
- How onboarding works — the steps, the events and account states
- Embed onboarding — the same flow inside an
<iframe>on your page - Users — the User object and its endpoints