Boni Verification API
Verify Aadhaar, PAN, GSTIN, vehicle records and recent FASTag toll observations through one simple tenant-scoped API.
Start here
Boni gives you a separate client ID and client secret for each activated environment. Use the sandbox while integrating; it returns fixed test records and never calls production data sources.
| Environment | Base URL |
|---|---|
| Sandbox | https://sandbox.api.boni.one/v1 |
| Production | https://api.boni.one/v1 |
Send these headers on every request:
x-boni-client-id: YOUR_CLIENT_ID
x-boni-client-secret: YOUR_CLIENT_SECRET
Content-Type: application/json
Idempotency-Key: a-unique-key-for-this-request
Keep credentials on your server. Do not put them in browser code, mobile apps, URLs or public repositories. Reuse an Idempotency-Key only when retrying the exact same request body.
First request
curl https://sandbox.api.boni.one/v1/verify/gstin \
-X POST \
-H 'x-boni-client-id: YOUR_SANDBOX_CLIENT_ID' \
-H 'x-boni-client-secret: YOUR_SANDBOX_CLIENT_SECRET' \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: gstin-demo-0001' \
-d '{"gstin":"22AAAAA0000A1Z5"}'
{
"success": true,
"request_id": "req_...",
"environment": "sandbox",
"endpoint": "gstin",
"status": "verified",
"data": {
"gstin": "22AAAAA0000A1Z5",
"legal_name": "BONI SANDBOX PRIVATE LIMITED",
"trade_name": "BONI SANDBOX",
"status": "ACTIVE",
"taxpayer_type": "Regular",
"registration_date": "2019-07-01",
"e_invoice_enabled": true,
"principal_place": {"state": "Chhattisgarh", "pincode": "492001"},
"sandbox": true
}
}
Endpoints and input
Every verification is a POST. Unknown fields are rejected. Spaces and hyphens in vehicle identifiers are normalized.
| What | Endpoint | JSON input |
|---|---|---|
| Aadhaar | /verify/aadhaar | aadhaar, name, date_of_birth, gender, mobile, consent |
| PAN | /verify/pan | pan plus all Aadhaar input fields |
| GSTIN | /verify/gstin | gstin |
| Vehicle | /verify/vahan | vehicle_number |
| FASTag | /verify/fastag | exactly one of vehicle_number or chassis_number |
date_of_birth uses YYYY-MM-DD, gender is M or F, and consent must be true. Aadhaar and PAN requests must be made with the document owner's consent.
Sandbox test values
| Field | Value |
|---|---|
| Aadhaar | 999999990019 |
| PAN | ABCDE1234F |
| GSTIN | 22AAAAA0000A1Z5 |
| Vehicle number | KA01AB1234 |
| Chassis number | MA1AA2BB3CC444444 |
| Name | Sandbox User |
| Date of birth | 1990-01-01 |
| Mobile | 9999999999 |
Sandbox Aadhaar and PAN finish immediately and do not require an OTP. Other valid-looking sandbox values return status: not_found so you can test that branch.
Aadhaar input and output
{
"aadhaar": "999999990019",
"name": "Sandbox User",
"date_of_birth": "1990-01-01",
"gender": "F",
"mobile": "9999999999",
"consent": true
}
A successful response uses the common envelope and returns the complete approved data payload:
{
"success": true,
"request_id": "req_...",
"environment": "sandbox",
"endpoint": "aadhaar",
"status": "verified",
"data": {
"aadhaar": "999999990019",
"name": "Sandbox User",
"date_of_birth": "1990-01-01",
"gender": "F",
"status": "VERIFIED",
"sandbox": true
}
}
Production data preserves the complete provider data structure. Boni removes only upstream authentication credentials and tokens, which are Boni platform secrets rather than verification data.
PAN input and output
{
"pan": "ABCDE1234F",
"aadhaar": "999999990019",
"name": "Sandbox User",
"date_of_birth": "1990-01-01",
"gender": "F",
"mobile": "9999999999",
"consent": true
}
{
"success": true,
"request_id": "req_...",
"environment": "sandbox",
"endpoint": "pan",
"status": "verified",
"match": {"pan": true},
"data": {
"pan": "ABCDE1234F",
"name": "SANDBOX USER",
"status": "VALID",
"category": "Individual",
"sandbox": true
}
}
Vehicle input and output
{"vehicle_number": "KA01AB1234"}
{
"success": true,
"request_id": "req_...",
"environment": "sandbox",
"endpoint": "vahan",
"status": "verified",
"data": {
"registration_number": "KA01AB1234",
"registration_date": "2022-04-18",
"owner_name": "SANDBOX OWNER",
"vehicle_class": "Goods Carrier",
"fuel_type": "DIESEL",
"maker_model": "BONI SANDBOX TRUCK",
"registration_status": "ACTIVE",
"fitness_upto": "2027-04-17",
"insurance_upto": "2027-01-31",
"pucc_upto": "2026-12-31",
"sandbox": true
}
}
FASTag input and output
Use either a vehicle number:
{"vehicle_number": "KA01AB1234"}
or a chassis number:
{"chassis_number": "MA1AA2BB3CC444444"}
{
"success": true,
"request_id": "req_...",
"environment": "sandbox",
"endpoint": "fastag",
"status": "verified",
"data": {
"vehicle_number": "KA01AB1234",
"lookback_hours": 72,
"events": [
{"plaza": "Boni Sandbox Toll Plaza A", "event_time": "2026-08-16T08:30:00+05:30", "direction": "EAST"}
],
"sandbox": true
}
}
FASTag is a sparse toll-observation feed for the rolling 72-hour window. It is not GPS tracking and does not return wallet balances, recharges or debit transactions. An empty observation result is a valid result.
Production OTP flow
Production Aadhaar or PAN may return HTTP 202 with an OTP challenge:
{
"success": true,
"request_id": "req_...",
"environment": "production",
"endpoint": "aadhaar",
"status": "otp_required",
"verification_id": "ver_...",
"expires_at": "2026-08-17T12:05:00.000Z"
}
Send the received OTP within five minutes to /verify/aadhaar/otp or /verify/pan/otp with a new idempotency key:
{"verification_id": "ver_...", "otp": "123456"}
A challenge allows at most three attempts and is bound to the same client, subscription and environment.
Common results
| HTTP | Meaning | What to do |
|---|---|---|
200 + verified | Data returned | Use data and keep request_id for support |
200 + not_found | No matching record | Treat as a normal no-record result |
202 + otp_required | Owner must provide OTP | Call the matching /otp endpoint |
400 | Invalid or unknown input | Fix the request; do not retry unchanged |
401 | Missing or invalid credentials | Check the client ID and secret |
403 | Environment, scope or endpoint not enabled | Use the correct credential or ask Boni to activate access |
409 | Idempotency or session conflict | Reuse a key only with its original body |
422 | Provider rejected the request | Check consent/input and follow the returned code |
429 | A quota window is full | Wait for Retry-After or the indicated reset |
503 or 504 | Temporary service/provider issue | Retry the same body with the same idempotency key |
Errors use one shape:
{
"success": false,
"request_id": "req_...",
"error": {"code": "rate_limit_exceeded", "message": "The minute request limit has been reached.", "retry_after_seconds": 12}
}
Quota headers report the configured second, minute, hour and day limits, remaining calls and reset times. Limits are assigned to your subscription and can differ by environment or endpoint.
Usage
Call GET /usage with the same environment credential and the verification.usage.read scope. Optional query parameters are from, to, and endpoint; a query can cover up to 31 days. The response separates total requests from metered production units and groups them by endpoint and outcome. Sandbox calls, validation failures, no-record results, rate-limit responses and upstream failures have zero billable units.
OpenAPI
Download the complete Boni Verification API V1 OpenAPI file for schemas, response types and code generation.