Circuit
For Developers
Search...⌘K
Ask Assistant⌘I
Merchant Onboarding Guide

Merchant Onboarding — Illustrated

How a merchant goes from signup to an operational, production-approved account. Two rails, one gate. Everything Circuit creates in the background (Cybrid, Persona, YellowCard, the platform USDC wallet) is shown per step.

  • Cybrid rail — US/CA merchants. Paid via Cybrid ACH/wire to a Plaid-linked bank. KYB via Cybrid-brokered Persona.
  • YellowCard rail — African merchants. Paid via YellowCard disbursement to mobile money or bank. KYB via Circuit's own direct Persona integration (Cybrid's Persona is US/CA-only).

The rail is derived from country at signup (US/CA → cybrid, else yellowcard).

1. The two onboarding tracks → one production gate

Onboarding a merchant flow: Signup + country, Login, Complete KYB, Link a cashout account, Readiness — then Issue live keys or Test keys / sandbox

The gate is structural. authenticateMerchant.ts and authenticatePublishable.ts reject any *_live_* key unless isMerchantProductionReady(merchant) is true. *_test_* keys always work — that is the sandbox. No merchant can integrate with production keys before completing both steps.

5. Endpoint map

StepCybrid rail (US/CA)YellowCard rail (African)
SignupPOST /merchants/signup (country)POST /merchants/signup (country)
KYBPOST /merchants/{id}/kyb (Cybrid-Persona)POST /merchants/{id}/persona-kyb (direct Persona)
KYB completionCybrid webhook /cybrid/webhookPersona webhook /persona/webhook (HMAC-verified)
Payout destinationPOST /merchants/{id}/cybrid/bank-account (Plaid)GET /merchants/{id}/yc/payout-networks POST /merchants/{id}/yc/payout-destination
ReadinessGET /merchants/{id}/readinessGET /merchants/{id}/readiness
KeysPOST /merchants/{id}/api-keys (test first)POST /merchants/{id}/api-keys (test first)

6. Sandbox vs production

  • Sandbox is always on. sk_test_* / pk_test_* keys pass auth at every onboarding state, so a merchant can integrate and test before approval. Sandbox uses the sandbox base URLs/keys for Cybrid, YellowCard, and Persona (per-stage env).
  • Production requires the gate. sk_live_* / pk_live_* are rejected (403) until isMerchantProductionReady — KYB verified and ≥1 validated cashout account for the rail. This protects both rails at one middleware choke point and closes the prior hole where an unverified merchant's live key would authenticate.

7. Cashout accounts (single vs multi-account)

A merchant's cashout account is a payout-destination record (one collection per merchant, one default per rail). The count allowed is gated by the merchant's account level (admin-set):

Account levelCashout accountsSet by
standard (default)one per rail — a 2nd link is rejected (403)
multi_accountmany — one default + per-payment overrideadmin: POST /admin/merchants/{id}/account-level
  • Linking creates a validated destination row (first = default). A multi_account merchant manages them via GET/POST/DELETE /merchants/{id}/payout-destinations[...].
  • A PaymentIntent may name a destinationId; otherwise the default is used. The chosen destination is snapshotted onto the Payout at creation for both rails, so a later default change can't redirect an in-flight payout.
Circuit · Merchant Onboarding Guide · covers signup, KYB, cashout accounts, and going live on the Cybrid and YellowCard rails.