BankMe Developers Back to bankme.co.in
API v1

Build with the BankMe APIs

Send money from your BankMe wallet to any bank account (IMPS or NEFT) or UPI ID with one HTTPS call, and get a signed webhook when the payout settles.

Simple JSONHTTPS requests and JSON responses. Two headers for authentication.
IdempotentThe same referenceId never pays twice.
Signed webhooksHMAC-signed results, retried until you acknowledge.
Sandbox firstTest with no real money, then switch the base URL.

What you can build

APIWhat it doesStart here
PayoutSend money from your wallet to any bank account or UPI IDCreate payout
VerificationPAN, GSTIN, bank account, company, licence and more in one callVerify a document
BBPSElectricity, water, gas, DTH and other bill paymentsBill categories
DMTDomestic money transfer to any bank accountCheck a sender
AEPSBalance, statement and cash withdrawal with Aadhaar and fingerprintBalance enquiry

All of them share the same authentication, the same sandbox and the same wallet. Test everything in the sandbox first.

How it works

  1. BankMe issues you a sandbox key (pk_... and sk_...). Production keys follow after your integration is approved.
  2. Your server calls Create payout with a unique referenceId.
  3. BankMe debits your wallet and sends the money. The result comes back in the response or as a webhook.
  4. If a call times out, ask for the result with Payout status. Never retry with a new reference.

API access is issued by BankMe. Each key is tied to one wallet and one payout route, with its own per-payout and per-day limits. Contact your BankMe account manager to get your keys.

Environments

Two environments, same paths and same code.

EnvironmentBase URLDoes money move?
Sandboxhttps://sandbox.bankme.co.inNo. Results are simulated and your wallet is never debited.
Productionhttps://api.bankme.co.inYes. Your wallet is debited and the beneficiary is paid.

Keys are not shared between environments. A sandbox key does not work on production, and the other way round. Every response carries an environment field so you can confirm where you are. Use the toggle in the code panels on this page to switch the base URL in every example.

Authentication

Every request carries your key id and secret in two headers.

HeaderRequiredValue
x-api-keyYesYour key id, starts with pk_
x-api-secretYesYour secret, starts with sk_. Shown once when the key is created.
Content-TypeOn POSTapplication/json

Keep the secret on your server. Never put it in a mobile app, a web page or a public repository. If it leaks, ask BankMe to rotate it straight away.

IP allowlist

Production keys only work from the server IP addresses you give BankMe. Calls from any other address are rejected. Call GET /v1/ip from your server to see the address BankMe sees.

Rate limit

120 requests per minute per key.

Writes money

Create payout

POST/v1/payout

Send money to a bank account or UPI ID.

Request body

FieldTypeNotes
referenceIdstringRequired. Your own unique id for this payout. It is the idempotency key.
amountintegerRequired. Whole rupees, minimum 100.
beneficiaryobjectRequired. Bank or UPI, see below.
remarksstringOptional. Up to 60 characters.
speedstringOptional. "standard" (default) or "instant". See Standard and instant payouts below.

Beneficiary: bank account

FieldNotes
type"bank"
nameAccount holder name. Letters, spaces and dots only.
accountNumber9 to 18 digits
ifscValid IFSC code, for example HDFC0001234
mode"IMPS" (default) or "NEFT"

Beneficiary: UPI

FieldNotes
type"upi"
nameBeneficiary name
vpaUPI ID, for example name@bank

Response

FieldMeaning
payoutIdBankMe's id for the payout
referenceIdYour reference, returned unchanged
amount, fee, totalDebitRupees. totalDebit is amount plus fee.
statuspending, processing, success or failed
utrBank reference number, filled when the payout succeeds
reasonWhy a payout failed, empty otherwise
speedstandard or instant
instantChargeRupees. The extra charge for an instant payout, including GST. It is included in totalDebit. Zero for standard.
scheduledForWhen a standard payout is due to be sent. Instant payouts are sent at once.
environmentsandbox or production

Standard and instant payouts

SpeedWhat happens
standard (default)Your wallet is debited at once. The payout stays pending and is sent in the next BankMe batch, which is the next day or, where two batches a day apply, the next batch time. The time is in scheduledFor. No extra charge.
instantThe payout is sent immediately. It carries an extra charge of Rs 0.15 per Rs 1,000 (minimum Rs 1) plus 18% GST. For example, an instant payout of Rs 10,000 adds Rs 1.77 to totalDebit. Your agreed rate can differ.

