POST /v1/kyc/start returns a docv object and the user finishes verification in a hosted flow you hand them. Neither one changes the four outcomes, and neither one makes the decision.
Before this page you need:
- a working start call you can drive to a
docvobject — see /kyc#start-a-verification, docv_eligible: trueon your start request, or you will never see the DocV flow,- the
kyc:writescope — see /connect#authentication, - a registered webhook, because the terminal outcome only arrives there — see /webhooks.
The DocV state machine
Set docv_eligible: true or you do not get this flow
Leaving docv_eligible unset does not skip document verification. It routes the same cases to manual review, 1–2 business days, with no user-facing step and no way for the user to unblock themselves.
Set it on every start request in every environment.
The state machine
Undefined is not a state we support. See Gaps.
Every value you can see
decision, status and subStatus are informational. Log them; do not branch on them.
The docv object
docv.url you send the user to, and docvTransactionToken, the transaction handle.
Whether
docvTransactionToken sits inside the docv object or at the top level of the response is not documented. Read it from both positions until your integration lead confirms which one ships.Integration points
sdkKey is always empty, which settles the client architecture: you cannot initialise a native Socure SDK. There is no key to initialise it with. Every platform opens the hosted URL.
Detecting submission: the 14-second trap
GET /v1/kyc/status keeps returning the docv object for roughly 14 seconds after the user submits their documents. During that window the response is indistinguishable from “has not started”.
Two failure modes fall out of this, and partners hit both:
- Polling immediately after the user says they are done, seeing the
docvobject, and telling the user the upload failed. - Re-issuing or re-opening the flow because the
docvobject is still present, which sends a user who has already submitted back into document capture.
- Treat your own front-end “finished” signal as a hint, not a fact. It tells you when to start polling, nothing more.
- Wait at least 14 seconds after that hint before you read anything into the
docvobject’s presence. - Poll
GET /v1/kyc/statuson a fixed interval and require thedocvobject to be absent on two consecutive polls before you treat the flow as left behind. - Treat
kyc.approved/kyc.rejectedas the only authoritative completion. There is no review webhook, so the intermediate states are poll-only.
Gaps: be explicit with your product team
State these as known unknowns in your design review rather than discovering them in production.- No published TTL for
docvTransactionTokenordocv.url. You cannot tell a user how long their link is good for, and you cannot expire it in your own UI on a matching timer. - No documented way to re-issue a DocV session after a user abandons it. There is no re-KYC and no reset either, so an abandoned flow has no published recovery path.
- An expired, un-submitted session has been observed returning
decision: ACCEPTwithstatus: CLOSEDand an emptyparticipantId. That is a bug, not a contract. Never treat anACCEPTwith an emptyparticipantIdas an approval — that is exactly the shape this bug produces, and it is also the shape a normal in-flight provisioning produces. Gate on thekyc.approvedwebhook and this bug cannot reach your users.
Prefill
Prefill is not on by default; confirm with your integration lead that it is enabled for your firm before you build against it. Prefill is an optional step that sits in front of the standard flow: the user gives a phone number and date of birth, confirms a one-time code, and you receive prefilled PII to submit toPOST /v1/kyc/start instead of asking them to type it.
Where prefill sits in the flow
1
Collect phone and date of birth
Two fields, not a full form. This is the whole point of prefill: the user types the minimum, not their address.
2
Request the one-time code
You post the phone number and date of birth. The user receives a code by SMS.
3
Verify the code
You post the code. On success you receive prefilled PII for that person.
4
Show the user what you got, then submit
Present the prefilled values for confirmation and correction, then call
POST /v1/kyc/start with them. Prefill does not verify anybody. The decision still comes from the standard flow and all four outcomes still apply.The SSN rule
The exchange account is derived from the end user’s SSN, and one SSN maps to exactly one exchange account platform-wide. That does not change under prefill: the national ID / SSN must still be present in the payload you send toPOST /v1/kyc/start, so keep that field on your form even when every other field arrives prefilled.
Running the prefill flow
OTP retries
No platform-enforced OTP limit is published — not a send cap, not a verification-attempt cap, not a code lifetime, and no statement of whether any of it is scoped per phone number, per user, per firm or globally. Do not read that as “unlimited”. Read it as “you own this, and you will be the one paying for the SMS”. Enforce your own budget in your own application, and make the numbers yours, not ours:- Cap sends per phone number over a rolling window, and make the resend button visibly disabled with a countdown.
- Cap verification attempts per issued code, then force a fresh send.
- Expire the code in your own UI on your own timer so the user sees a clear “code expired, send a new one” state rather than a generic failure.
- After your cap is reached, fall back to the standard flow on /kyc#start-a-verification and let the user type their details. Prefill is optional; never let it become a dead end.
OTP error cases
There is no published error catalogue for the OTP steps. In practice the cases you have to design a screen for are: wrong code, expired code, too many attempts, unreachable or non-mobile number, and a date of birth that does not match the phone number’s owner. You will be able to tell them apart only by inspecting the bodies you actually get back. Until the catalogue exists, treat the OTP steps defensively:- Log the full response body verbatim on every non-
200, including the status code. That log is currently the only way either side can identify a new OTP error case. - Do not map an unknown error onto “wrong code”. A user who is told their code is wrong will retype it and burn your attempt budget on a failure that was never about the code.
- Show one generic recoverable message plus a “enter your details instead” escape hatch, and keep the exact error in your logs.