Skip to main content
For trying the API. Every block below is a notebook cell: open a Jupyter notebook, save a few real documents beside it, and run the cells in order. Nothing here is an integration pattern, just the shortest path to seeing a real record. You need a workflow whose mode is staged. GET /workflows lists yours with the mode of each, along with how many credits each has left. Reach for your uat key, whose token begins uat_, so the run below comes out of a uat workflow’s credits rather than out of what you bought for real work. Whichever key you use, the keys below are placeholders for your own, and a uat workflow’s key ends -uat. The verification is real either way. There is no sandbox: your documents really are read, and really are confirmed with the bodies that issued them.
Already keep the key in your environment? Drop the assignment and the client picks it up from the kernel. Nothing but the client reads it, so a plain api_key = "your key" variable does the job just as well.
Every error comes back as {"detail": "..."}. A cell that fails raises on the response it already kept in response, so response.json()["detail"] in a new cell says what went wrong.

1. See what the workflow asks for

Before uploading anything, read the workflow. Its mode says whether you run it, and each step’s intake says exactly how it is answered: the slots its documents go in, the kinds of document each slot takes, with how many files each kind arrives as and in what formats, and the values it takes in the run request. A kind’s label is your own name for that document where your workflow gives it one, and null where it does not; the wording the person providing it reads belongs to their screens, not to this API.
required is what decides whether you can leave a document out, and step 8 depends on it. The cross-check lists no slots and no values: it is answered from what the earlier steps establish, so you send nothing for it.
A workflow whose mode is hosted is walked by the person being verified, not run by you. Uploading to one, or running its checks, is refused with 409. See the other recipe.

2. Create a verification

reference_user_id is your own identifier for the subject. On a staged workflow it is also what makes creating idempotent, and the handle that survives once the verification’s data has been deleted, so make it something you can reconcile against your own records. There is no user to sign in, so there is no mobile number to give.
A 402 here means the workflow has no credits left, and a 409 that it already has as many verifications going as it may. Read the workflow to see which: credits.remaining and runs. Neither clears by retrying. See Credits and limits. The credit is used when the verification ends, not here, so the record you just created reads credits_consumed: 0 until step 8 completes it.

3. Upload the documents

One call per file, naming the step and slot from step 1, with each path relative to the notebook.
Send several files to the same slot where it takes several. Nothing is read from a document as it arrives, so upload everything before the next step. Run the cell twice and the second upload is refused with 422 wherever the slot already holds as many files as it takes. Withdraw the file below, or reset as in step 7. The bank step is left out on purpose: it takes typed details or a document, and the run request below sends the details. To answer it with a cancelled cheque instead, upload one to its bank-account-proof slot with "kind": "cheque", since that slot names more than one kind of proof, and send no bank entry in step 4.
A file the step cannot use is refused on its own call: 415 for a format the slot does not take, 413 for one over the size limit, which is 20 MB for a PDF and 10 MB for an image. Nothing else you uploaded is affected.
Uploaded the wrong file? Withdraw it by its id, which the cell above kept, and the slot has room again.

4. Run the checks

One request says the submission is complete. Steps whose intake.values names values take them here; every other step is answered from its documents.
Had you uploaded a cancelled cheque or bank statement to the bank step instead, you would drop the bank entry and send {"steps": {}}: the document answers the step, and sending both is refused. This returns as soon as the request is accepted, with run_requested_at set. From that moment the submission is frozen: uploads and withdrawals are refused until you reset. The checks run after it. One request answers the whole submission; there is no call that runs a single step.

5. Watch it settle

Poll until the verification leaves open. The checks are document reads and calls to the issuing registries, so give it a minute.
The cell holds the kernel while it polls, and stops after five minutes rather than running for ever. Still open when it stops? Run it again: reading a verification changes nothing, and the last record it read is what the cells below use.

6. Read what it found

Every step reports a state and, where it did not pass cleanly, the reasons why.
A run worth a second look
A step that passed with a gap is the case worth routing to a person: every document is real and confirmed at source, but something is not an exact match. A step that failed carries the reasons it did not stand up. A step in error was never checked, because a source could not be reached. Cross-check scores are on the step’s outputs, if you want the numbers rather than the sentences:

7. Go round again

Reset clears every answer, every file and the run request, and reopens the verification, so you can try different documents without creating a new one.
Creating is idempotent per reference and workflow, so calling step 2 again returns this same verification rather than a fresh one, answering 200 instead of 201 to tell you so. Reset is how you get a clean run. To work out which of several documents is the problem, reset and send fewer. Send at least two, though: a cross-check scores names against one another, so on a round with one document it has nothing to compare and drops out of the record. Each round here clears a run nothing was charged for, so it draws one of the workflow’s resets. Watch resets.remaining while you iterate, and see When the resets run out.

8. See what a bad submission does

Reset once more so nothing is uploaded, and run the checks on that.
What comes back depends on your workflow. Where a document is required, the run is refused with 422 before anything runs, naming every step that has nothing - so nothing was charged for and nothing was checked:
Where every document is optional, an empty submission is a valid one: the run is accepted and settles with each step not-supplied and nothing checked. It reads completed with no failures, which is not the same as a business that passed, so read progress and the step states rather than the status alone. The 422 also covers a slot you filled only part of, which reads gst: slot 'gst-certificate' needs 2 more file(s), and a step given both values and a document. Correct the submission and ask again.
Run the checks on a verification that has already settled and you get 409 rather than 422: it is no longer open, so there is nothing to submit to. Reset it first, as above.

9. Purge it

When you are done, delete everything you supplied. The record stays readable, saying what each step concluded and that you asked for the purge, and holds nothing else.

The record you just read

The finished record behind the run above, from the vendor-verification workflow. Yours differs: which steps a verification runs comes from the workflow configured for your integration. The envelope around them is the same for everyone.
  • Nobody signs in, so mobile, return_url and journey_url are null, and run_requested_at records the moment you asked for the checks.
  • udyam is not-supplied. Nothing was uploaded to it and it is optional, so the run closed over it. collected is null, no source was called, and it is not a verdict about the business - only the absence of a check.
  • The cross-check passed with a gap. The bank returned AVESCO HOSPITEX where the business is registered as AVESCO HOSPITEX PRIVATE LIMITED: close enough not to be a different business, not close enough to call an exact match. outputs.reference names which name it scored against and outputs.matches carries the score behind every check, so you can route on the number rather than the sentence.
  • Take the bank details from outputs. answer holds what you sent; outputs holds what the bank confirmed, and registered_name is the bank’s own spelling.
Reading the result is the field-by-field reference for a step.
When you move from trying it to building against it, read Staged for what is decided for you and why, Callbacks, which is what you use instead of polling, and Going live before your first real subject.