Who can use instant. Instant payout opens when your account reaches Rs 1 crore of successful pay-in business. Before that, an instant request is refused with INSTANT_NOT_AVAILABLE and nothing is debited. Send a standard payout instead.

A speed value other than standard or instant is refused with INVALID_SPEED. In the sandbox you can test the instant request and its charge without the Rs 1 crore requirement.

Idempotency. If you send a referenceId that already exists, you get the original payout back with "duplicate": true. Nothing new is created or debited.

Debit and refund. A live payout debits amount + fee (plus the instant charge, if you ask for instant) from your wallet immediately. If the payout fails, the full debit is returned to your wallet. A request that fails validation never debits anything.

Payout status

GET/v1/payout/{referenceId}

Fetch a payout by your own reference, plus the delivery state of its webhook.

Use this when a request timed out and you do not know if it arrived, or when you want to confirm a payout without waiting for the webhook. The webhook object shows status, attempts and lastError for the delivery of this payout's result.

If you are unsure whether a create call reached BankMe, call this endpoint first. Do not create a new payout with a new reference.

Wallet balance

GET/v1/balance

The current balance of the wallet your key pays from, in rupees.

Check it before large batches. In the sandbox the balance is virtual and is never debited.

Your IP address

GET/v1/ip

Returns the public IP address BankMe sees for your request. No keys needed.

Run it from your production server, then give that address to BankMe to add to your allowlist.

Limits and fees

ItemValue
Minimum per payoutRs 100
Maximum per payoutUp to Rs 2,00,000. Your key may have a lower limit.
Daily limitRs 5,00,000 by default, set per key. The day resets at midnight IST.
FeeSlab based, from Rs 10 to Rs 100 per payout, GST included. The exact fee is returned in fee.
Rate limit120 requests per minute per key

Status and error codes

Failed requests return a non-2xx status and JSON with "success": false, a code and a readable message.

CodeWhen it happens
AUTH_REQUIREDMissing, wrong or disabled key or secret, or the call came from an IP that is not allowed.
INVALID_AMOUNTAmount is not a whole number, or is below Rs 100.
INVALID_BENEFICIARYA beneficiary field is missing or badly formatted. The message names the field.
LIMIT_PER_TXNAmount is above the per-payout limit.
LIMIT_PER_DAYThe daily limit would be exceeded. The message shows what is left today.
INSUFFICIENT_BALANCEThe wallet cannot cover amount plus fee.
RAIL_UNAVAILABLEThe payout route for your key is not available right now. Try again later.
OWNER_NOT_FOUNDThe wallet owner for the key was not found. Contact BankMe.

A request that fails validation never debits your wallet. For a timeout or a network error, check Payout status before doing anything else.

Collects money

Create a payment

POST/v1/payin/orders

Collect a UPI payment from your customer through a BankMe payment link.

You create an order, then send your customer to the paymentUrl in the response. The customer pays on a BankMe hosted page. BankMe confirms the payment on its own side and tells you the result by webhook. You never handle the customer's UPI details.

Request body

FieldTypeNotes
referenceIdstringRequired. Your unique id, 6 to 60 letters, numbers, - or _. It is the idempotency key.
amountnumberRequired. Rupees. Minimum Rs 10, and within your per-order and daily limits.
customerobjectOptional. name and mobile (10 digit Indian number).
redirectUrlstringOptional. An https:// address where the customer returns after paying.
notestringOptional. Up to 80 characters.

Response

FieldMeaning
orderIdBankMe's id for the order
referenceIdYour reference, returned unchanged
amount, fee, netAmountRupees. netAmount is amount minus fee. This is what reaches your wallet.
statuspending, success, failed or expired
paymentUrlSend your customer here. Present only while the order is open.
settlementStatusWhere the money is on its way to your wallet. See Settlement and activation.
utrBank reference number, filled when the payment succeeds
reasonWhy a payment failed, empty otherwise
environmentsandbox or live
createdAt, paidAtTimestamps. paidAt is empty until the payment succeeds.

Example request

{
  "referenceId": "ORDER_10045",
  "amount": 499,
  "customer": { "name": "Asha K", "mobile": "9876543210" },
  "redirectUrl": "https://yourshop.example/thanks",
  "note": "Order 10045"
}

Idempotency. If you send a referenceId that already exists, you get the original order back. No second order is created.

