Overview
Everything you need to call BankPay APIs's provider-backed APIs from your own systems.
Every API is reached under a common base URL and shares the same authentication scheme (see Authentication below). Each API is documented as its own section further down this page — start with BIN Checker, Mobile Prefill - KYC and Mobile Prefill - Name Lookup, the three APIs live today.
| Base path | /api/v1 |
|---|---|
| Content type | application/json for all request and response bodies |
| Access | Requires a BankPay APIs-issued API key & secret — see the Developer Hub's how to get access steps |
Response envelope
Every endpoint returns the same JSON envelope, camelCase throughout. The actual
result of the call — the fields documented per endpoint below — sits under
data.
{
"success": true,
"statusCode": "00",
"message": "Success",
"correlationId": "0HN...",
"data": { /* endpoint-specific fields — see each API section below */ }
}
success tells you the request itself was
valid and authenticated. The inner data.status
("Success"/"Failed") tells you whether the underlying lookup actually found an
answer — a request can be success: true at the
envelope level while data.status is
"Failed" (e.g. a BIN that doesn't resolve to any
issuer). See Error Handling.
Authentication
Shared by every API on this platform — a plain API Key + API Secret pair, sent as headers.
Every request must include two headers. There is no request-signing/HMAC step
and no OAuth flow — this is a deliberate choice: every call is over HTTPS, only
IPs on your allowlist are ever accepted (see IP
Allowlisting), and every request carries your own unique
clientRefId, so a signed-canonical-
request scheme would add integration friction without a meaningful security gain
on top of TLS + IP allowlisting.
| Header | Description |
|---|---|
X-Api-Key | Your public API key — generate one from "API Credentials" in your merchant portal. |
X-Api-Secret | Your API secret, shown once at generation time. Never logged or displayed again — regenerate if lost. |
X-Api-Secret must never be sent from a browser or
embedded in a mobile app — call these APIs from your own backend only.
Sample code
Each sample calls the BIN Checker endpoint. Replace the placeholder key/secret with your own.
curl -X POST "https://api.example.com/api/v1/verify/bin-check" \
-H "Content-Type: application/json" \
-H "X-Api-Key: your_api_key" \
-H "X-Api-Secret: your_api_secret" \
--data-raw '{
"clientRefId": "REF-0001",
"bin": "411111",
"latitude": "12.9716",
"longitude": "77.5946"
}'// Node.js (server-side only — never call this from a browser, it would
// expose your API secret to anyone viewing the page).
const https = require("https");
const body = JSON.stringify({
clientRefId: "REF-0001",
bin: "411111",
latitude: "12.9716",
longitude: "77.5946"
});
const options = {
hostname: "api.example.com",
path: "/api/v1/verify/bin-check",
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": Buffer.byteLength(body),
"X-Api-Key": "your_api_key",
"X-Api-Secret": "your_api_secret",
},
};
const req = https.request(options, (res) => {
let data = "";
res.on("data", (chunk) => (data += chunk));
res.on("end", () => console.log(res.statusCode, data));
});
req.write(body);
req.end();import json, requests
url = "https://api.example.com/api/v1/verify/bin-check"
headers = {
"Content-Type": "application/json",
"X-Api-Key": "your_api_key",
"X-Api-Secret": "your_api_secret",
}
body = {
"clientRefId": "REF-0001",
"bin": "411111",
"latitude": "12.9716",
"longitude": "77.5946",
}
resp = requests.post(url, json=body, headers=headers)
print(resp.status_code, resp.json())using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Api-Key", "your_api_key");
client.DefaultRequestHeaders.Add("X-Api-Secret", "your_api_secret");
var body = "{\"clientRefId\":\"REF-0001\",\"bin\":\"411111\",\"latitude\":\"12.9716\",\"longitude\":\"77.5946\"}";
var content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://api.example.com/api/v1/verify/bin-check", content);
var responseBody = await response.Content.ReadAsStringAsync();
System.Console.WriteLine((int)response.StatusCode + " " + responseBody);
}
}Error Handling
How failures are reported, and why some "failures" come back as HTTP 200.
A business-level outcome (like "this BIN could not be identified") is not the same as a request error (like "invalid credentials"). This platform distinguishes the two on purpose:
| HTTP Status | Meaning |
|---|---|
| 200 OK | The request itself was valid and authenticated. Check data.status to see whether the underlying lookup succeeded — a "not found" result is still a 200, and is not billed. |
| 400 Bad Request | A required field was missing or invalid (e.g. bin isn't exactly 6 digits). |
| 401 Unauthorized | Missing/invalid X-Api-Key or X-Api-Secret, or a revoked key. |
| 403 Forbidden | This request came from an IP not on your account's allowlist. See IP Allowlisting. |
| 500 Internal Server Error | An unexpected error on our side. Safe to retry after a short delay. |
data.status before treating a call as successful —
see the response fields documented per API below.
IP Allowlisting Required
Two layers — one on your API key, one (optional) on the specific API.
Your API key does not work from any IP until at least one server IP is
registered against it, from "API Credentials" in your merchant portal. A request
from an unregistered IP is rejected with 403 Forbidden
before it reaches any endpoint logic.
Separately, an individual API can carry its own IP allowlist for your account
(configured by your account manager). A mismatch here is reported as a normal
200 response with data.status: "Failed" and a
message explaining the call was blocked — not a 403 — since your key itself was
valid.
403 Forbidden, this is almost always why — add your
server IP(s) from "API Credentials" in your portal.
Test Mode
Integrate and test error handling before you ever touch a real upstream provider.
Each API key (ApiClient) is issued flagged as either Live or Test — ask your account manager for a Test key if you don't have one yet. A Test key goes through the exact same authentication and IP allowlist checks as a Live key, and the same field validation.
What's different: a Test-key call never reaches the real upstream provider and is never charged. By default it returns a generic success response; if your account has specific mock responses configured (e.g. a particular BIN or mobile number that should return a canned failure), it returns that instead — ask your account manager to set these up so you can exercise both success and failure paths deterministically.
mobileNumber: "9876543210" in Test Mode for a canned
success response, or mobileNumber: "9000000000" for a
canned "not found" failure. Any other number returns a generic success with an
empty result.
bin: "411111" in Test Mode for a canned success
response, or bin: "000000" for a canned "not found"
failure. Any other 6-digit BIN returns a generic success with an empty
result.
BIN Checker Live
Look up issuer and card details for a 6-digit card BIN.
POST/api/v1/verify/bin-check
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
clientRefId | string | Yes | Your own unique reference for this call — must be unique per call. Reusing a clientRefId from an earlier request is rejected outright (status: "Failed", not reprocessed and not replayed) — even if the earlier issue has since been fixed, use a new clientRefId to try again. |
bin | string | Yes | Exactly 6 numeric digits. |
latitude | string | No | Decimal degrees. |
longitude | string | No | Decimal degrees. |
{
"clientRefId": "REF-0001",
"bin": "411111",
"latitude": "12.9716",
"longitude": "77.5946"
}
Response — data fields
| Field | Type | Description |
|---|---|---|
transactionId | number | Internal transaction reference — quote this if contacting support. |
clientRefId | string | Echoes your request value. |
status | string | Success or Failed. |
responseMessage | string | A short status message — the reason on failure, or a success confirmation. |
charges | object | What was billed for this call, on your account's rate, and your wallet balance before/after — see below. All zero/unchanged on a failed lookup. |
result | object | The full lookup result, passed through unmodified from the network — not a hand-picked subset. See fields below. |
result fields
| Field | Type | Description |
|---|---|---|
issuerBank | string | Card-issuing bank. |
cardNetwork | string | e.g. VISA, MASTERCARD, RUPAY. |
cardType | string | e.g. Credit, Debit. |
cardLevel | string | e.g. Platinum, Classic. |
isoCountryName, isoCountryA2 | string | Issuing country — full name and ISO 2-letter code. |
issuerWebsite, issuerPhone | string | Issuer contact details, when the network reports them. |
cardTransfer | string | Whether this card supports card-to-card transfer, per the card network. |
charges fields
| Field | Type | Description |
|---|---|---|
serviceCharge, serviceChargeGSTAmount, totalCharge | number | What was billed for this call, on your account's rate. |
walletBalanceBefore, walletBalanceAfter | number | Your wallet balance before/after this call. |
{
"success": true,
"statusCode": "00",
"message": "Success",
"correlationId": "0HN...",
"data": {
"transactionId": 100123,
"clientRefId": "REF-0001",
"status": "Success",
"responseMessage": "BIN found.",
"charges": {
"serviceCharge": 0.42,
"serviceChargeGSTAmount": 0.08,
"totalCharge": 0.50,
"walletBalanceBefore": 10000.00,
"walletBalanceAfter": 9999.50
},
"result": {
"issuerBank": "HDFC Bank",
"cardNetwork": "VISA",
"cardType": "Credit",
"cardLevel": "Platinum",
"isoCountryName": "India",
"isoCountryA2": "IN",
"issuerWebsite": "https://www.hdfcbank.com",
"issuerPhone": "1800-xxx-xxxx",
"cardTransfer": "Y"
}
}
}{
"success": true,
"statusCode": "00",
"message": "Failed",
"correlationId": "0HN...",
"data": {
"transactionId": 100124,
"clientRefId": "REF-0002",
"status": "Failed",
"responseMessage": "BIN not found or could not be verified.",
"charges": {
"serviceCharge": 0,
"serviceChargeGSTAmount": 0,
"totalCharge": 0,
"walletBalanceBefore": 9999.50,
"walletBalanceAfter": 9999.50
}
}
}{
"success": false,
"statusCode": "VAL001",
"message": "\"bin\" must be exactly 6 numeric digits.",
"correlationId": "0HN..."
}data.status is
"Success". Validation errors, auth failures and "not
found" results are never billed.
Mobile Prefill - KYC Live
Resolve the full KYC profile — name, DOB, age, gender, PAN, email, reported address history and a bureau score — linked to a mobile number.
POST/api/v1/verify/mobile-prefill
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
clientRefId | string | Yes | Your own unique reference for this call — must be unique per call. Reusing a clientRefId from an earlier request is rejected outright (status: "Failed", not reprocessed and not replayed) — even if the earlier issue has since been fixed, use a new clientRefId to try again. |
mobileNumber | string | Yes | 10-digit mobile number. |
{
"clientRefId": "REF-2001",
"mobileNumber": "9876543210"
}
Response — data fields
| Field | Type | Description |
|---|---|---|
transactionId | number | Internal transaction reference. |
clientRefId | string | Echoes your request value. |
status | string | Success or Failed. |
responseMessage | string | A short status message — the reason on failure, or a success confirmation. |
charges | object | What was billed, on your account's rate, and your wallet balance before/after — see below. All zero/unchanged on a failed lookup. |
result | object | The full KYC result, passed through unmodified from the bureau — not a hand-picked subset. See fields below. |
result fields
Every field the bureau returns is forwarded as-is — this is the current field set; the bureau can add fields over time without a version bump on our side, so treat unknown fields as forward-compatible rather than an error.
| Field | Type | Description |
|---|---|---|
name | string | Full name on record. |
dob | string | Date of birth, DD-MM-YYYY. |
age | string | Age in years, as of the bureau's record date. |
gender | string | Male or Female. |
pan | string | PAN on record, if the bureau has one linked to this mobile number. |
email | string | Email on record — an empty string if the bureau has none. |
address | array | Every address the bureau has on record for this person, most systems return more than one historical entry — see fields below. Any individual field within an entry can be null if the bureau didn't report it for that particular record. |
score | string | Bureau confidence/credit score for this record. |
result.address[] fields
| Field | Type | Description |
|---|---|---|
first_line_of_address, second_line_of_address, third_line_of_address | string | Address lines as reported — not always split the same way between entries. |
city, state | string or null | Frequently null on older or less-structured bureau records — fall back to the address lines when absent. |
postal_code | string | PIN code. |
country_code | string | Bureau-specific country code, not necessarily an ISO 2-letter code. |
reported_date | string | When the bureau recorded this address — can be an empty string if unavailable. |
charges fields
| Field | Type | Description |
|---|---|---|
serviceCharge, serviceChargeGSTAmount, totalCharge | number | What was billed for this call, on your account's rate. |
walletBalanceBefore, walletBalanceAfter | number | Your wallet balance before/after this call. |
{
"success": true,
"statusCode": "00",
"message": "Success",
"correlationId": "0HN...",
"data": {
"transactionId": 100301,
"clientRefId": "REF-2001",
"status": "Success",
"responseMessage": "KYC record found.",
"charges": {
"serviceCharge": 2.12,
"serviceChargeGSTAmount": 0.38,
"totalCharge": 2.50,
"walletBalanceBefore": 9997.00,
"walletBalanceAfter": 9994.50
},
"result": {
"name": "Rohit Kumar Sharma",
"dob": "14-05-1990",
"age": "35",
"gender": "Male",
"pan": "ABCPS1234D",
"email": "",
"address": [
{
"first_line_of_address": "12-3-45/A, MG Road",
"second_line_of_address": "Indiranagar",
"third_line_of_address": "Bengaluru",
"city": "Bengaluru",
"state": "Karnataka",
"postal_code": "560038",
"country_code": "IB",
"reported_date": ""
},
{
"first_line_of_address": "12 3 45 A MG ROAD INDIRANAGAR",
"second_line_of_address": "BENGALURU",
"third_line_of_address": "560038",
"city": null,
"state": null,
"postal_code": "560038",
"country_code": "IB",
"reported_date": ""
}
],
"score": "812"
}
}
}{
"success": true,
"statusCode": "00",
"message": "Failed",
"correlationId": "0HN...",
"data": {
"transactionId": 100302,
"clientRefId": "REF-2002",
"status": "Failed",
"responseMessage": "No KYC record found for this mobile number.",
"charges": {
"serviceCharge": 0,
"serviceChargeGSTAmount": 0,
"totalCharge": 0,
"walletBalanceBefore": 9994.50,
"walletBalanceAfter": 9994.50
}
}
}data.status is
"Success".
Mobile Prefill - Name Lookup Live
Resolve the name linked to a mobile number.
POST/api/v1/verify/mobile-prefill-with-name
Request body
| Field | Type | Required | Notes |
|---|---|---|---|
clientRefId | string | Yes | Your own unique reference for this call — must be unique per call. Reusing a clientRefId from an earlier request is rejected outright (status: "Failed", not reprocessed and not replayed) — even if the earlier issue has since been fixed, use a new clientRefId to try again. |
mobileNumber | string | Yes | 10-digit mobile number. |
{
"clientRefId": "REF-1001",
"mobileNumber": "9876543210"
}
Response — data fields
| Field | Type | Description |
|---|---|---|
transactionId | number | Internal transaction reference. |
clientRefId | string | Echoes your request value. |
status | string | Success or Failed. |
responseMessage | string | A short status message — the reason on failure, or a success confirmation. |
charges | object | What was billed, on your account's rate, and your wallet balance before/after — see below. All zero/unchanged on a failed lookup. |
result | object | The lookup result — name, the resolved name linked to the mobile number. |
charges fields
| Field | Type | Description |
|---|---|---|
serviceCharge, serviceChargeGSTAmount, totalCharge | number | What was billed, on your account's rate. |
walletBalanceBefore, walletBalanceAfter | number | Your wallet balance before/after this call. |
{
"success": true,
"statusCode": "00",
"message": "Success",
"correlationId": "0HN...",
"data": {
"transactionId": 100201,
"clientRefId": "REF-1001",
"status": "Success",
"responseMessage": "Name resolved.",
"charges": {
"serviceCharge": 0.85,
"serviceChargeGSTAmount": 0.15,
"totalCharge": 1.00,
"walletBalanceBefore": 9999.50,
"walletBalanceAfter": 9998.50
},
"result": {
"name": "Rohit Kumar Sharma"
}
}
}{
"success": true,
"statusCode": "00",
"message": "Failed",
"correlationId": "0HN...",
"data": {
"transactionId": 100202,
"clientRefId": "REF-1002",
"status": "Failed",
"responseMessage": "No name found for this mobile number.",
"charges": {
"serviceCharge": 0,
"serviceChargeGSTAmount": 0,
"totalCharge": 0,
"walletBalanceBefore": 9998.50,
"walletBalanceAfter": 9998.50
}
}
}data.status is
"Success".
Payouts, BBPS & More Coming soon
Payouts (IMPS/NEFT/RTGS/UPI), bank account verification, PAN verification, BBPS bill fetch/pay and recharge collections will be documented here as they're published — the same authentication, error handling and billing model described above applies to every one of them.