Capture consent from inside your own product, and get back a record the subject, a counterparty, or a regulator can independently verify. You do not have to use VerifyBG for background checks to use this.
Under the Digital Personal Data Protection Act, 2023, consent has to be specific, informed and demonstrable. A checkbox in your database is none of those things once someone disputes it, because the only evidence it happened is a row you control and could have written at any time.
This API produces consent that is evidenced independently: signed by the subject, authenticated by a one-time code sent to their email, bound to a timestamp, IP address and device, and issued as a certificate carrying a reference that anyone can check at verifybg.in/verify/<reference> without an account and without asking you.
Create a key under your account. Send it as a bearer token. The key is shown once at creation and stored only as a hash, so we cannot recover it for you; if it is lost, revoke it and make another.
Authorization: Bearer vbg_live_xxxxxxxx_...
Create a test key under your account and build against it. Test keys never email anyone, never bill, and create records that say plainly on every surface that they are tests, including the public verification page.
Mode is carried in the key itself rather than passed as a parameter, so you cannot accidentally send test traffic to production by forgetting a flag, nor production traffic to test by remembering one. A test key sees only test records; a live key sees only live ones.
vbg_test_xxxxxxxx_... test vbg_live_xxxxxxxx_... live
Because a real consent needs a human to open a link and sign, test mode gives you a way to close the loop automatically:
POST /api/v1/consent-requests/{id}/simulate-consent
{ "signed_name": "Test Subject", "method": "EMAIL_OTP" }This fires your webhooks exactly as a real signature would, so you can exercise your own receiver in CI. It is available only to test keys, and only against test records: a live key gets 403, and a test key pointed at a live record gets 404. There is no parameter that relaxes either check. Consent that could be forged would be worth nothing.
POST https://www.verifybg.in/api/v1/consent-requests
{
"subject_name": "Amit Sharma",
"subject_email": "amit@example.com",
"purpose": "Tenancy application for 3BHK, Vasant Kunj",
"reference": "your-internal-id-4821"
}purpose is required and is shown to the subject verbatim. It appears on the certificate and on the public verification page, so write what you would be content for them to read, because they will.
201 Created
{
"id": "cms8...",
"status": "awaiting_consent",
"consent_url": "https://www.verifybg.in/consent/oVhq...",
"reference": "your-internal-id-4821",
"email_sent": true,
"retention_days": 30
}If you supplied subject_email we email the subject the link. Pass "send_email": false to deliver consent_url yourself.
GET https://www.verifybg.in/api/v1/consent-requests/{id}
{
"id": "cms8...",
"status": "consented",
"consent": {
"signed_at": "2026-07-31T15:41:56.642Z",
"method": "EMAIL_OTP",
"verify_code": "VBG-7UVACFJY",
"verify_url": "https://www.verifybg.in/verify/VBG-7UVACFJY",
"withdrawn_at": null
}
}status is one of awaiting_consent, consented or withdrawn. method is EMAIL_OTP where the subject confirmed a one-time code, or TYPED_NAME where no email was available. The two are never presented as equivalent, on the certificate or here.
Add an HTTPS endpoint under your account and you will receive consent.signed and consent.withdrawn. Failed deliveries retry with backoff at 1, 5, 25 and 125 minutes before being marked failed.
POST your-endpoint
X-VerifyBG-Signature: <hmac-sha256 of the raw body>
X-VerifyBG-Event: consent.signed
{
"event": "consent.signed",
"data": {
"request_id": "cms8...",
"verify_code": "VBG-7UVACFJY",
"method": "EMAIL_OTP",
"signed_at": "2026-07-31T15:41:56.642Z"
}
}Verify the signature on every delivery. Compute an HMAC-SHA256 of the raw request body, before any JSON parsing, using the signing secret shown when you added the endpoint, and compare it to the header in constant time. An endpoint that skips this accepts events from anyone who learns the URL.
Public, unauthenticated, and the point of the whole thing. A counterparty holding a reference can confirm it without any relationship with you or with us.
GET https://www.verifybg.in/api/verify/VBG-7UVACFJY 200 -> the consent is genuine 404 -> no such consent was ever issued
A reference that was never issued returns a real 404, so an automated check cannot be fooled by a fabricated certificate. Verification reveals the consent and its scope, never the findings of any background check.
Errors return { "error": { "message": "..." } } with a conventional status: 401 for a bad key, 404 for a record that is not yours, 422 for a validation failure with a detail array, 429 when rate limited. Creation is limited to 300 calls per key per hour.
Questions, or need a higher limit? Write to our contact page.