Do not trust the redirect. The customer returning to your redirectUrl does not prove payment. Confirm with the webhook or the status call before you deliver goods.

Errors

CodeMeaning
INVALID_REFERENCEreferenceId is not 6 to 60 letters, numbers, - or _
INVALID_AMOUNTBelow the minimum, or too small after charges
INVALID_URLredirectUrl is not a valid https:// address
INVALID_INPUTA field such as customer.mobile is not valid
LIMIT_PER_TXNAbove your per-order limit
LIMIT_PER_DAYYour daily pay-in limit is reached
NOT_ACTIVATEDLive pay-in is not activated for your account yet
NOT_AVAILABLEPay-in is not available right now. Try again shortly.
SERVER_ERRORSomething went wrong. Check the status with your referenceId before you retry.

Payment status

GET/v1/payin/orders/{referenceId}

Fetch an order by your own reference.

For an open live order, BankMe checks the latest result before it answers. Use this when a request timed out, when a webhook has not arrived, or when you want to confirm a payment yourself. An unknown reference returns NOT_FOUND.

If you are unsure whether a create call reached BankMe, call this endpoint first. Do not create a new order with a new reference.

Pay-in webhooks

BankMe tells your server when a payment succeeds or fails.

EventWhen
payin.successThe customer's payment is confirmed
payin.failedThe payment failed or the order expired

The body is JSON: an event field plus the same fields as the order response. The headers are x-bankme-event, x-bankme-timestamp and x-bankme-signature. The signature is HMAC-SHA256 of timestamp + "." + body, using your webhook secret, in hex. The header value is sha256= followed by that hex. It is the same scheme as your payout webhooks, so use the same verification code from the Webhooks section.

Retries. If your server does not answer with a 2xx status, BankMe retries after 1, 5, 30, 120 and 720 minutes. The same event can arrive more than once, so treat your referenceId as the key and ignore repeats.

Your webhook address must be an https:// address on a public domain.

Settlement and activation

When you are paid

Money from your customer reaches BankMe first. Your wallet is credited with the netAmount only after BankMe has received it. Depending on how the payment was received, that is either instant or the next working day (T+1). Your settlementStatus follows it: pending, then settled.

Pay-in money always settles to your BankMe wallet. Payouts to your own bank account use the Payout API, to verified accounts only.

Chargebacks

If a customer disputes a payment, the amount is debited from your wallet and the order shows a chargeback. If the wallet is short, the shortfall is kept as a balance due and recovered from your next credits. You can see chargebacks and a daily reconciliation in your Partner Console.

Going live

StepDetail
1. TestUse the sandbox for at least 7 days and complete at least one successful test payment.
2. ActivateOne-time activation fee of Rs 15,000 plus 18% GST (Rs 17,700 in total).
3. IP addressAdd at least one server IP address to your allowlist.
4. Production keyAfter BankMe verifies your activation payment, your production credentials are issued.

Charges, limits and settlement timing can differ for each partner and change with volume. Your agreed rates are shown in your Partner Console.

Test pay-in in the sandbox

No real money moves in the sandbox.

Create an order with your sandbox key. The paymentUrl opens a test page with two buttons, one to simulate a successful payment and one to simulate a failed payment. Press one, then read the result with the status call or your webhook.

You wantDo this
SuccessOpen the paymentUrl and choose the success button
FailureOpen the paymentUrl and choose the failed button. The result is failed.
DuplicateSend the same referenceId twice
Above the limitSend an amount over your per-order limit. The call is refused with LIMIT_PER_TXN.

Going live. Live pay-in is refused with NOT_ACTIVATED until your activation is complete. Your sandbox days and test payments count towards the 7 day requirement.

Charged per found record

Verify a document

POST/v1/verify/{product}

One call to check a PAN, GSTIN, bank account, company, licence and more. The product id goes in the path.

Send the inputs for that product in the JSON body. The product list shows the product ids and the inputs each one needs.

Request body

FieldTypeNotes
(product inputs)stringRequired. The inputs for the product, for example pan, name and dob for pan_lite.
referenceIdstringOptional. Your own unique id, 6 to 60 letters, numbers, - or _. Send it to make the call safe to repeat.

Response

FieldMeaning
successWhether the call was processed
productThe product id you called
result.statussuccess or failed
result.dataThe verified details. The fields depend on the product.
result.codeOn failure, for example NOT_FOUND when no record exists
chargedLive only. The price, GST and total taken from your wallet. All zero when nothing is charged.
callIdLive only. BankMe's id for the call
sandboxtrue on sandbox calls

