Skip to main content

Creating a verification

POST /verifications names one of your workflows by workflow_key. What else it takes depends on that workflow’s mode: a hosted workflow takes the user’s mobile, which they sign in to the journey with, and may take a return_url; a staged workflow opens no journey, so it takes neither, and a call that names either is refused with 400. Creating is idempotent per subject and workflow. On a hosted workflow the same phone number in the same workflow always resolves to the same verification; on a staged workflow the same reference_user_id does. A retry returns the existing record as it stands, whatever its status, so a repeat call is a safe retry rather than a way to change a verification already under way. To run the same subject through again, reset the existing verification. The status code says which of the two you got. 201 means the call created the verification. 200 means this subject already had one in this workflow and you are reading that record back: nothing was created and nothing changed. Read its status before acting on it, because a record already submitted or completed is not waiting for anyone. Where you expected a new verification, a 200 is how you find out the same subject has reached you twice. A create is held to the workflow’s credits and to how many verifications it may have going at once. A workflow with no credits left refuses it with 402, and one already at its live ceiling with 409. Only a call that would create a verification is refused: one that resolves to a record you already have answers 200 as it always does, so a retry never turns into a payment error. See Credits and limits. context is facts you already know about the subject, and it is fixed for the life of the verification: a reset preserves it, and nothing can add to it afterwards. Where a workflow has a required step that reads one of these fields and cannot run without it, creating one without that field is rejected with 400, and the detail names every field that was missing. A field you do supply is held to the step that reads it. One in a shape that step cannot use is rejected with 400 too, naming the field and the step, because a value only the journey would have choked on is worth hearing about from the call that sent it. Fields no step reads are yours to use as you like, and are echoed back untouched. On a hosted workflow the response includes journey_url, the address the journey is walked at, and return_url must match one of the URLs registered for that workflow. On a staged workflow journey_url, mobile and return_url are all null: nobody is sent anywhere.

Which workflows you can name

GET /workflows lists the keys you can create against, with the mode, retention window and step count of each. To see what one of them will ask for before creating anything on it, read the workflow itself with GET /workflows/{workflow_key}. It returns every step the workflow can present, in the order they are answered, each with the condition that gates it and an intake saying how it is answered over the API. A step also carries a label, which is your own name for it where your workflow is configured with one, and the kinds of document its slots take carry theirs. A label is a name for your own records rather than wording for a screen: nothing is addressed by it, and the key remains what names a step everywhere. Several steps may share a label on purpose. A workflow that asks a sole proprietor, a partner and a director each for a PAN declares three steps, because the condition gating each is different, and one of them runs; giving all three the same label is how you read the PAN off the record without knowing which. The wording the person being verified reads is theirs, so no step’s intake carries it. Custom output transformations do the same one level down, for the fields a step publishes. The mode, the step keys and the intake are stable. The rest is a reference view of configuration we maintain and it changes without notice, so read it to understand a journey rather than to build behaviour against it; Step types says more. Any one verification walks some of those steps rather than all of them, and its record reports the ones it walked.

Versions

A change to a workflow is published as its next version, and a verification keeps the version it was created on. Versions are numbered from 1. GET /workflows and GET /workflows/{workflow_key} report the latest version as version, and that is the version a verification created now runs. Every verification says which version it runs in a version of its own, and so does the callback its submission sends. A version published after a verification was created never changes it: not what it asks for, not which steps its record reports, not the names its outputs arrive under, and not how long it holds data. A subject partway through a journey finishes the one they started, and a finished record reads the same for as long as you keep it. Creating a verification for a subject who already has one answers that record, on its own version, and is never refused for a field of context only a later version reads. GET /workflows/{workflow_key}/versions lists every version a workflow has published, newest first, and GET /workflows/{workflow_key}/versions/{version} reads one of them as it was published. Read the version a verification names to see the journey it runs, and read two to see what changed between them: a version reports its steps exactly as the workflow reports its latest one’s, so they compare field for field. A workflow taken out of use keeps its versions readable for the verifications that ran them. Resetting a verification is how you move it onto the latest version: the reset clears everything and reopens the verification there, so its version moves on with it. What to do about verifications left on an earlier version is up to you: let them finish, reset them, or purge them. Where the latest version reads a context field the verification was not created with, the reset is refused with 400 and the verification stays on its version; purge it and create a new one with that context instead.

Identifiers

Creating a verification whose reference_user_id already belongs to a different user in that hosted workflow is refused with 409, naming the verification that holds it. The same subject in a second workflow keeps the same reference: that is a verification of its own.

Statuses

