Build with the BankMe Payout API
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.
referenceId never pays twice.How it works
- BankMe issues you a sandbox key (
pk_...andsk_...). Production keys follow after your integration is approved. - Your server calls Create payout with a unique
referenceId. - BankMe debits your wallet and sends the money. The result comes back in the response or as a webhook.
- 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.
| Environment | Base URL | Does money move? |
|---|---|---|
| Sandbox | https://sandbox.bankme.co.in | No. Results are simulated and your wallet is never debited. |
| Production | https://api.bankme.co.in | Yes. 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.
| Header | Required | Value |
|---|---|---|
x-api-key | Yes | Your key id, starts with pk_ |
x-api-secret | Yes | Your secret, starts with sk_. Shown once when the key is created. |
Content-Type | On POST | application/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.
Create payout
Send money to a bank account or UPI ID.
Request body
| Field | Type | Notes |
|---|---|---|
referenceId | string | Required. Your own unique id for this payout. It is the idempotency key. |
amount | integer | Required. Whole rupees, minimum 100. |
beneficiary | object | Required. Bank or UPI, see below. |
remarks | string | Optional. Up to 60 characters. |
Beneficiary: bank account
| Field | Notes |
|---|---|
type | "bank" |
name | Account holder name. Letters, spaces and dots only. |
accountNumber | 9 to 18 digits |
ifsc | Valid IFSC code, for example HDFC0001234 |
mode | "IMPS" (default) or "NEFT" |
Beneficiary: UPI
| Field | Notes |
|---|---|
type | "upi" |
name | Beneficiary name |
vpa | UPI ID, for example name@bank |
Response
| Field | Meaning |
|---|---|
payoutId | BankMe's id for the payout |
referenceId | Your reference, returned unchanged |
amount, fee, totalDebit | Rupees. totalDebit is amount plus fee. |
status | pending, processing, success or failed |
utr | Bank reference number, filled when the payout succeeds |
reason | Why a payout failed, empty otherwise |
environment | sandbox or production |
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 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
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
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
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
| Item | Value |
|---|---|
| Minimum per payout | Rs 100 |
| Maximum per payout | Up to Rs 2,00,000. Your key may have a lower limit. |
| Daily limit | Rs 5,00,000 by default, set per key. The day resets at midnight IST. |
| Fee | Slab based, from Rs 10 to Rs 100 per payout, GST included. The exact fee is returned in fee. |
| Rate limit | 120 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.
| Code | When it happens |
|---|---|
AUTH_REQUIRED | Missing, wrong or disabled key or secret, or the call came from an IP that is not allowed. |
INVALID_AMOUNT | Amount is not a whole number, or is below Rs 100. |
INVALID_BENEFICIARY | A beneficiary field is missing or badly formatted. The message names the field. |
LIMIT_PER_TXN | Amount is above the per-payout limit. |
LIMIT_PER_DAY | The daily limit would be exceeded. The message shows what is left today. |
INSUFFICIENT_BALANCE | The wallet cannot cover amount plus fee. |
RAIL_UNAVAILABLE | The payout route for your key is not available right now. Try again later. |
OWNER_NOT_FOUND | The 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.
Webhooks
BankMe posts the result of each payout to the HTTPS URL registered for your key. Use it instead of polling.
Events
| Event | Sent when |
|---|---|
payout.success | A payout was paid |
payout.failed | A payout failed and was refunded |
webhook.test | A test delivery was requested |
Headers on every delivery
| Header | Value |
|---|---|
x-bankme-event | The event name |
x-bankme-timestamp | Unix time of the delivery |
x-bankme-signature | sha256= followed by the hex HMAC-SHA256 of timestamp + "." + rawBody, keyed with your signing secret (starts with whsec_) |
Delivery rules
- Reply with any
2xxstatus 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
httpsand 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/24and74.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.
- Read the raw request body as received. Do not parse and re-encode it first.
- Build the string
timestamp + "." + rawBody. - Compute HMAC-SHA256 of it with your
whsec_secret and compare withx-bankme-signaturein constant time. - Reject deliveries whose timestamp is more than 5 minutes old.
- 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
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 want | Send |
|---|---|
| Success | Any valid beneficiary, for example account 123456789012 |
| Failure | A bank account number ending in 0000, or a UPI ID starting with fail. The result is failed with the reason "Sandbox: simulated failure". |
| Duplicate | Send 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
- Your integration passes the sandbox tests: success, failure, duplicate and webhook handling.
- Your API secret and webhook signing secret are in server-side configuration.
- Every payout uses a new, unique
referenceId. You reuse one only to retry the same payout. - You called GET /v1/ip from your production server and gave that IP address to BankMe.
- Your webhook endpoint verifies the signature and replies with
2xx. - BankMe issues your production key. Change the base URL to
https://api.bankme.co.inand use the production key and secret. - 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.