You pay only for a found record. The price plus 18% GST is held from your wallet first. If no record is found or the service is down, the full amount returns to your wallet at once and the response shows charged as zero.

Repeat safely. If you send a referenceId that already exists, you get the first result back with "repeated": true and are not charged again.

Test in the sandbox

You wantSend
SuccessAny input in the right format. The response has a sample record.
FailureMake the first input end in 0000 or start with ZZZZ. The result is failed with code NOT_FOUND.

Sandbox first. Use your sandbox key on https://sandbox.bankme.co.in. Results are simulated, your wallet is never debited and no real money moves. Sandbox responses carry "sandbox": true and "charged": 0.

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Verification products and inputs

Use the product id in POST /v1/verify/{product}.

Product idNameInputsProduction
pan_fetchFetch PAN detailspanSandbox, live soon
pan_litePAN verification (Lite)pan, name, dobSandbox, live soon
pan_advPAN verification (Advanced)panSandbox, live soon
bank_pennylessBank account (Pennyless)acct, ifscSandbox, live soon
bank_pennydropBank account (Pennydrop)acct, ifscSandbox, live soon
vpa_verifyUPI ID (VPA)vpa, mobile, nameSandbox, live soon
mobile_vpaMobile to VPAmobileSandbox, live soon
gst_basicGST verification (Basic)gstinLive
gst_panFetch GST with PANpanSandbox, live soon
gst_advAdvanced GSTgstinSandbox, live soon
cinCIN verificationcinLive
dinDIN verificationdinSandbox, live soon
itrITR compliance checkpanSandbox, live soon
fssaiFSSAI licencefssaiLive
msmeMSME / UdyamudyamLive
dlDriving licencedl, dobSandbox, live soon
voterVoter IDepicSandbox, live soon
passportPassport applicationpassfile, dobSandbox, live soon
name_matchName matchname, name2Sandbox, live soon
rcVehicle RCrcSandbox, live soon
echallanVehicle e-challanrcSandbox, live soon
employeeEmployee detailuanSandbox, live soon
emailEmail verificationemailSandbox, live soon
revgeoReverse geocodinglat, lngSandbox, live soon
ipIP verificationipSandbox, live soon

Input formats

InputFormatExample
panPAN, 10 charactersABCDE1234F
name, name2Letters, spaces, dots, apostrophes and hyphens, 2 to 80 charactersRohan Kumar
dobYYYY-MM-DD1990-01-31
acct6 to 20 digits1234567890
ifscIFSC, 11 charactersHDFC0001234
mobile10 digit Indian number9876543210
vpaUPI IDname@bank
gstinGSTIN, 15 characters22AAAAA0000A1Z5
cinCIN, 21 charactersU12345TN2020PTC123456
din8 digits01234567
fssai14 digits12345678901234
udyamUdyam numberUDYAM-TN-00-0000000
dlDriving licence numberTN3720200001234
epicVoter ID numberABC1234567
passfilePassport file number, 10 to 16 charactersCH1234567890123
rcVehicle registration numberTN37AB1234
uan12 digits123456789012
emailEmail addressname@example.com
lat, lngDecimal degrees11.0168, 76.9558
ipIP address8.8.8.8

Products marked Live work on production keys once activated. The others return simulated data in the sandbox now and are switched on one by one. Price per call is on your partner rate card. Prices exclude 18% GST.

Bill categories

GET/v1/bbps/categories

List the bill categories you can pay: electricity, water, gas, DTH, broadband and more.

Pay bills in four steps. Get the categories, pick the biller (operator), fetch the bill, then pay it. Each step has its own call below.

Sandbox first. Use your sandbox key on https://sandbox.bankme.co.in. Results are simulated, your wallet is never debited and no real money moves.

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Billers (operators)

GET/v1/bbps/operators

List the billers in a category. Use the operatorCode when you fetch or pay a bill.

Query

FieldTypeNotes
categorystringOptional. A category id from the categories call.
locationstringOptional. Narrow the list to a state or area.

Fetch a bill

GET/v1/bbps/bill

Look up the amount due for a customer account before you pay.

Query

FieldTypeNotes
operatorCodestringRequired. From the operators call.
accountstringRequired. The customer's account or consumer number with the biller.
mobilestringRequired. Customer mobile, 10 digits.
senderNamestringRequired. Customer name.
categorystringRequired. The bill category.
district, statestringOptional. Some electricity boards need them.

