Skip to main content
This is the map. The Onboard a Customer and Onboard with KYC Reliance guides each walk one path step by step. This guide connects them — what state your customer is in at each point, what moves them forward, which webhook tells you it happened, and what to do when something goes wrong. Onboarding is submit-and-listen. You submit one application and wait for a webhook. Nothing to poll, and — unless you deliver verification links yourself — no intermediate states to act on between submission and the final decision. (Self-delivery is the one exception: you forward each person’s link as its idv_link.created event arrives.)
Test this flow in sandbox. Drive it end-to-end with simulated money and deterministic controls — start with the sandbox quickstart, then customer KYC simulation for this flow, and the cheat sheet for every magic value and simulate endpoint.

The two paths, one shape

Every business customer travels the same journey: you submit an application, Conduit verifies the business and the people behind it, and the customer either becomes active or the application is rejected. Only one thing differs: how each control person proves their identity. A control person is a beneficial owner or controlling person of the business — the individuals you list in ownership.persons[]; the discovery response’s individualRequirements[] tells you how many each country requires. Everything else — business-entity fields, KYB documents, each person’s address and proof-of-address documents, screening, the review pipeline, the states, and the decision webhooks — is identical. (Person-verification events like idv_link.created fire only on the standard path — reliance runs no hosted checks, so there are no links to deliver.) The rest follows the shared journey and calls out the reliance branch only where it diverges.
KYC reliance is not on by default. If it is not enabled for your organization, attaching verification reports will not satisfy the identity requirement — each person will still be expected to complete a hosted flow. Contact your Conduit account manager to enable it.

The journey

1

Before you start — discover and collect

There is no customer and no application yet.Requirements are country-specific, so call GET /v2/onboarding/requirements?country=... to learn which fields and documents to collect, then upload each document with POST /v2/documents and keep the returned doc_... ids. Never hardcode the requirements — they vary by country and change over time.Discovery also carries per-person requirements that apply on both paths: each control person’s role in individualRequirements[] lists the fields they must submit (fields[]) and the documents they must supply (documents[]). Which rows appear is jurisdiction- and diligence-dependent — a residential address and a proof of address are listed where enhanced due diligence applies. Collect whatever discovery lists for each person and hold each doc_... id to attach to that person.Reliance branch: additionally, upload one identity verification report (a PDF exported from your own KYC provider) per control person, and hold each doc_... id to attach to that person.See Onboard a Customer → Discover requirements for the full field and document walkthrough, and requirements reference for the response schema.
2

Submit the application

Submit everything you collected to POST /v2/onboarding with a required Idempotency-Key. The endpoint returns 202 Accepted.State: processing. The application now exists and is in review. No customer exists yet — customerId is absent from the response until approval. Nothing else to do here. The next thing that happens is a webhook.Per-person data attaches to the person, on both paths: a person’s residential address (when required) goes under ownership.persons[i].address, and their proof-of-address (and any other per-person document) id goes in ownership.persons[i].documentIds[]. The top-level documentIds[] carries business-entity documents only.Reliance branch: each person’s identity verification report id goes in that same ownership.persons[i].documentIds[], alongside any other per-person documents.
Reuse the same Idempotency-Key if a submission times out, so a retry can’t create a duplicate application. A submission whose tax ID or a control person’s identity matches an existing active application is rejected with 409 ONBOARDING_ALREADY_SUBMITTED.
3

Verification runs (you wait)

State: still processing. Conduit verifies the business and screens the people behind it. This is where the two paths physically differ:
  • Full KYC — each declared control person completes a Conduit-hosted identity check (a government-ID capture, plus a live selfie where enhanced due diligence applies). Conduit emails each person their link by default and, independently, fires an idv_link.created webhook per verification so you can deliver the link yourself (also pullable from POST /v2/applications/{applicationId}/persons/{personReferenceId}/idv-link). See Onboard a Customer for the delivery details.
  • KYC reliance — Conduit reads the report you uploaded for each control person and matches it against the data you submitted, centering on name and date of birth. A clean match clears the identity requirement automatically. A mismatch, an unreadable report, or an unrecognized provider routes the application to a manual reviewer.
The application stays in processing from your side. If you rely on Conduit’s direct email (the default), there is nothing to do but wait. If you deliver links yourself, this is the one step that needs your action mid-flight: hand each link to its person as the idv_link.created webhook arrives (or pull it from the idv-link endpoint if an event went missing), then wait. Verification can take seconds to days depending on what review finds. Wait for the decision webhook in the next step.
4

The decision arrives

Review completes and the application reaches a terminal state. Exactly one of two outcomes fires, and every payload echoes your clientReferenceId.Approved — state: approved. The customer now exists. Two webhooks fire as a pair on first approval:
  • application.approved — carries the populated customerId.
  • customer.created — the new customer, same applicationId and customerId.
Because they are a pair, dedupe on (applicationId, customerId) if your handler reacts to either. An idempotent re-approval of an already-approved application does not re-emit them.Rejected — state: rejected. No customer is created; customerId is absent from the webhook.
  • application.rejected — carries failureCode (machine-readable) and failureMessage (human-readable) when a specific reason is available. Both fields are also readable from GET /v2/applications/{applicationId}.
Both approved and rejected are terminal. See the rejection branch below for how to recover.
5

The customer is active

State: approved, customer exists. Fetch it with GET /v2/customers/{customerId} using the id from the webhook.The customer is active but has no features yet — it can’t receive or move money until you add one. The usual next step is to give them a place to receive funds. See Add Virtual Accounts.
Operations that require a fully-onboarded customer (adding features, creating wallets, transacting) fail with 422 CUSTOMER_NOT_ONBOARDED until the application is approved. Gate those calls on application.approved rather than attempting them and handling the error. See CUSTOMER_NOT_ONBOARDED.

Checking state without a webhook

Webhooks are the intended signal, but if you miss one you can read the current state at any time. The response carries status, and — on a rejected application — failureCode and failureMessage.
You can also list every application for a customer with GET /v2/applications, which carries the same failureCode/failureMessage pair on each rejected row. The full set of status values and their meanings lives in the application reference — treat that as authoritative rather than memorizing them here.

The rejection branch

A rejection does not block the business. A rejected application is terminal and creates no customer, but it no longer counts as active. Once you’ve corrected the data, submit a fresh POST /v2/onboarding:
  • use a new Idempotency-Key — reusing the rejected submission’s key replays its original response instead of creating a new application.
  • keep the same clientReferenceId — so every attempt stays correlated to one record in your system.
To abandon an application that is still in review before any decision, call POST /v2/applications/{applicationId}/cancel. Approved, rejected, and already-cancelled applications are terminal and cannot be cancelled — submit a new application instead.

When something goes wrong

Where to go next

  • Onboard a Customer — the full-KYC path, end to end
  • Onboard with KYC Reliance — the reliance path, end to end
  • Add Virtual Accounts — the usual first step with a newly active customer
  • Webhooks — subscribe to application.approved, application.rejected, customer.created, and idv_link.created (each person’s verification link, to deliver yourself)