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. No intermediate states to act on between submission and the final decision.

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.
Full KYCKYC reliance
Identity verificationEach control person completes a Conduit-hosted identity flowYou upload one verification report per control person
Where it attachesNothing extra on the personownership.persons[i].documentIds[]
AvailabilityDefaultMust be enabled for your organization first
Detailed guideOnboard a CustomerOnboard with KYC Reliance
Everything else — business-entity fields, KYB documents, screening, the review pipeline, the states, the endpoints, and the webhooks — is identical. 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.Reliance branch: alongside the business documents, 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 by Country 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 null until approval. Nothing else to do here. The next thing that happens is a webhook.Reliance branch: the request body differs in one way. Each person’s verification report id goes in ownership.persons[i].documentIds[]. The top-level documentIds[] still carries business-entity documents only.
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 is taken through a Conduit-hosted identity flow.
  • 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.
Either way the application stays in processing from your side. You do not poll and you do not act. 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 stays null.
  • application.rejected — carries a human-readable reason when one is available. The reason is delivered on the webhook only, so persist it when you receive it.
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. This reports the status but not the rejection reason — that lives on the webhook only.
curl https://api.conduit.financial/v2/applications/{applicationId} \
  -H "x-api-key: YOUR_API_KEY"
{
  "id": "app_2xKjF9mQb7vN4hL1pR3w8t",
  "customerId": null,
  "type": "CUSTOMER_ONBOARDING",
  "status": "rejected",
  "submittedAt": "2026-01-15T09:30:00.000Z",
  "reviewedAt": "2026-01-15T09:42:00.000Z"
}
You can also list every application for a customer with GET /v2/applications. 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

SymptomWhere to look
Submission rejected with 409 ONBOARDING_ALREADY_SUBMITTEDAn active application already exists for that tax ID or control person. Cancel or await the existing one.
A reliance report didn’t clear the identity requirementOnboard with KYC Reliance — acceptance and rejection expectations
A required document is missing or has the wrong purposeDOCUMENTATION_REQUIRED
An operation failed because the customer isn’t active yetCUSTOMER_NOT_ONBOARDED

Where to go next