A bill lookup is free. Nothing is debited until you call Pay a bill.

Test in the sandbox

You wantSend
A billAny account number
No bill foundAn account number ending in 0000
Writes money

Pay a bill

POST/v1/bbps/pay

Pay a bill from your wallet.

Request body

FieldTypeNotes
referenceIdstringRequired. Your unique id, 6 to 60 letters, numbers, - or _. It is the idempotency key.
operatorCodestringRequired.
accountstringRequired.
mobilestringRequired. Customer mobile.
senderNamestringRequired.
categorystringRequired.
amountnumberRequired. Rupees, 1 to 2,00,000, up to 2 decimals. Use the amount from the bill.

Response

FieldMeaning
referenceIdYour reference, returned unchanged
typeThe kind of transaction
amount, fee, totalDebitRupees. totalDebit is amount plus fee.
statussuccess, failed or pending
utrReference number from the bank or biller, when available
reasonWhy it failed, empty otherwise
environmentsandbox or production

Debit and refund. A live call debits amount + fee from your wallet first. If it fails, the full debit returns to your wallet. If the bank has not answered, the status is pending and the debit stays. Call the status endpoint to follow it up. Never retry with a new reference.

Idempotency. A referenceId that already exists returns the original result with "duplicate": true. Nothing new is debited.

Test in the sandbox

You wantSend
SuccessAny account number
FailureAn account number ending in 0000
DuplicateThe same referenceId twice

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Bill payment status

GET/v1/bbps/pay/{referenceId}

Fetch a bill payment by your own reference.

Use this when a request timed out, or when the status was pending. If you are unsure whether a pay call reached BankMe, call this first. Do not pay again with a new reference.

Check a sender

POST/v1/dmt/sender

Check whether a customer (the sender) is already registered for money transfer.

Send money in five steps. Check the sender, register them if needed, add the recipient, request the OTP, then transfer. Each step has its own call below.

Limits and fees

RuleValue
Minimum per transferRs 100
Maximum per transferRs 49,999
Per customer per dayRs 2,00,000
Sender fee, up to Rs 25,0001% including GST, minimum Rs 10
Sender fee, Rs 25,001 to Rs 49,999Rs 295 (Rs 250 plus 18% GST)
Customer confirmationEvery transfer is confirmed with the OTP sent to the customer's mobile

Request body

FieldTypeNotes
mobilestringRequired. The sender's 10 digit mobile.

Test in the sandbox

You wantSend
A registered senderAny mobile number
A sender not yet registeredA mobile number ending in 0000

Sandbox first. Use your sandbox key on https://sandbox.bankme.co.in. Results are simulated, your wallet is never debited and no real money moves.

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Register a sender

POST/v1/dmt/sender/register

Register a new sender before their first transfer.

Request body

FieldTypeNotes
mobilestringRequired.
namestringRequired. As on the sender's ID.
dobstringRequired. YYYY-MM-DD.
linestringRequired. Address line.
citystringRequired.
statestringRequired.
pincodestringRequired.
district, areastringOptional.

List recipients

GET/v1/dmt/recipients

List the recipients already saved for a sender.

Query

FieldTypeNotes
mobilestringRequired. The sender's mobile.

Add a recipient

POST/v1/dmt/recipient

Save a bank account as a recipient for a sender.

Request body

FieldTypeNotes
mobilestringRequired. The sender's mobile.
recipientNamestringRequired. Account holder name.
accountstringRequired. 6 to 20 digits.
ifscstringRequired. Valid IFSC code.
recipientMobilestringOptional. Defaults to the sender's mobile.

Check the account first. Call Verify a document with bank_pennyless or bank_pennydrop before you save the recipient. It confirms the account holder's name and avoids failed transfers.

Send the transfer OTP

POST/v1/dmt/otp

Send the confirmation OTP to the sender's mobile for one transfer.

Request body

FieldTypeNotes
mobilestringRequired. The sender's mobile.
recipientIdintegerRequired. From the recipient calls.
amountnumberRequired. Rs 100 to Rs 49,999.

Response

FieldMeaning
otp.otpRefIdSend this with the transfer, together with the OTP the customer received

The call is refused with LIMIT_PER_DAY if the amount is more than the customer can still send today.

Writes money

Transfer money

POST/v1/dmt/transfer

