Browse help guides
KYC
KYC in Open Dram
How users, KYC records, methods and your Sumsub connection fit together, and which statuses a user moves through.
The words
| In the app | In the vault | Meaning |
|---|---|---|
| User | subjects/SUB-….md | The person or company you serve. |
| KYC record | an applicant in kyc/events.jsonl | One verification attempt on that user. |
| Method | applicant provider + flow | How the attempt is done: Sumsub link, Manual, or none. |
| Connection | config/kyc.yaml + the OS keychain | Your own Sumsub keys (bring your own key, BYOK). |
A user can exist with no KYC at all — the badge then reads Not started. A user can have many KYC records over time; the latest one is the current record and drives the badge.
The whole desk at a glance
flowchart LR
subgraph settings ["Settings"]
S["Integrations · Sumsub"]
end
subgraph create ["Users · New user"]
T{"Person or company"}
T --> I["Person fields"]
T --> C["Company fields"]
I --> D{"Default KYC method"}
C --> D
D -->|"Sumsub connected"| SS["Create + Sumsub link"]
D -->|"Manual"| M["Create + manual KYC"]
D -->|"Skip"| U["Create user only"]
end
subgraph userpage ["User page"]
P["Badge: KYC status"]
P --> F["Fetch / new link"]
P --> FB["Fall back to manual"]
P --> TX["Book trade"]
end
S -.->|"level + keys"| SS
SS --> P
M --> P
U --> P
TX -->|"approved or compliance override"| L["Transaction posted"]KYC statuses
| Status | What it means |
|---|---|
| Not started | No KYC yet, or Sumsub did not start. |
| Link sent | A Sumsub link exists; the client has not finished. |
| Pending | Sumsub is reviewing, or staff saved a manual decision as pending. |
| Needs documents | Sumsub asked for a retry (RED + RETRY) or staff asked for more. |
| Approved | Verified. The user can be booked. |
| Approved (overridden) | Approved by compliance or the owner with a written reason, not by Sumsub. |
| Rejected | Final refusal (RED + FINAL) or a manual rejection with a reason. |
| Expired | A decision that has lapsed and needs renewal. |
stateDiagram-v2
state "Not started" as not_started
state "Link sent" as link_issued
state "Pending" as pending
state "Needs documents" as need_docs
state "Approved" as approved
state "Rejected" as rejected
state "Approved (overridden)" as overridden
[*] --> not_started: skip or Sumsub failed
[*] --> link_issued: Sumsub link minted
[*] --> pending: manual saved as pending
not_started --> link_issued: Retry Sumsub
not_started --> approved: manual approve
not_started --> rejected: manual reject
link_issued --> pending: Fetch status
link_issued --> not_started: link expired
pending --> approved
pending --> need_docs
pending --> rejected
need_docs --> link_issued: new link
need_docs --> overridden: compliance override
not_started --> overridden: compliance override
approved --> overridden: compliance changes decisionWhere each journey leaves the user
| Journey | KYC status | Method on the current record | Can be booked |
|---|---|---|---|
| Sumsub link sent, client not finished | Link sent | Sumsub | No |
| Sumsub GREEN, then Fetch | Approved | Sumsub | Yes |
| Sumsub failed, not retried | Not started | none | No |
| …then manual approve | Approved | Manual | Yes |
| Create without KYC | Not started | none | No |
| Manual KYC on create | Staff choice | Manual | Only if approved |
| Compliance override | Approved (overridden) | unchanged | Yes |
Decisions this design follows
- One Sumsub connection and one level name for the whole desk. No per-user level.
- The default method is chosen once in Settings. The new-user form never opens with a method picker.
- Manual KYC is always available as a fallback — on the new-user form and on the user page.
- “Create without KYC” is always shown. It saves the user at Not started.
- People and companies are both supported; the form asks which first.
- If Sumsub fails, the user is still saved (Not started) and the page offers Retry Sumsub or Manual.
- Operators cannot book until KYC is approved. Compliance or the owner can override with a reason: the KYC event is written first, then the trade.
- Webhooks are optional; on desktop, Fetch status is the path that always works.
Something missing or out of date? Send feedback.
