KYC and KYB Flow
A sub-merchant cannot transact until they're verified and their wallet is provisioned. Inflow runs identity verification under the hood and exposes a unified contract (nextUrl + nextSteps) — you never integrate with a third-party verification provider directly.
Always treat the GET …/kyc/status response as the source of truth for what to do next — don't hard-code hosted URLs on your side.
When is a sub-merchant operable?
A sub-merchant is ready for X-On-Behalf-Of calls when all of the following are true:
kycReadyistrueonGET /api/connect/accounts/:subMerchantId/kyc/statuswalletIdis non-null (custodial wallet provisioned)- The sub-merchant is not suspended
Until then, payment and payout routes return 403 ON_BEHALF_SUBMERCHANT_NOT_OPERABLE.
kycReadycombines verification and wallet provisioning. If KYC passes but wallet creation fails,kycReadystaysfalseandnextStepsmay includeretry_wallet_provisioning.
Response shapes by endpoint
Connect uses two related but distinct response shapes:
At creation — POST /api/connect/accounts
POST /api/connect/accountsReturns the initial bootstrap state:
{
"id": "usr_01JABCDEF…",
"kycStatus": "pending",
"verificationType": "KYC",
"nextUrl": "https://verify.inflowpay.com/…",
"nextSteps": ["redirect_submerchant_to_url", "…", "check_connect_kyc_status"],
"kycBootstrapError": null
}Use customerType ("individual" | "business") to choose KYC vs KYB.
At status poll — GET /api/connect/accounts/:subMerchantId/kyc/status
GET /api/connect/accounts/:subMerchantId/kyc/statusThis is the live source of truth during onboarding:
{
"subMerchantId": "usr_01JABCDEF…",
"kycReady": false,
"verificationType": "KYB",
"nextUrl": "https://verify.inflowpay.com/…",
"nextSteps": ["redirect_submerchant_to_url", "wait_for_aiprise_webhook_approval", "check_connect_kyc_status"],
"pendingRequirements": ["proof_of_address", "company_registration"],
"fallbackBridgeKycLink": "https://verify.inflowpay.com/…",
"walletId": null
}| Field | Meaning |
|---|---|
kycReady | true when verification is complete and the wallet is provisioned |
pendingRequirements | Verification items still outstanding |
fallbackBridgeKycLink | Alternate hosted verification link (independent of ToS acceptance state) |
walletId | Custodial wallet external id — non-null when operable |
Poll until kycReady === true.
Some field and
nextStepsvalues use legacy API identifiers. Treat them as opaque enums — branch on the exact strings returned, not on their names.
At read — GET /api/connect/accounts/:subMerchantId
GET /api/connect/accounts/:subMerchantIdReturns a cached snapshot for dashboard use:
{
"id": "usr_01JABCDEF…",
"connectKycStatus": "approved",
"verificationType": "KYC",
"custodialWalletAddress": "0xABC123…"
}connectKycStatus | Meaning |
|---|---|
"pending" | Verification in progress |
"approved" | Verification passed |
"rejected" | Verification declined — terminal for this account |
null | No cached status yet |
For driving onboarding forward, always prefer GET …/kyc/status over the read endpoint.
The unified contract
nextUrl
nextUrlThe Inflow-hosted URL the sub-merchant must visit to make progress. null when there is nothing for the user to do (e.g. waiting for an async KYB decision).
nextSteps
nextStepsAn ordered string array describing what should happen next. Match on the exact strings returned by the API:
| Step | Meaning |
|---|---|
redirect_submerchant_to_url | Redirect the user to nextUrl. |
complete_bridge_tos_and_kyc_flow | User accepts Inflow ToS and completes identity verification on the hosted page. |
wait_for_aiprise_webhook_approval | KYB form submitted — decision is async; keep polling. |
accept_bridge_tos | Sub-merchant still has Inflow Terms of Service to accept; nextUrl points to the ToS page. |
complete_remaining_bridge_onboarding | Used with accept_bridge_tos when both ToS acceptance and additional verification steps are pending. |
check_connect_kyc_status | Re-poll the status endpoint after a delay. |
retry_kyc_bootstrap | Initial verification link failed to be issued; the next status poll will retry. |
retry_wallet_provisioning | Verification approved but wallet creation failed; re-poll to retry. |
KYC happy path: ["redirect_submerchant_to_url", "complete_bridge_tos_and_kyc_flow", "check_connect_kyc_status"]
KYB happy path: ["redirect_submerchant_to_url", "wait_for_aiprise_webhook_approval", "check_connect_kyc_status"]
pendingRequirements
pendingRequirementsString identifiers for outstanding verification items (e.g. "proof_of_address", "company_registration", "terms_of_service"). Use these to show progress in your onboarding UI or to decide whether to redirect to nextUrl vs fallbackBridgeKycLink.
Polling for status
GET /api/connect/accounts/:subMerchantId/kyc/status
?kycEndorsement=&redirectUri=
X-Inflow-Api-Key: <inflow_apikey>| Query param | When to use |
|---|---|
kycEndorsement ("sepa" | "spei" | "cards") | Rail-aware hint when generating a hosted link. Only relevant if you need a link tuned for a specific payout rail. |
redirectUri | Override the redirect URL used when (re-)generating a hosted link. Useful for routing back to a per-seller page. |
Recommended cadence:
- While the user is on the hosted page: don't poll — wait until they hit your
redirectUrlKyc. - After redirect-back: poll every 2–3 seconds for up to ~30 seconds. KYC is usually instant; KYB can take longer.
- If still not ready after 30s: stop polling, surface "we're verifying — we'll notify you when it's done", and rely on webhooks to wake your backend.
Retrying a failed bootstrap
If POST /api/connect/accounts returned kycStatus: "pending" with a kycBootstrapError, the sub-merchant exists but doesn't yet have a hosted link. Recovery is one extra call:
curl "https://api.inflowpay.xyz/api/connect/accounts/$SUB/kyc/status?redirectUri=https://marketplace.example.com/onboarding/$SELLER/done" \
-H "X-Inflow-Api-Key: $INFLOW_API_KEY"The status endpoint detects the missing session and re-issues a fresh nextUrl. No additional state to track on your side.
Handling rejection
connectKycStatus: "rejected" (or a terminal rejection from the status endpoint) is final for the current sub-merchant account. You cannot re-run verification on the same record — regulatory rules require a fresh customer.
- Surface a clear message to the seller (Inflow does not return a free-text rejection reason).
- Optionally suspend the sub-merchant via
POST …/suspendso any pending obligations stop processing. - If the seller wants to retry, sign them up with a different email — that creates a brand-new sub-merchant and KYC flow.
Security note
KYC state is server-controlled. Verification status, provider IDs, and approval flags are under Inflow's exclusive control — they cannot be set or overwritten via PATCH /api/connect/accounts/:id, even if you put them inside marketplaceMetadata.