Send money to the recipient's bank account.

Request body

FieldTypeNotes
referenceIdstringRequired. Your unique id, 6 to 60 letters, numbers, - or _. It is the idempotency key.
mobilestringRequired. The sender's mobile.
recipientIdintegerRequired.
amountnumberRequired. Rs 100 to Rs 49,999.
otpstringRequired. The OTP the sender received.
otpRefIdstringRequired. From the OTP call.
statestringOptional. State code. A default is used if you leave it out.

Response

FieldMeaning
referenceIdYour reference, returned unchanged
typeThe kind of transaction
amount, fee, totalDebitRupees. totalDebit is amount plus fee.
statussuccess, failed or pending
utrReference number from the bank or biller, when available
reasonWhy it failed, empty otherwise
environmentsandbox or production

Debit and refund. A live call debits amount + fee from your wallet first. If it fails, the full debit returns to your wallet. If the bank has not answered, the status is pending and the debit stays. Call the status endpoint to follow it up. Never retry with a new reference.

Commission, where your agreement includes it, is credited back to your wallet when a transfer succeeds.

Test in the sandbox

You wantSend
SuccessOTP 123456
FailureOTP 000000. The result is failed with the reason "Sandbox: simulated failure".
Wrong OTPAny other OTP. The call is refused with INVALID_OTP.
Above the limitAn amount over 49,999. The call is refused with LIMIT_PER_TXN.
DuplicateThe same referenceId twice

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Transfer status

GET/v1/dmt/transfer/{referenceId}

Fetch a transfer by your own reference.

Use this when a request timed out, or when the status was pending. Never create a new transfer with a new reference to retry.

Balance enquiry

POST/v1/aeps/balance

Check a customer's bank balance with their Aadhaar and fingerprint.

AEPS needs a registered merchant. BankMe sets up your merchant account when it activates AEPS for you. Calls come from a certified fingerprint device at the customer's side.

Request body

FieldTypeNotes
customerIdstringRequired. The customer's 10 digit mobile.
aadhaarstringRequired. 12 digit Aadhaar number.
latlongstringRequired. The device location, for example 11.0168,76.9558.
bankCodestringRequired. The customer's bank code.
piddatastringRequired for balance, statement and withdrawal. The biometric capture from the fingerprint device. Never store it.

Test in the sandbox

You wantSend
SuccessAny 12 digit Aadhaar number
FailureAn Aadhaar number ending in 0000. The response says the biometric did not match.

Sandbox first. Use your sandbox key on https://sandbox.bankme.co.in. Results are simulated, your wallet is never debited and no real money moves. Use any text for piddata in the sandbox.

Going live. BankMe activates each API for production after your integration is approved. Until then, live calls are refused with NOT_ACTIVATED or NOT_AVAILABLE.

Mini statement

POST/v1/aeps/mini-statement

Get the last few transactions of the customer's account.

Request body

Same fields as Balance enquiry.

Withdrawal OTP

POST/v1/aeps/withdrawal-otp

Request the OTP for a cash withdrawal above Rs 5,000.

Request body

FieldTypeNotes
customerIdstringRequired. The customer's 10 digit mobile.
aadhaarstringRequired. 12 digit Aadhaar number.
latlongstringRequired. The device location, for example 11.0168,76.9558.
bankCodestringRequired. The customer's bank code.
amountintegerRequired. Whole rupees, above 5000.

Withdrawals of Rs 5,000 or less do not need an OTP. Use the withdrawal call directly.

Writes money

Cash withdrawal

POST/v1/aeps/withdrawal

Pay cash to the customer against their Aadhaar and fingerprint.

Request body

FieldTypeNotes
customerIdstringRequired. The customer's 10 digit mobile.
aadhaarstringRequired. 12 digit Aadhaar number.
latlongstringRequired. The device location, for example 11.0168,76.9558.
bankCodestringRequired. The customer's bank code.
piddatastringRequired for balance, statement and withdrawal. The biometric capture from the fingerprint device. Never store it.
amountintegerRequired. Whole rupees.
txnOtpRequestIdstringRequired when the amount is above 5000. From the withdrawal OTP call.

Your commission on a successful withdrawal is credited to your wallet as per your agreement.

Test in the sandbox

You wantSend
SuccessAny valid Aadhaar number
FailureAn Aadhaar number ending in 0000
Above Rs 5,000Send txnOtpRequestId from the withdrawal OTP call

