Merchant onboarding
Two ways to add a sub-merchant — direct API call or self-serve invitation link.
You have two flows to choose from.
Option A — direct creation (you have their wallet)
If your merchants have already given you a wallet address, post it directly:
curl -X POST https://api.0fra.dev/v1/onboarding/merchants \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"external_id": "vendor_2001",
"name": "Acme Music Festival",
"merchant_wallet": "0xabc…",
"chain_id": 84532,
"reserve_bps": 500
}'The merchant is created in active state immediately. Use the same external_id you already use in your own systems — 0fra treats it as your local primary key.
Option B — invitation link (self-serve, recommended)
Like Stripe Connect's onboarding link, this lets the merchant bind their own wallet — you never touch their private key.
1. Generate the link
curl -X POST https://api.0fra.dev/v1/merchants/invitations \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"external_id": "vendor_2001",
"suggested_name": "Acme Music Festival",
"chain_id": 84532,
"reserve_bps": 500,
"expires_in_seconds": 604800
}'{
"id": "...",
"token": "moi_live_a1b2c3...",
"url": "https://dash.0fra.dev/onboard/moi_live_a1b2c3...",
"expires_at": "2026-05-02T00:00:00Z",
"external_id": "vendor_2001"
}2. Email the URL to your merchant
The link is single-use, expires after the time you set, and is bound to the external_id you supplied.
3. Merchant completes onboarding
The page at /onboard/<token> walks them through:
- Connect wallet (any EOA — MetaMask, Rabby, Coinbase Wallet)
- Choose their display name
- Sign a free message (
personal_sign) attesting wallet ownership
The signature is verified by 0fra using viem.verifyMessage. On success, the merchant record is created and the invitation marked completed.
Listing & rotating invitations
GET /v1/merchants/invitationsReturns up to 50 most recent invitations with their state (pending / completed / expired) and the wallet attached if completed. To rotate (e.g. merchant lost the link), generate a fresh invitation with the same external_id — it'll get a new token; the old one stays expired.
Programmatic management
Once a merchant exists, common operations:
GET /v1/merchants # list
GET /v1/merchants/:id # detail
# Note: status & reserve adjustments are on the roadmap and currently
# require contacting 0fra support.What's not on the roadmap (yet)
- KYC / KYB verification — MVP relies on the platform doing its own diligence
- Identity-doc upload via 0fra-hosted form
- Tax W-8/W-9 collection
If your jurisdiction requires KYC before payouts, do it in your own system before generating the invitation.