curl --request POST \
--url https://api.verify.privue.ai/verifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"context": {
"channel": "field-sales",
"state": "MH"
},
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"return_url": "https://yourapp.com/kyc/done",
"workflow_key": "merchant-onboarding"
}
'import requests
url = "https://api.verify.privue.ai/verifications"
payload = {
"context": {
"channel": "field-sales",
"state": "MH"
},
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"return_url": "https://yourapp.com/kyc/done",
"workflow_key": "merchant-onboarding"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
context: {channel: 'field-sales', state: 'MH'},
mobile: '+919876543210',
reference_user_id: 'merchant-42',
return_url: 'https://yourapp.com/kyc/done',
workflow_key: 'merchant-onboarding'
})
};
fetch('https://api.verify.privue.ai/verifications', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"mode": "hosted",
"status": "completed",
"workflow_key": "merchant-onboarding",
"version": 2,
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"context": {
"channel": "field-sales",
"state": "MH"
},
"return_url": "https://yourapp.com/kyc/done",
"journey_url": "https://verify.privue.ai/acme/merchant-onboarding",
"created_at": "2026-08-10T14:02:11",
"last_activity_at": "2026-08-10T14:41:06",
"expires_after_days": 30,
"run_requested_at": null,
"submitted_at": "2026-08-10T14:41:06",
"completed_at": "2026-08-10T14:41:09",
"cancelled_at": null,
"gated_at": null,
"gated_by_step": null,
"failed_at": null,
"expired_at": null,
"expired_by": null,
"acknowledgement": null,
"callback": {
"status": "delivered",
"settled_at": "2026-08-10T14:41:09",
"reason": null
},
"credits_consumed": 1,
"resets": 0,
"progress": {
"total": 12,
"passed": 10,
"failed": 0,
"awaiting": 0,
"enriching": 0,
"error": 0,
"declined": 1,
"not_supplied": 0,
"undetermined": 0,
"not_applicable": 1
},
"steps": [
{
"key": "contact",
"title": "Before we start",
"label": "contact_email",
"type": "form",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"email": "owner@acmetraders.in"
},
"outputs": {
"email": "owner@acmetraders.in"
}
},
"documents": []
},
{
"key": "gst",
"title": "GST certificate",
"label": "tax_registration",
"type": "gst-certificate",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"gstin": "27AABCA1234F1Z5",
"legal_name": "ACME TRADERS PRIVATE LIMITED",
"trade_name": "Acme Traders",
"registration_status": "Active",
"registration_date": "2020-01-13",
"business_constitution": "Private Limited Company",
"taxpayer_type": "Regular",
"e_invoice_mandated": true,
"aggregate_turnover": "Slab: Rs. 5 Cr. to 25 Cr.",
"authorized_signatories": [
"Rahul Mehta",
"Priya Mehta"
],
"nature_of_business_activities": [
"Wholesale Business",
"Warehouse / Depot"
],
"business_details": {
"goods_details": [
{
"goods_description": "Filtering machinery",
"hsn_code": "84212190"
}
],
"service_details": []
},
"filings": [
{
"return_type": "GSTR1",
"financial_year": "2026-2027",
"tax_period": "May",
"status": "Filed",
"filing_date": "2026-06-04",
"mode_of_filing": "ONLINE"
},
{
"return_type": "GSTR3B",
"financial_year": "2026-2027",
"tax_period": "May",
"status": "Filed",
"filing_date": "2026-06-23",
"mode_of_filing": "ONLINE"
},
{
"return_type": "GSTR9",
"financial_year": "2024-2025",
"tax_period": "Annual",
"status": "Filed",
"filing_date": "2025-12-18",
"mode_of_filing": "ONLINE"
}
],
"business_pan": "AABCA1234F",
"sole_proprietor_pan": null,
"addresses": [
{
"address": "12 Industrial Estate, Pune, Maharashtra 411026",
"tag": "Principal Business Address"
}
],
"primary_business_address": {
"street": "12 Industrial Estate",
"city": "Pune",
"state": "Maharashtra",
"country": "India",
"postal_code": "411026"
},
"other_business_address": null,
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "Legal Name"
},
{
"name": "Acme Traders",
"tag": "Trade Name"
}
],
"promoters": [
"Rahul Mehta",
"Priya Mehta"
],
"business_email": "accounts@acmetraders.in",
"business_mobile": "9820011223"
}
},
"documents": [
{
"id": "bb9909b4-44e4-414a-af82-bad690d434ed",
"slot": "gst-certificate",
"kind": "gst-certificate",
"label": "gst_certificate",
"filename": "gst-certificate.pdf",
"content_type": "application/pdf",
"size_bytes": 182044,
"sha256": "63f90f32e899197edb4f038322e354f3c6b907602a44a58a0ae52b40a2cd9811",
"received_at": "2026-08-10T14:21:58"
}
]
},
{
"key": "pan",
"title": "PAN card",
"label": "entity_pan",
"type": "pan-card",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"pan": "AABCA1234F",
"name": "ACME TRADERS PRIVATE LIMITED",
"date_of_birth_or_incorporation": "2011-06-14",
"card_document_id": "4fd79a54-a8a7-4e07-b902-a2e75af3e467",
"status": "valid",
"aadhaar_seeded": null,
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "PAN Holder"
}
]
}
},
"documents": [
{
"id": "4fd79a54-a8a7-4e07-b902-a2e75af3e467",
"slot": "pan-card",
"kind": "pan-card",
"label": "entity_pan",
"filename": "pan-card.jpg",
"content_type": "image/jpeg",
"size_bytes": 92412,
"sha256": "42b7e28cf9a26dcef6e275de42f7516ad36ee86c6aa45888821a81217e62a670",
"received_at": "2026-08-10T14:09:12"
}
]
},
{
"key": "identity",
"title": "Identity",
"label": null,
"type": "digilocker",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [
{
"code": "digilocker-document-missing",
"message": "Your pan document was not shared from DigiLocker.",
"details": {
"doc_type": "pan"
}
}
],
"collected": {
"answer": {
"session_id": "e0d4a1f6-7c93-4b28-9f51-3a8c62d0be47"
},
"outputs": {
"name": "Rahul Mehta",
"names": [
{
"name": "Rahul Mehta",
"tag": "DigiLocker Holder"
}
],
"email": "rahul.mehta@example.com",
"mobile": "9876543210",
"date_of_birth": "14/03/1986",
"gender": "Male",
"pan": null,
"masked_aadhaar": "XXXXXXXX4172",
"photo_document_id": "c48b2e57-9a10-4d3f-b6e8-1f7c9a05d24b"
}
},
"documents": [
{
"id": "7e5c1a90-2f83-4a12-9c47-6d0b58e2af31",
"slot": "digilocker-docs",
"kind": "aadhaar",
"label": null,
"filename": "aadhaar.pdf",
"content_type": "application/pdf",
"size_bytes": 148820,
"sha256": "e17c4b8025d9a63f04e7b158c92da370465f8b1e07c3d924a6b508f1c73e2d05",
"received_at": "2026-08-10T14:14:37"
},
{
"id": "c48b2e57-9a10-4d3f-b6e8-1f7c9a05d24b",
"slot": "digilocker-docs",
"kind": "photo",
"label": null,
"filename": "photo.jpg",
"content_type": "image/jpeg",
"size_bytes": 18734,
"sha256": "b8043f7e1c592a6d0e34b871f5c9d206a47e3b9018c5d62faf7b04e39c1a5867",
"received_at": "2026-08-10T14:14:38"
}
]
},
{
"key": "selfie",
"title": "Selfie",
"label": null,
"type": "selfie",
"required": false,
"state": "declined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "bank",
"title": "Bank account",
"label": "payout_account",
"type": "bank-account",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"source": "typed",
"account_number": "50100234567890",
"ifsc": "HDFC0001234"
},
"outputs": {
"source": "typed",
"account_number": "50100234567890",
"ifsc": "HDFC0001234",
"registered_name": "ACME TRADERS PRIVATE LIMITED",
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "Bank Account Holder"
}
],
"bank_name": null,
"branch": null
}
},
"documents": []
},
{
"key": "trade-licence",
"title": "Trade licence",
"label": null,
"type": "documents",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {}
},
"documents": [
{
"id": "2a6f8d13-4c95-4e7b-8f30-5b1e6c9a7d02",
"slot": "licence",
"kind": "licence",
"label": "trade_licence",
"filename": "shop-establishment-licence.pdf",
"content_type": "application/pdf",
"size_bytes": 221893,
"sha256": "0a9c7f1b5e2d48a6c3f07b91d4e85a2c6f13b8074de92a5c1f6b3e08d7a24c95",
"received_at": "2026-08-10T14:27:03"
},
{
"id": "8b31c4e6-7d92-4a58-b0f1-3e6d2c94a17f",
"slot": "lease",
"kind": "lease",
"label": "lease_agreement",
"filename": "lease-agreement.pdf",
"content_type": "application/pdf",
"size_bytes": 654201,
"sha256": "7d4e1c08b3a95f26d07e4b1a8c53f902e6b7d148a05c39f2b8e6104d7c3a95e2",
"received_at": "2026-08-10T14:28:44"
}
]
},
{
"key": "premises",
"title": "Premises photos",
"label": null,
"type": "premises-photos",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"locations": {
"5c9e07b2-8f41-4d6a-9e35-2b7a1c8f60d4": {
"latitude": 18.629812,
"longitude": 73.813104,
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"place_id": "ChIJhTQr8kW_wjsR1nQm2eF0hQY"
},
"e6142f8a-3b57-4c90-8d21-9a4f7e0b53c6": {
"latitude": 18.629774,
"longitude": 73.813251,
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"place_id": "ChIJhTQr8kW_wjsR1nQm2eF0hQY"
}
}
},
"outputs": {
"addresses": [
"12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India"
]
}
},
"documents": [
{
"id": "5c9e07b2-8f41-4d6a-9e35-2b7a1c8f60d4",
"slot": "storefront",
"kind": "storefront",
"label": "storefront_photo",
"filename": "storefront.jpg",
"content_type": "image/jpeg",
"size_bytes": 1442310,
"sha256": "c1f5b70e934a26d8071c4be95f3a20d7e846b1c95023f7ad6b48e01c9f735a26",
"received_at": "2026-08-10T14:33:19"
},
{
"id": "e6142f8a-3b57-4c90-8d21-9a4f7e0b53c6",
"slot": "interior",
"kind": "interior",
"label": "interior_photo",
"filename": "interior.jpg",
"content_type": "image/jpeg",
"size_bytes": 1180955,
"sha256": "9b0d3e64a17c58f2e40b96d7c85a13f0246e9b7d1c503a8f6b2e74d09c1a5837",
"received_at": "2026-08-10T14:34:02"
}
]
},
{
"key": "premises-proof",
"title": "Proof of premises",
"label": null,
"type": "address-proof",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"verified_tags": [
"Principal Business Address"
],
"unverified_tags": [],
"readings": [
{
"slot": "utility-bill",
"kind": "electricity",
"label": "electricity_bill",
"premises_address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"verified_tags": [
"Principal Business Address"
]
}
]
}
},
"documents": [
{
"id": "0c73de91-6a24-4b8f-95d0-7e41b25c8a63",
"slot": "utility-bill",
"kind": "electricity",
"label": "electricity_bill",
"filename": "electricity-bill.pdf",
"content_type": "application/pdf",
"size_bytes": 96410,
"sha256": "3e8b1d95c072a46f8b5309e7d41c6a28b90f7e35c1d84620a7f3b9e05d268c14",
"received_at": "2026-08-10T14:36:50"
}
]
},
{
"key": "addresses",
"title": "Tag the addresses",
"label": null,
"type": "address-tagging",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"addresses": []
},
"outputs": {
"addresses": [
{
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"tag": "Principal Business Address"
}
],
"recognised": [
"12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India"
]
}
},
"documents": []
},
{
"key": "review",
"title": "Review",
"label": "applicant_signoff",
"type": "review",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"declarations": [
{
"key": "terms-of-service",
"label": "tos_consent",
"title": "Terms of service",
"content": "I accept the [terms of service](https://yourapp.com/terms) and the [privacy policy](https://yourapp.com/privacy).",
"accepted": true
},
{
"key": "information-true",
"label": "truth_declaration",
"title": null,
"content": "Everything I have provided is true and correct to the best of my knowledge.",
"accepted": true
},
{
"key": "contact-on-whatsapp",
"label": "whatsapp_optin",
"title": null,
"content": "You may contact me about this application on WhatsApp.",
"accepted": false
}
]
},
"outputs": {}
},
"documents": []
}
]
}{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"mode": "hosted",
"status": "open",
"workflow_key": "merchant-onboarding",
"version": 2,
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"context": {
"channel": "field-sales",
"state": "MH"
},
"return_url": "https://yourapp.com/kyc/done",
"journey_url": "https://verify.privue.ai/acme/merchant-onboarding",
"created_at": "2026-08-10T14:02:11",
"last_activity_at": "2026-08-10T14:02:11",
"expires_after_days": 30,
"run_requested_at": null,
"submitted_at": null,
"completed_at": null,
"cancelled_at": null,
"gated_at": null,
"gated_by_step": null,
"failed_at": null,
"expired_at": null,
"expired_by": null,
"acknowledgement": null,
"callback": null,
"credits_consumed": 0,
"resets": 0,
"progress": {
"total": 12,
"passed": 0,
"failed": 0,
"awaiting": 8,
"enriching": 0,
"error": 0,
"declined": 0,
"not_supplied": 0,
"undetermined": 4,
"not_applicable": 0
},
"steps": [
{
"key": "contact",
"title": "Before we start",
"label": "contact_email",
"type": "form",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "gst",
"title": "GST certificate",
"label": "tax_registration",
"type": "gst-certificate",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "pan",
"title": "PAN card",
"label": "entity_pan",
"type": "pan-card",
"required": true,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "identity",
"title": "Identity",
"label": null,
"type": "digilocker",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "selfie",
"title": "Selfie",
"label": null,
"type": "selfie",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "bank",
"title": "Bank account",
"label": "payout_account",
"type": "bank-account",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "trade-licence",
"title": "Trade licence",
"label": null,
"type": "documents",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "premises",
"title": "Premises photos",
"label": null,
"type": "premises-photos",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "premises-proof",
"title": "Proof of premises",
"label": null,
"type": "address-proof",
"required": false,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "alt-business-proof",
"title": "Alternative proof of business",
"label": null,
"type": "documents",
"required": true,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "addresses",
"title": "Tag the addresses",
"label": null,
"type": "address-tagging",
"required": false,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "review",
"title": "Review",
"label": "applicant_signoff",
"type": "review",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
}
]
}{
"code": "mobile-required",
"detail": "workflow 'merchant-onboarding' is hosted, so creating one names the mobile number its user signs in with"
}{
"code": "unauthenticated",
"detail": "Missing or malformed Authorization header"
}{
"code": "credits-exhausted",
"detail": "the credits for workflow 'merchant-onboarding' are gone; of 500 granted, 500 used"
}{
"code": "environment-mismatch",
"detail": "workflow 'merchant-onboarding' is production and this request is for uat"
}{
"code": "reference-taken",
"detail": "reference_user_id 'merchant-42' already belongs to verification 3f2504e0-4f89-41d3-9a0c-0305e82c3301"
}{
"code": "request-invalid",
"detail": "mobile: String should match pattern '^(?:\\+91)?[6-9][0-9]{9}$'"
}{
"code": "rate-limited",
"detail": "Unauthorized: RATE_LIMITED"
}{
"code": "workflow-misconfigured",
"detail": "workflow 'merchant-onboarding' cannot ask its gate check 'gst-onboarded': the workflow registers no endpoint to ask its checks at"
}{
"code": "auth-unavailable",
"detail": "Auth provider unavailable"
}Create a verification
Create a verification on one of your workflows.
What creating one takes depends on the 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. An instant workflow is not created here at all: it is run in the one call that also creates its record, so naming one here is refused with 409.
Creating is idempotent per subject and workflow: repeating the call returns the existing verification, whatever its status, so retries are always safe. On a hosted workflow the subject is the user the mobile number names; on a staged workflow it is the reference_user_id. To run the same subject through again, reset the existing verification.
The status code tells the two apart. 201 means this call created the verification. 200 means this subject already had one in this workflow and you are reading that record back, so nothing was created and nothing was changed: check its status before acting on it, because a record already submitted or completed is not waiting for anyone. A verification you meant to be new that answers 200 is a sign the same subject reached you twice.
context is checked against the steps of the workflow’s latest version that read it. A field one of them needs and you left out is refused, and so is one supplied in a shape that step cannot read - both with 400, naming the field. Fields no step reads are yours to use as you like and are echoed back untouched. Only a call that creates a verification is checked: one that resolves to a record you already have answers 200 with that record, on the version it runs.
reference_user_id is yours and must be unique within the workflow. On a hosted workflow a retry of the same call resolves to the record already holding it, and a reference that belongs to a different user in that workflow is refused with 409. The same subject in a second workflow keeps the same reference, so the reference and the workflow key together always name one record for you to reconcile against.
A workflow with no prepaid credits left refuses a create with 402. 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. Read the workflow for its balance, and see credits there for how far past it a workflow may be committed before it stops.
curl --request POST \
--url https://api.verify.privue.ai/verifications \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"context": {
"channel": "field-sales",
"state": "MH"
},
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"return_url": "https://yourapp.com/kyc/done",
"workflow_key": "merchant-onboarding"
}
'import requests
url = "https://api.verify.privue.ai/verifications"
payload = {
"context": {
"channel": "field-sales",
"state": "MH"
},
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"return_url": "https://yourapp.com/kyc/done",
"workflow_key": "merchant-onboarding"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
context: {channel: 'field-sales', state: 'MH'},
mobile: '+919876543210',
reference_user_id: 'merchant-42',
return_url: 'https://yourapp.com/kyc/done',
workflow_key: 'merchant-onboarding'
})
};
fetch('https://api.verify.privue.ai/verifications', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"mode": "hosted",
"status": "completed",
"workflow_key": "merchant-onboarding",
"version": 2,
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"context": {
"channel": "field-sales",
"state": "MH"
},
"return_url": "https://yourapp.com/kyc/done",
"journey_url": "https://verify.privue.ai/acme/merchant-onboarding",
"created_at": "2026-08-10T14:02:11",
"last_activity_at": "2026-08-10T14:41:06",
"expires_after_days": 30,
"run_requested_at": null,
"submitted_at": "2026-08-10T14:41:06",
"completed_at": "2026-08-10T14:41:09",
"cancelled_at": null,
"gated_at": null,
"gated_by_step": null,
"failed_at": null,
"expired_at": null,
"expired_by": null,
"acknowledgement": null,
"callback": {
"status": "delivered",
"settled_at": "2026-08-10T14:41:09",
"reason": null
},
"credits_consumed": 1,
"resets": 0,
"progress": {
"total": 12,
"passed": 10,
"failed": 0,
"awaiting": 0,
"enriching": 0,
"error": 0,
"declined": 1,
"not_supplied": 0,
"undetermined": 0,
"not_applicable": 1
},
"steps": [
{
"key": "contact",
"title": "Before we start",
"label": "contact_email",
"type": "form",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"email": "owner@acmetraders.in"
},
"outputs": {
"email": "owner@acmetraders.in"
}
},
"documents": []
},
{
"key": "gst",
"title": "GST certificate",
"label": "tax_registration",
"type": "gst-certificate",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"gstin": "27AABCA1234F1Z5",
"legal_name": "ACME TRADERS PRIVATE LIMITED",
"trade_name": "Acme Traders",
"registration_status": "Active",
"registration_date": "2020-01-13",
"business_constitution": "Private Limited Company",
"taxpayer_type": "Regular",
"e_invoice_mandated": true,
"aggregate_turnover": "Slab: Rs. 5 Cr. to 25 Cr.",
"authorized_signatories": [
"Rahul Mehta",
"Priya Mehta"
],
"nature_of_business_activities": [
"Wholesale Business",
"Warehouse / Depot"
],
"business_details": {
"goods_details": [
{
"goods_description": "Filtering machinery",
"hsn_code": "84212190"
}
],
"service_details": []
},
"filings": [
{
"return_type": "GSTR1",
"financial_year": "2026-2027",
"tax_period": "May",
"status": "Filed",
"filing_date": "2026-06-04",
"mode_of_filing": "ONLINE"
},
{
"return_type": "GSTR3B",
"financial_year": "2026-2027",
"tax_period": "May",
"status": "Filed",
"filing_date": "2026-06-23",
"mode_of_filing": "ONLINE"
},
{
"return_type": "GSTR9",
"financial_year": "2024-2025",
"tax_period": "Annual",
"status": "Filed",
"filing_date": "2025-12-18",
"mode_of_filing": "ONLINE"
}
],
"business_pan": "AABCA1234F",
"sole_proprietor_pan": null,
"addresses": [
{
"address": "12 Industrial Estate, Pune, Maharashtra 411026",
"tag": "Principal Business Address"
}
],
"primary_business_address": {
"street": "12 Industrial Estate",
"city": "Pune",
"state": "Maharashtra",
"country": "India",
"postal_code": "411026"
},
"other_business_address": null,
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "Legal Name"
},
{
"name": "Acme Traders",
"tag": "Trade Name"
}
],
"promoters": [
"Rahul Mehta",
"Priya Mehta"
],
"business_email": "accounts@acmetraders.in",
"business_mobile": "9820011223"
}
},
"documents": [
{
"id": "bb9909b4-44e4-414a-af82-bad690d434ed",
"slot": "gst-certificate",
"kind": "gst-certificate",
"label": "gst_certificate",
"filename": "gst-certificate.pdf",
"content_type": "application/pdf",
"size_bytes": 182044,
"sha256": "63f90f32e899197edb4f038322e354f3c6b907602a44a58a0ae52b40a2cd9811",
"received_at": "2026-08-10T14:21:58"
}
]
},
{
"key": "pan",
"title": "PAN card",
"label": "entity_pan",
"type": "pan-card",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"pan": "AABCA1234F",
"name": "ACME TRADERS PRIVATE LIMITED",
"date_of_birth_or_incorporation": "2011-06-14",
"card_document_id": "4fd79a54-a8a7-4e07-b902-a2e75af3e467",
"status": "valid",
"aadhaar_seeded": null,
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "PAN Holder"
}
]
}
},
"documents": [
{
"id": "4fd79a54-a8a7-4e07-b902-a2e75af3e467",
"slot": "pan-card",
"kind": "pan-card",
"label": "entity_pan",
"filename": "pan-card.jpg",
"content_type": "image/jpeg",
"size_bytes": 92412,
"sha256": "42b7e28cf9a26dcef6e275de42f7516ad36ee86c6aa45888821a81217e62a670",
"received_at": "2026-08-10T14:09:12"
}
]
},
{
"key": "identity",
"title": "Identity",
"label": null,
"type": "digilocker",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [
{
"code": "digilocker-document-missing",
"message": "Your pan document was not shared from DigiLocker.",
"details": {
"doc_type": "pan"
}
}
],
"collected": {
"answer": {
"session_id": "e0d4a1f6-7c93-4b28-9f51-3a8c62d0be47"
},
"outputs": {
"name": "Rahul Mehta",
"names": [
{
"name": "Rahul Mehta",
"tag": "DigiLocker Holder"
}
],
"email": "rahul.mehta@example.com",
"mobile": "9876543210",
"date_of_birth": "14/03/1986",
"gender": "Male",
"pan": null,
"masked_aadhaar": "XXXXXXXX4172",
"photo_document_id": "c48b2e57-9a10-4d3f-b6e8-1f7c9a05d24b"
}
},
"documents": [
{
"id": "7e5c1a90-2f83-4a12-9c47-6d0b58e2af31",
"slot": "digilocker-docs",
"kind": "aadhaar",
"label": null,
"filename": "aadhaar.pdf",
"content_type": "application/pdf",
"size_bytes": 148820,
"sha256": "e17c4b8025d9a63f04e7b158c92da370465f8b1e07c3d924a6b508f1c73e2d05",
"received_at": "2026-08-10T14:14:37"
},
{
"id": "c48b2e57-9a10-4d3f-b6e8-1f7c9a05d24b",
"slot": "digilocker-docs",
"kind": "photo",
"label": null,
"filename": "photo.jpg",
"content_type": "image/jpeg",
"size_bytes": 18734,
"sha256": "b8043f7e1c592a6d0e34b871f5c9d206a47e3b9018c5d62faf7b04e39c1a5867",
"received_at": "2026-08-10T14:14:38"
}
]
},
{
"key": "selfie",
"title": "Selfie",
"label": null,
"type": "selfie",
"required": false,
"state": "declined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "bank",
"title": "Bank account",
"label": "payout_account",
"type": "bank-account",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"source": "typed",
"account_number": "50100234567890",
"ifsc": "HDFC0001234"
},
"outputs": {
"source": "typed",
"account_number": "50100234567890",
"ifsc": "HDFC0001234",
"registered_name": "ACME TRADERS PRIVATE LIMITED",
"names": [
{
"name": "ACME TRADERS PRIVATE LIMITED",
"tag": "Bank Account Holder"
}
],
"bank_name": null,
"branch": null
}
},
"documents": []
},
{
"key": "trade-licence",
"title": "Trade licence",
"label": null,
"type": "documents",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {}
},
"documents": [
{
"id": "2a6f8d13-4c95-4e7b-8f30-5b1e6c9a7d02",
"slot": "licence",
"kind": "licence",
"label": "trade_licence",
"filename": "shop-establishment-licence.pdf",
"content_type": "application/pdf",
"size_bytes": 221893,
"sha256": "0a9c7f1b5e2d48a6c3f07b91d4e85a2c6f13b8074de92a5c1f6b3e08d7a24c95",
"received_at": "2026-08-10T14:27:03"
},
{
"id": "8b31c4e6-7d92-4a58-b0f1-3e6d2c94a17f",
"slot": "lease",
"kind": "lease",
"label": "lease_agreement",
"filename": "lease-agreement.pdf",
"content_type": "application/pdf",
"size_bytes": 654201,
"sha256": "7d4e1c08b3a95f26d07e4b1a8c53f902e6b7d148a05c39f2b8e6104d7c3a95e2",
"received_at": "2026-08-10T14:28:44"
}
]
},
{
"key": "premises",
"title": "Premises photos",
"label": null,
"type": "premises-photos",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"locations": {
"5c9e07b2-8f41-4d6a-9e35-2b7a1c8f60d4": {
"latitude": 18.629812,
"longitude": 73.813104,
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"place_id": "ChIJhTQr8kW_wjsR1nQm2eF0hQY"
},
"e6142f8a-3b57-4c90-8d21-9a4f7e0b53c6": {
"latitude": 18.629774,
"longitude": 73.813251,
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"place_id": "ChIJhTQr8kW_wjsR1nQm2eF0hQY"
}
}
},
"outputs": {
"addresses": [
"12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India"
]
}
},
"documents": [
{
"id": "5c9e07b2-8f41-4d6a-9e35-2b7a1c8f60d4",
"slot": "storefront",
"kind": "storefront",
"label": "storefront_photo",
"filename": "storefront.jpg",
"content_type": "image/jpeg",
"size_bytes": 1442310,
"sha256": "c1f5b70e934a26d8071c4be95f3a20d7e846b1c95023f7ad6b48e01c9f735a26",
"received_at": "2026-08-10T14:33:19"
},
{
"id": "e6142f8a-3b57-4c90-8d21-9a4f7e0b53c6",
"slot": "interior",
"kind": "interior",
"label": "interior_photo",
"filename": "interior.jpg",
"content_type": "image/jpeg",
"size_bytes": 1180955,
"sha256": "9b0d3e64a17c58f2e40b96d7c85a13f0246e9b7d1c503a8f6b2e74d09c1a5837",
"received_at": "2026-08-10T14:34:02"
}
]
},
{
"key": "premises-proof",
"title": "Proof of premises",
"label": null,
"type": "address-proof",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {},
"outputs": {
"verified_tags": [
"Principal Business Address"
],
"unverified_tags": [],
"readings": [
{
"slot": "utility-bill",
"kind": "electricity",
"label": "electricity_bill",
"premises_address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"verified_tags": [
"Principal Business Address"
]
}
]
}
},
"documents": [
{
"id": "0c73de91-6a24-4b8f-95d0-7e41b25c8a63",
"slot": "utility-bill",
"kind": "electricity",
"label": "electricity_bill",
"filename": "electricity-bill.pdf",
"content_type": "application/pdf",
"size_bytes": 96410,
"sha256": "3e8b1d95c072a46f8b5309e7d41c6a28b90f7e35c1d84620a7f3b9e05d268c14",
"received_at": "2026-08-10T14:36:50"
}
]
},
{
"key": "addresses",
"title": "Tag the addresses",
"label": null,
"type": "address-tagging",
"required": false,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"addresses": []
},
"outputs": {
"addresses": [
{
"address": "12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India",
"tag": "Principal Business Address"
}
],
"recognised": [
"12, Industrial Estate Rd, Bhosari, Pune, Maharashtra 411026, India"
]
}
},
"documents": []
},
{
"key": "review",
"title": "Review",
"label": "applicant_signoff",
"type": "review",
"required": true,
"state": "passed",
"reasons": [],
"gaps": [],
"collected": {
"answer": {
"declarations": [
{
"key": "terms-of-service",
"label": "tos_consent",
"title": "Terms of service",
"content": "I accept the [terms of service](https://yourapp.com/terms) and the [privacy policy](https://yourapp.com/privacy).",
"accepted": true
},
{
"key": "information-true",
"label": "truth_declaration",
"title": null,
"content": "Everything I have provided is true and correct to the best of my knowledge.",
"accepted": true
},
{
"key": "contact-on-whatsapp",
"label": "whatsapp_optin",
"title": null,
"content": "You may contact me about this application on WhatsApp.",
"accepted": false
}
]
},
"outputs": {}
},
"documents": []
}
]
}{
"id": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"mode": "hosted",
"status": "open",
"workflow_key": "merchant-onboarding",
"version": 2,
"mobile": "+919876543210",
"reference_user_id": "merchant-42",
"context": {
"channel": "field-sales",
"state": "MH"
},
"return_url": "https://yourapp.com/kyc/done",
"journey_url": "https://verify.privue.ai/acme/merchant-onboarding",
"created_at": "2026-08-10T14:02:11",
"last_activity_at": "2026-08-10T14:02:11",
"expires_after_days": 30,
"run_requested_at": null,
"submitted_at": null,
"completed_at": null,
"cancelled_at": null,
"gated_at": null,
"gated_by_step": null,
"failed_at": null,
"expired_at": null,
"expired_by": null,
"acknowledgement": null,
"callback": null,
"credits_consumed": 0,
"resets": 0,
"progress": {
"total": 12,
"passed": 0,
"failed": 0,
"awaiting": 8,
"enriching": 0,
"error": 0,
"declined": 0,
"not_supplied": 0,
"undetermined": 4,
"not_applicable": 0
},
"steps": [
{
"key": "contact",
"title": "Before we start",
"label": "contact_email",
"type": "form",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "gst",
"title": "GST certificate",
"label": "tax_registration",
"type": "gst-certificate",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "pan",
"title": "PAN card",
"label": "entity_pan",
"type": "pan-card",
"required": true,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "identity",
"title": "Identity",
"label": null,
"type": "digilocker",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "selfie",
"title": "Selfie",
"label": null,
"type": "selfie",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "bank",
"title": "Bank account",
"label": "payout_account",
"type": "bank-account",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "trade-licence",
"title": "Trade licence",
"label": null,
"type": "documents",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "premises",
"title": "Premises photos",
"label": null,
"type": "premises-photos",
"required": false,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "premises-proof",
"title": "Proof of premises",
"label": null,
"type": "address-proof",
"required": false,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "alt-business-proof",
"title": "Alternative proof of business",
"label": null,
"type": "documents",
"required": true,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "addresses",
"title": "Tag the addresses",
"label": null,
"type": "address-tagging",
"required": false,
"state": "undetermined",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
},
{
"key": "review",
"title": "Review",
"label": "applicant_signoff",
"type": "review",
"required": true,
"state": "awaiting",
"reasons": [],
"gaps": [],
"collected": null,
"documents": []
}
]
}{
"code": "mobile-required",
"detail": "workflow 'merchant-onboarding' is hosted, so creating one names the mobile number its user signs in with"
}{
"code": "unauthenticated",
"detail": "Missing or malformed Authorization header"
}{
"code": "credits-exhausted",
"detail": "the credits for workflow 'merchant-onboarding' are gone; of 500 granted, 500 used"
}{
"code": "environment-mismatch",
"detail": "workflow 'merchant-onboarding' is production and this request is for uat"
}{
"code": "reference-taken",
"detail": "reference_user_id 'merchant-42' already belongs to verification 3f2504e0-4f89-41d3-9a0c-0305e82c3301"
}{
"code": "request-invalid",
"detail": "mobile: String should match pattern '^(?:\\+91)?[6-9][0-9]{9}$'"
}{
"code": "rate-limited",
"detail": "Unauthorized: RATE_LIMITED"
}{
"code": "workflow-misconfigured",
"detail": "workflow 'merchant-onboarding' cannot ask its gate check 'gst-onboarded': the workflow registers no endpoint to ask its checks at"
}{
"code": "auth-unavailable",
"detail": "Auth provider unavailable"
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
What creating a verification takes.
Which of your workflows the verification runs.
1Your own identifier for this user, unique within the workflow. It is echoed back on every response, and together with the workflow key it is the handle that survives once the verification has expired, so make it something you can reconcile against your own records.
Creating one again with a reference that already belongs to a different user in the same workflow is refused. Running the same user through a second workflow is not: that is a verification of its own under the same identifier.
1 - 255The user's Indian mobile number, on a hosted workflow. It is how they sign in to the journey, and a call without it is refused.
A workflow you supply yourself opens no journey, so it takes no mobile number and a call that names one is refused.
^(?:\+91)?[6-9][0-9]{9}$Facts you already know about the user, as a flat JSON object. Workflow conditions and step inputs can read these values to decide what the journey asks for.
Context 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 cannot run without one of these fields, creating one without it is refused, and the response names every field that was missing.
Where the user is sent after they submit the journey, on a hosted workflow. Must match one of the return URLs registered for the workflow being started, which each carry their own.
A workflow you supply yourself sends nobody anywhere, so it takes no return URL and a call that names one is refused.
Response
This subject already has a verification in this workflow, so nothing was created. The record is the one you already have, unchanged and whatever state it has reached.
The whole record of one verification; safe to poll.
The verification's id.
How verifications on this workflow are conducted. hosted: the person being verified walks the journey on our screens and submits it. staged: you create a verification, upload each document against the step it answers, and then ask for the checks to run. instant: you send the whole submission in one request, which runs the checks and answers with the finished record.
A workflow is one of the three, and every endpoint belonging to another is refused on it.
hosted, staged, instant open while the run is live and the user may act, which a step held up by a technical problem does not end; submitted once the user has finished, which they can only do with every step settled, so the result is final from that moment; completed once the checks that follow a submission have run, such as notifying you by callback, and the data is safe to read; failed if the run reached an unrecoverable state, in which case reset it or create a new one; cancelled if you ended the run; gated if a check this workflow puts to a system of yours stopped the journey there, which ends the run where it stood. A check stops it when your system answers terminate or redirect, or when your system gave no answer and the workflow falls back to terminate. Poll until the status is one of completed, cancelled, gated or failed.
expired supersedes all of them once the retention window runs out: the run is of no further use and is kept for your audit alone. It says nothing about how the run had ended, so read completed_at, cancelled_at, gated_at or failed_at for that rather than expecting the status to hold it.
open, submitted, completed, cancelled, gated, expired, failed The workflow this verification runs.
1Which version of the workflow this verification runs. It is the workflow's latest version when the verification was created, and it holds for the verification's whole life: a change published to the workflow afterwards never changes what this verification asks for, which steps it reports or the names its outputs arrive under. Resetting the verification moves it onto the latest version at the time.
x >= 1The user's mobile number, as you provided it. Null on a verification you supplied yourself, and null once the verification has expired.
Your identifier for this verification, echoed back.
The facts you supplied when you created it, unchanged. Empty once the verification has expired.
Where the user is sent after submitting, where one was given.
Where to send your user, on a hosted verification. The same address serves every user of this workflow and carries no credential, so it is safe to send over WhatsApp, SMS, or email, and the user proves who they are by signing in with the mobile number you created the verification with. To open the journey from inside your own app with the user already signed in, create a handoff instead.
Null on a verification you supplied yourself, which opens no journey.
When the verification was created.
When you asked for the checks to run, on a staged verification. From that moment the submission is frozen: uploads, withdrawals and a run request with different values are refused until you reset.
On an instant verification it is when the request carrying the whole submission arrived. Null on a hosted one, and null on a staged one until you ask.
When the verification was submitted, if it has been: by the user on a hosted workflow, by the run of the checks on one you supplied yourself.
When the verification completed, if it has.
When the verification was cancelled, if it was.
When a check of yours stopped the journey, if one did.
The step whose check stopped the journey, if one did. A workflow may put more than one check to you, and this says which of them the run stopped at.
It is set and cleared with gated_at: it stays set once the verification expires or you purge it, so the record still says how the run had ended, and a reset clears both.
When the verification was marked failed, if it was.
When the verification expired, if it has. From that moment it is kept for your audit and nothing else: it holds what each step concluded and nothing the user gave, so no answers, no values read off their documents, and no files. The step states you read are the ones frozen at that moment. Read the other timestamps to see how it had ended before it expired.
What expired the verification. retention when its workflow's retention window ran out; client when you purged it. Null until it expires.
retention, client When the verification was last acted on: by the user on a hosted workflow, by you or by the run of the checks on one you supplied yourself. A verification that is created and never touched reads the moment it was created. expires_after_days is counted from here, so the two together say when a record left untouched expires.
How many days this verification may go without activity before it expires and everything the user provided is deleted, as the version it runs states. It is this verification's own window: a later version of its workflow can state a different one, which reaches the verifications created or reset after it, so read the window here rather than off the workflow. On an expired verification it is the window it was held to.
x >= 1The receipt the user was sent telling them their submission arrived, on a workflow that acknowledges submissions by email. Null wherever nothing has been sent: a workflow that acknowledges nothing, a verification carrying no address to send to, a submission still being finalised, and a send that could not be made.
It names the submission it answers. A reset undoes a submission without unsending its receipt, so read submitted_at here against the record's own to tell a receipt for the submission this record stands in from one for a submission it no longer does.
Show child attributes
Show child attributes
How the callback for this verification's run ended: verification.submitted once it was submitted, or verification.gated once a check of yours stopped it. Null until the callback settles, and on every verification of a workflow with no callback endpoint registered. A verification completes, or stays gated, whether or not its callback was delivered, so read this to tell a result you were told about from one you were not.
Show child attributes
Show child attributes
How many credits this verification has used. A run uses one credit when it first reaches completed, cancelled or expired, whatever the workflow asks for and however many of its checks ran. A run that ends as failed or gated uses none, and one still open or submitted has used nothing yet.
Resetting a verification runs the subject through again, which is a run of its own and uses a credit of its own, so a record reset twice and completed each time reads 3.
How many times this verification has been reset. A reset clears everything the record collected and runs the subject through the checks again, so a verification reading 2 is on its third run and holds what that one has collected.
Each of these opened a run charged a credit of its own where it ended, which is what credits_consumed counts. A reset that cleared a run no credit had paid for also drew one of the workflow's resets: see resets on the workflow.
Every step of the journey counted by where it stands, the ones left out included.
Show child attributes
Show child attributes
The steps this journey has not ruled out, in journey order. A workflow presents the steps that apply to whoever is being verified, so a journey that took one branch reports that branch and not the others; progress.not_applicable says how many are missing from here, and reading the verification with include_not_applicable shows them.
A step is only missing once something has ruled it out. One whose place in the journey turns on a value an earlier step has yet to publish is here, reading undetermined, so a verification you have just created reports every step its workflow declares and they resolve into the other states as it goes on.
Show child attributes
Show child attributes