Errors for the other APIs

Verification, BBPS, DMT and AEPS answer errors in the same shape as the Payout API: success false, a code and a message.

CodeHTTPMeaning
INVALID_INPUT400A field is missing or in the wrong format. The message names it.
INVALID_REFERENCE400referenceId must be 6 to 60 letters, numbers, - or _.
INVALID_AMOUNT400The amount is outside the allowed range.
LIMIT_PER_TXN400A DMT transfer is above Rs 49,999.
LIMIT_PER_DAY422The customer has used the Rs 2,00,000 daily DMT limit.
INVALID_OTP422Sandbox only. Use 123456 or 000000.
INSUFFICIENT_BALANCE402Your wallet is too low. Nothing was debited.
NOT_ACTIVATED403This API is not activated for production on your account.
PARTNER_INACTIVE403Your partner account is not active.
NOT_AVAILABLE503Live access is not switched on yet. Use the sandbox.
UNKNOWN_PRODUCT404The verification product id does not exist.
NOT_FOUND404No transaction with this referenceId.
IN_PROGRESS409The same referenceId is still being processed. Wait, then check the status.
REQUEST_FAILED422The provider could not complete the request. Check your input.
PROVIDER_ERROR502The bank or provider is not available. You were not charged. Try again.
SERVER_ERROR500Something went wrong on our side. You were not charged.

A request that fails validation never debits your wallet. For a timeout, check the status endpoint before you try again.

Webhooks

BankMe posts the result of each payout to the HTTPS URL registered for your key. Use it instead of polling.

Events

EventSent when
payout.successA payout was paid
payout.failedA payout failed and was refunded
webhook.testA test delivery was requested

Headers on every delivery

HeaderValue
x-bankme-eventThe event name
x-bankme-timestampUnix time of the delivery
x-bankme-signaturesha256= followed by the hex HMAC-SHA256 of timestamp + "." + rawBody, keyed with your signing secret (starts with whsec_)

Delivery rules

  • Reply with any 2xx status within a few seconds to acknowledge. Anything else counts as a failure.
  • Failed deliveries are retried automatically, so you can receive the same event more than once. Make your handler idempotent by looking up the payout by referenceId.
  • The webhook URL must be https and use a public domain name. IP addresses, localhost and private networks are rejected.
  • If your firewall limits inbound traffic, allow BankMe's outbound ranges: 74.220.52.0/24 and 74.220.60.0/24.
  • A lost webhook never loses the result. Fetch it any time with Payout status.

Verify a webhook

Always check the signature before you trust a delivery.

  1. Read the raw request body as received. Do not parse and re-encode it first.
  2. Build the string timestamp + "." + rawBody.
  3. Compute HMAC-SHA256 of it with your whsec_ secret and compare with x-bankme-signature in constant time.
  4. Reject deliveries whose timestamp is more than 5 minutes old.
  5. Process the event, then reply 200.

Store your whsec_ secret in server-side configuration, never in code. If it leaks, ask BankMe to rotate it.

Send a test webhook

POST/v1/webhook/test

Sends a signed webhook.test delivery to your registered URL so you can check your handler end to end.

Works in the sandbox and in production. Your endpoint should verify the signature and reply 200 exactly as for a real event.

Sandbox testing

The sandbox behaves like production but never moves money and never debits a wallet.

You wantSend
SuccessAny valid beneficiary, for example account 123456789012
FailureA bank account number ending in 0000, or a UPI ID starting with fail. The result is failed with the reason "Sandbox: simulated failure".
DuplicateSend the same referenceId twice. The second response has "duplicate": true.

Sandbox payouts carry "environment": "sandbox" and a UTR starting with SBX. Webhooks are delivered from the sandbox too and signed the same way.

Go-live checklist

  1. Your integration passes the sandbox tests: success, failure, duplicate and webhook handling.
  2. Your API secret and webhook signing secret are in server-side configuration.
  3. Every payout uses a new, unique referenceId. You reuse one only to retry the same payout.
  4. You called GET /v1/ip from your production server and gave that IP address to BankMe.
  5. Your webhook endpoint verifies the signature and replies with 2xx.
  6. BankMe issues your production key. Change the base URL to https://api.bankme.co.in and use the production key and secret.
  7. Make a first small live payout (Rs 100) and confirm the UTR before going to volume.

Payouts are paid from your own BankMe wallet. Keep it funded before you send live payouts.