A verification has six statuses, and they mean the same thing however the documents arrived. Five of them say how the run ended; the sixth, expired, says the record is past its useful life and is kept for your audit alone. open covers two situations that look different from outside: a person still working through a journey, and a staged submission being assembled or having its checks run. Both amount to the same thing, which is that the verification is not settled yet. On a staged verification, run_requested_at says which: null while you are still uploading, set from the moment you asked for the checks to run. Each ending also settles what the run cost. Reaching completed, cancelled or expired uses one credit of the workflow’s balance; gated and failed use none, and neither does a record still open or submitted. credits_consumed on the record counts what it has used, over every run of it. See What uses a credit. A hosted journey cannot be submitted while any step is unanswered, still being checked, or unresolved after a check that could not run. A submission you sent is submitted by the run once every step has settled, or once the run gives up on a source it could not reach, in which case that step reads error. Either way no step’s outcome changes between submitted and completed. Poll GET /verifications/{verification_id} until it reads completed, cancelled, gated or failed. To see how many of your verifications stand in each status, or to list the ones that stand in a particular one, see Tracking verifications.

Expiry supersedes every ending

expired is not one ending among the others. Whatever a verification ended as, it expires once its retention window runs out, or the moment you purge it:
A record does not keep the status it earned. A verification that completed reads completed until it expires, and expired from then on. So status == "completed" is not a durable test for “did this finish?” - read completed_at for that, and treat status as the answer to “can I still use this record?”

Timestamps

Timestamps are in IST. Each ending stamps its own on the way past, and those survive expiry, so nothing about how a run ended is lost: A verification that was never submitted, cancelled, gated or failed carries none of those endings, which is how an abandoned journey reads: expired with nothing before it. last_activity_at is when the verification was last acted on, which on one nobody has touched is the moment you created it. Read it to tell a journey that is moving from one that has stopped. Together with expires_after_days, the window the record’s own version holds it to, it says when a verification left untouched expires.

Ending or restarting

Reset is the one operation that clears what was collected without deleting the record’s data for good, and it is how you run a cancelled, completed, gated or failed verification through again. Purge is how you delete the data before the window would. An expired verification cannot be reset, whether it expired on the window or you purged it. Expiring deletes the subject’s sign-in along with the rest of their data, so by the time the status reads expired there is nobody a reopened journey could sign in. Verify that subject again by creating a new verification.

Expiry and retention

Every workflow expires a verification after a set period of inactivity, and none of them can hold data indefinitely. How long is configured per workflow, anywhere from 1 to 120 days, so different journeys on your account can hold data for different lengths of time. Tell us what each of yours needs and we set it when we publish them; a workflow that asks for nothing in particular gets 30 days. Each verification is held for as long as the version it runs says, and reports that window on its record as expires_after_days. A change to the window reaches the verifications created or reset after it and never one already under way, so read a verification’s window off the verification: expires_after_days on a workflow is its latest version’s, which a record on an earlier version may not be held to. Expiring is one act, not two: the data is deleted and the record is marked expired in the same moment. Purging is the same act at the moment you ask for it. The window is counted from last_activity_at, so it limits how long a verification may be idle rather than how long anyone may take over it. On a hosted workflow every answer, upload and withdrawal moves that moment forward, and a check still running against a source does not. On a staged workflow your uploads, withdrawals and run request move it forward, and so does the run of the checks. A verification you create and nobody touches counts as idle from the moment you created it.

What is deleted

Everything the subject provided: their answers, the values read off their documents, the files themselves, their mobile number, the context you supplied when creating it, and the values you sent with the run request.
This applies to completed verifications too, on the same window. Download the documents and read the record you need before it passes: nothing is recoverable afterwards.

What survives

A record of what the system did, not of the person it did it to: the id, your reference_user_id, the workflow_key and mode, every timestamp the run collected, what expired it, the callback outcome, and what each step concluded - every step’s state and the reason codes behind it, frozen at the moment of expiry. So an expired record still answers “did this subject pass, and on which step did they not?” while holding nothing about them. It reports no collected data and no documents, and asking to download its files links nothing. Together, reference_user_id and workflow_key are the handle on an expired record, which is why the reference is required and unique within a workflow. Keep your own copy of anything else you need to tie a record back to a person.

Coming back afterwards

Before the window closes, a reset reopens a verification whatever state it reached and starts the window afresh, so a subject who went quiet can be sent through again. What a reset clears stays cleared: they provide it again. After the window closes, or after a purge, verify that subject again by creating a new verification. An expired record keeps its reference_user_id for your audit but no longer holds the name against a live one, so create it under the same reference you used before. You get a fresh record, and the expired one stays readable alongside it.