Onboarding case ( onboarding_case )
A onboarding_case represents a business onboarding case. It drives an orchestration process that collects data, runs compliance checks, and reaches an approval or rejection decision. It also provides a URL to a User Journey completed by the subject.
Role
The onboarding case is the central object of KYC and KYB flows. It carries two distinct dimensions: the case lifecycle of the case — is it still active? — and the final decision . This separation distinguishes a case closed with rejection from a case canceled before any decision.
At creation, an orchestration process starts automatically. This process is responsible for collecting supporting documents, calling identity-verification providers, and concluding by attaching company and contact objects created during the process.
Identifier and structure
Every case has a stable identifier prefixed with obc_. The
The url field contains the User Journey URL returned directly in the creation response — no additional call is required to retrieve the link to send to the subject.
{
"object": "onboarding_case",
"id": "obc_3f8a1d9c2b4e7f6a",
"subject_type": "company",
"status": "open",
"decision_status": "pending",
"company_id": null,
"contact_id": null,
"process_definition_id": "prd_8a2b3c4d5e6f7a8b",
"process_instance_id": "pci_1b2c3d4e5f6a7b8c",
"process_status": "running",
"url": "https://onboarding.example.com/o/obc_3f8a…",
"initial_data": {
"company": {
"legal_name": "Dupont & Fils SARL",
"registration_number": "841234567",
"registration_country": "FR"
}
},
"dedupe_key": "source_reference:crm-prospect-00512",
"locale": "fr",
"return_url": "https://example.com/onboarding/return",
"source_reference": "CRM-PROSPECT-00512",
"metadata": {},
"checks": [],
"opened_at": "2026-06-17T09:00:00.000Z",
"closed_at": null,
"created_at": "2026-06-17T09:00:00.000Z",
"updated_at": "2026-06-17T09:00:00.000Z"
}Subject type
The field subject_type determines the nature of the subject being onboarded and resulting closure constraints.
| subject_type | Sujet | Required for approval |
|---|---|---|
company | Company (legal entity) | company_id must be populated |
individual | Particulier (personne physique) | company_id et contact_id must be populated |
The onboarding decision remains carried by the case through decision_status. It is not projected onto the company: multiple cases may coexist or be replayed, and policy authorizing a later operation belongs to the process or merchant.
Fields
| Field | Type | Description |
|---|---|---|
id | string | Case identifier (prefix `obc_`). |
object | string | Always "onboarding_case". |
merchant_id | string | Merchant owning the case. |
subject_type | enum | Subject type: `company` or `individual`. |
status | enum | Lifecycle: `open`, `completed`, `cancelled`. |
decision_status | enum | Final decision: `pending`, `approved`, `rejected`. |
company_id | string | Company attached to the case (`cmp_…`). May be null until resolution in the process. |
contact_id | string | Primary attached contact (`ctc_…`). Required for approved `individual` cases. |
process_definition_id | string | Onboarding process definition started (`prd_…`). |
process_instance_id | string | Process instance currently driving the case (`pci_…`). May change during corrective resume. |
process_status | enum | Execution state derived from the associated instance: `running`, `waiting`, `stopping`, `completed`, `failed`, `retry_exhausted`, `superseded`, `stopped`, or null. |
url | string | URL of the hosted onboarding experience. Returned in the creation response. |
initial_data | object | Prefill data injected into the process. See dedicated section. |
dedupe_key | string | Deduplication key. Automatically generated when absent. See dedicated section. |
locale | string | User Journey language (for example `fr`, `en`). |
return_url | string | Redirect URL after experience completion. |
source_reference | string | Reference in your system (CRM, internal case…). |
metadata | object | Flat map of `string | number | boolean` scalars, following the API metadata convention. |
checks | array | Compliance checks attached to the case. Included only on GET /:id. |
opened_at | datetime | Case opening date. |
closed_at | datetime | Closure date (final status). `null` while still open. |
created_at | datetime | Creation date. |
updated_at | datetime | Last update date. |
Lifecycle and decision
The field status describes the case lifecycle. The
decision_status field expresses the final decision. Only certain combinations are valid.
Combinaisons valides
| status | decision_status | Valide | Note |
|---|---|---|---|
open | pending | yes | Initial state. No decision made. |
completed | approved | yes | Favorable decision. Company (and contact for `individual`) required. |
completed | rejected | yes | Unfavorable decision. |
completed | pending | no | A `completed` case must carry a decision. |
cancelled | pending | yes | Cancellation without decision. `decision_status` cannot be non-pending. |
cancelled | approved/rejected | no | A canceled case cannot carry a decision. |
A case in a final status (completed or cancelled) can no longer be modified. When using the finalize_onboarding_casenode, the status parameter directly takes the decision value (
"approved" or "rejected"), not the case status — the node applies status: completed.
Associated process
A case created with an onboarding process exposes the instance currently driving it through process_instance_id. The
process_status gives the state of this instance. It is derived from the associated execution and remains distinct from status and
decision_status.
| Example | Interpretation |
|---|---|
status: open + process_status: running | The case is open and processing is underway. |
status: open + process_status: stopped | Execution was stopped, but the case was not automatically canceled. |
status: completed + decision_status: approved + process_status: completed | The case carries a favorable decision and execution is complete. |
A instance completed does not automatically approve or reject the case. An instance failed, retry_exhausted or
stopped does not automatically move it to cancelled. The
finalize_onboarding_case and explicit update nodes remain responsible for the decision and business lifecycle.
When a manual retry, a fork retry_step / skip_step or resumption of a user step creates a new instance to continue the same onboarding, process_instance_id switches to this new instance. It becomes the canonical execution of the case and process_status reflects its state. The old instance remains available for traceability.
See Errors and idempotency for resume and associated-instance transfer rules.
Initial data
The field initial_data allows pre-filling subject data before the process starts. This data is injected into the process as variables of type draft :
Key in initial_data | Process variable | Accepted fields |
|---|---|---|
initial_data.company | company_draft | legal_name, trade_name, legal_form, registration_number, registration_country, tax_identifier, registered_address, incorporation_date, share_capital, currency, is_buyer, is_supplier, source_reference, metadata |
initial_data.contact | contact_draft | full_name, first_name, last_name, email, phone, job_title, preferred_locale, source_reference, metadata |
These draft variables are available as soon as the process starts and may be passed to nodes create_company or create_contact to create the actual objects without asking again for already-known data.
Creation with prefilled initial data
POST /v1/onboarding-cases
{
"subject_type": "company",
"locale": "fr",
"source_reference": "CRM-PROSPECT-00512",
"initial_data": {
"company": {
"legal_name": "Dupont & Fils SARL",
"registration_number": "841234567",
"registration_country": "FR",
"is_buyer": true
}
}
}Deduplication
The platform prevents opening several active cases for the same subject. Detection relies on a deduplication key (dedupe_key).
When dedupe_key is not supplied, it is automatically generated according to this priority:
source_reference:<normalized value>— whensource_referenceis presentperson_company:<email>:<country>:<number>— when email and company number are present ininitial_datacompany_registration:<country>:<number>— when only company number is availableperson_email:<email>— when only email is available
If an active case (status: open) already exists with the same key, creation returns an error 409 :
409 Conflict
{
"error": {
"message": "An active onboarding case already exists for this dedupe key"
}
}To bypass deduplication in specific cases, for example intentional re-onboarding, pass a dedupe_key random unique value on every creation.
Compliance checks
Each case carries an array checks of compliance checks performed during the process. These checks are available on
GET /v1/onboarding-cases/:id (not included in the list).
Every check records a verification result with its provider, scope, verified subject, and timestamp. Possible results are:
| Result | Meaning |
|---|---|
pending | Verification awaiting result |
passed | Verification successful |
failed | Verification failed |
manual_review | Ambiguous result requiring manual review |
error | Technical error during verification |
The node create_compliance_check lets the process record a verification trace. It accepts as subject (subject) a company, contact, or contact_role. The check_type
field may take free-form values (for example kyc, kyb,
sanctions, pep).
In processes
The case is automatically injected as input to the onboarding process under the variable onboarding_case (type
platform.onboarding_case). Five nodes can operate it:
| Node | Role | Key inputs / outputs |
|---|---|---|
finalize_onboarding_case | Resolves subjects, attaches them, and applies the final decision — recommended pattern | Accepts: onboarding_case, status (approved | rejected), company?, contact? · Produces: onboarding_case, company, contact |
update_onboarding_case_status | Updates status and/or decision_status | Accepts: onboarding_case, status (open | completed | cancelled), decision_status? · Produces: onboarding_case |
update_onboarding_case_subject | Attaches a company and/or contact to the case without closing it | Accepts: onboarding_case, company?, contact?, source_reference, dedupe_key · Produces: onboarding_case |
create_compliance_check | Records a compliance check on a subject, with optional attachment to the case | Accepts: onboarding_case?, scope, subject, check_type, provider?, result, raw_response?, valid_until? · Produces: compliance_check |
has_already_onboarded | Checks whether the company already has an approved and closed onboarding | Accepts: company, contact? · Route yes (produces onboarding_case, completed_at) / no |
In the finalize_onboarding_case node, status takes
"approved" or "rejected" (the decision),
not "completed". The node itself applies
status: completed and resolves the subjects in one operation. Use
update_onboarding_case_status only when attachment logic has already been handled separately.
Events
| Event | Trigger |
|---|---|
onboarding_case.company.created | Case created with `subject_type = company`. |
onboarding_case.individual.created | Case created with `subject_type = individual`. |
onboarding_case.completed | Case closed with `decision_status = approved`. |
onboarding_case.rejected | Case closed with `decision_status = rejected`. |
The creation event is differentiated by subject_type, allowing distinct onboarding processes by subject nature without extra trigger filtering. Transitioning to
cancelled does not emit a dedicated event.
L'endpoint GET /v1/onboarding-cases/search lets you retrieve the latest completed and approved case for a given company and optionally contact without traversing the paginated list:
GET /v1/onboarding-cases/search?company_id=cmp_3a8f
{
"object": "onboarding_case_search_result",
"onboarding_case": {
"id": "obc_3f8a",
"status": "completed"
},
"completed_at": "2026-01-15T14:30:00.000Z"
}