Sending money to a bank account you have not verified is a bet that a human typed fourteen digits correctly. Sometimes the bet fails by accident: a transposed digit, a closed account, a name that does not match. Sometimes it fails on purpose: an account that belongs to someone else, swapped in just before settlement. The cost is never only the amount. It is the time to chase a recovery, the support tickets, the finance reconciliation and the payee who did not get paid and now tells everyone. Verifying the account before the first payout, and again when it changes, turns that bet into a check that costs a few rupees and takes a few seconds.
This page is for teams that pay people at scale: gig and marketplace platforms paying sellers and workers, lenders disbursing loans, insurers settling claims, payroll providers, apps issuing refunds, and creator platforms. It explains what the StampMitra bank-account endpoint returns, where to put verification in a payout pipeline, how to set name-match policies for different payout types, how to pre-validate a large payee list, and what the check costs. The endpoint confirms what the source says about an account and a name; it does not authorise a payment, assess a payee's trustworthiness, or replace your payment provider's own controls.
Key takeaways
- Verify at three moments: before the first payout to an account, whenever an account changes, and when a payout to it comes back. That covers the cases where unverified accounts cause losses.
- The call is
POST /v1/verify/bank-accountwithaccountNumber,ifsc, and ideallyname, plus an optionalphone. Readvalid,accountStatus,nameAtBank,nameMatchScoreandnameMatchResult, and keep thereferenceId. - Different payout types deserve different name-match policies. A salary account tolerates less mismatch than a joint refund account; set the policy per payout type, not globally.
- Pre-validate formats locally: IFSC has eleven characters with a zero in the fifth position, and account numbers for this endpoint are nine to eighteen digits.
valid: falseis a completed, billable answer, not an error. Retry only 429 and 502.- The bank-account rate is the same on every plan, so a plan fee does not make this check cheaper. Choose a plan on your other usage, not on this endpoint.
- A hold-then-release design is safer than blocking at entry: let payees save details, but have the payout service refuse unverified accounts.
What goes wrong when you pay an unverified account
Five failure patterns account for most payout losses and support load.
Typos. Account numbers are long. One wrong digit sends money to a stranger or, more often, bounces it back days later. Either way a payee waits.
Wrong IFSC. The account number is right but the branch code is not, so the payment fails or lands somewhere unexpected.
Closed or frozen accounts. The account was valid when the payee signed up and is not valid now. Payouts return, and the payee blames you.
Name mismatch. The account exists but belongs to someone else, perhaps a relative, an agent, or a fraudster. Even when it is innocent, regulations or your own policy may not allow paying a third party.
Account swap. A genuine payee's account details are changed through a compromised login or a fraudulent request just before a large settlement.
A bank-account check addresses all five at the moment of entry, and the account-change rules below address the last one specifically.
What the endpoint returns, field by field
The documented response for a bank-account verification looks like this, with sample values:
{
"referenceId": "SMV-20260927-3B71A0",
"valid": true,
"nameAtBank": "RAVI KUMAR",
"bankName": "ICICI Bank",
"utr": "017952100012345",
"city": "Mumbai",
"branch": "Andheri West",
"micr": "400229002",
"nameMatchScore": "100",
"nameMatchResult": "GOOD_MATCH",
"accountStatus": "ACCOUNT_IS_VALID",
"accountStatusCode": "1",
"ifscDetails": {
"bank": "ICICI Bank",
"ifsc": "ICIC0001234",
"micr": "400229002",
"address": "Andheri West, Mumbai",
"city": "Mumbai",
"state": "Maharashtra",
"branch": "Andheri West"
}
}| Field | What it tells you | How to use it |
|---|---|---|
referenceId | StampMitra's transaction id for this call, present on negative results too | Store it with the payee record; quote it to support |
valid | Whether the verification succeeded for the account | false means do not pay this account; ask the payee for another |
accountStatus and accountStatusCode | The account state as returned by the source | Treat only the value that means a valid account as a pass; send anything else to review, including values you have not seen before |
nameAtBank | The holder name as the bank reports it | Show to reviewers only; do not display it to the payee or the public |
nameMatchScore | A number, as a string, for how the supplied name compares with nameAtBank | Convert to a number and compare with your threshold |
nameMatchResult | A label for the comparison, such as the good-match value in the sample | Use it as a secondary signal; treat unknown labels as review |
utr | A reference for the verification transaction, where returned | Store with the evidence |
bankName, branch, city, micr | What the IFSC resolves to | Compare the bank with the one the payee declared |
ifscDetails | Structured branch details | Useful for showing the payee "we found ICICI Bank, Andheri West" so they can confirm |
Three practical notes follow. First, the response shape for negative results is documented only in terms of the same valid flag and a referenceId, so write defensive code that does not assume every field is present. Second, the input name is optional, but without it you have no name-match result, which removes the most valuable part of the check for payouts. Always send the payee's legal name. Third, an optional phone field exists for the account holder's ten-digit Indian mobile number, which the documentation says improves match confidence when available.
Where to put the checks in a payout pipeline
A pipeline has more control points than most teams use. The table lists the five worth building, ordered by how much loss they prevent.
| Control point | Trigger | Check | Decision |
|---|---|---|---|
| 1, first payout | A payee adds an account or a payout is first scheduled | Verify account with legal name | Release or hold |
| 2, account change | A payee edits account or IFSC | Verify new account; restart cooling-off | Release after cooling-off, or hold |
| 3, dormant reactivation | A payee returns after a long gap | Re-verify the stored account | Update status |
| 4, return handling | A payout bounces | Re-verify, ask the payee to confirm | Fix or replace the account |
| 5, periodic refresh | Policy interval for high-value payees | Re-verify | Update status; flag changes |
If you can only build one, build the first. If you can build two, add the second, because account changes are the favourite route for fraud.
The workflow, step by step
- Capture the account at the moment of need. Ask for account number, IFSC and the holder's name when the payee has money waiting or is about to. Say clearly that the account must be in the payee's own name. Decision: nothing is paid yet; the account is saved as "unverified".
- Normalise and pre-validate locally. Remove spaces, upper-case the IFSC, check that the IFSC is eleven characters with a zero in the fifth, check that the account number is nine to eighteen digits. Decision: ask the payee to correct it, or continue.
- Check for duplicates in your own data. Look up a keyed hash of the account number and IFSC in your payee table. Decision: if the account already belongs to another payee, route to review before paying.
- Call the endpoint.
POST /v1/verify/bank-accountwithaccountNumber,ifsc,nameand optionallyphone. Decision tree below. - Interpret the response.
valid: false: hold and ask for another account.valid: truewith a strong score: mark verified. A middling score: review. A weak score: hold. - Show the payee what you found. Display bank and branch from the IFSC details, not the name at the bank, and let the payee confirm. Decision: payee confirms or corrects.
- Release or hold. The payout service checks the verified state and the cooling-off window and either releases or holds. Decision: this check lives in the payout service, not in the app.
- Pay and watch for returns. If a payout bounces, mark the account as "failed", ask the payee to re-confirm details and re-verify before paying again.
- Record the evidence.
referenceId, time, the key fields, your decision and rule version.
curl -X POST "https://api-b2b.stampmitra.in/v1/verify/bank-account" \
-H "Authorization: Bearer $STAMPMITRA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"accountNumber":"000123456789","ifsc":"ICIC0001234","name":"Ravi Kumar","phone":"9876543210"}'A payout gate in code
The Node function below turns a response into a payout decision, with thresholds per payout type. The numbers are placeholders for you to tune.
const POLICY = {
salary: { release: 90, review: 70 },
vendor: { release: 90, review: 65 },
refund: { release: 80, review: 55 },
claim: { release: 92, review: 75 },
creator: { release: 85, review: 60 },
};
export async function decidePayoutAccount({ payoutType, accountNumber, ifsc, legalName, phone }) {
const res = await fetch("https://api-b2b.stampmitra.in/v1/verify/bank-account", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.STAMPMITRA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ accountNumber, ifsc, name: legalName, ...(phone ? { phone } : {}) }),
});
if (res.status === 429 || res.status === 502) return { action: "retry_later", status: res.status };
if (res.status === 402) return { action: "ops_alert", reason: "wallet" };
const body = await res.json();
if (!res.ok) return { action: "fix_input", requestId: body.error?.requestId };
if (!body.valid) return { action: "hold", reason: "account_not_valid", ref: body.referenceId };
const p = POLICY[payoutType] ?? POLICY.salary;
const score = Number(body.nameMatchScore);
if (Number.isNaN(score)) return { action: "review", reason: "no_score", ref: body.referenceId };
if (score >= p.release) return { action: "release", ref: body.referenceId };
if (score >= p.review) return { action: "review", reason: "name_partial", ref: body.referenceId };
return { action: "hold", reason: "name_mismatch", ref: body.referenceId };
}Name-match policy by payout type
One threshold for everything is the most common mistake. The right tolerance depends on who is being paid, how much, and what happens if the account is wrong.
| Payout type | Typical risk | Suggested stance |
|---|---|---|
| Salary or wages | Repeated, moderate value, long relationship | Strict on first payout; allow review for initials and married names; re-verify on any change |
| Vendor or supplier payments | Large value, business names, trade names | Compare against the legal name of the firm; allow trade-name variants through review; never pay a personal account for a company vendor without a documented reason |
| Customer refunds | Small to moderate, many payees, accounts entered once | Slightly looser threshold, with a review band; many refunds go to joint or family accounts |
| Insurance or claim settlement | Higher value, fraud pressure | Strict thresholds; second approver above a value limit; verify immediately before payment, not at claim intake |
| Creator or seller payouts | Frequent, variable, many new accounts | Moderate threshold, cooling-off after changes, duplicate-account detection |
| Loan disbursal | High value, one-off | Strict; the account must be the borrower's; hold on any mismatch |
These are starting points. Review your own mismatch data after the first month and adjust, and keep a record of the thresholds in force at the time of each payout.
Names that look different and are not
Bank accounts show names in many forms: with initials, in a different order, with titles, abbreviated, or truncated by the bank's systems. A business account may carry the registered name, a trade name or both. A joint account lists several holders. A minor's account carries a guardian. A woman's account may carry a name from before or after marriage.
The endpoint's score handles ordinary variation, and your review band handles the rest. For reviewers, show the name you supplied next to the name at the bank and the score, and give them a short list of acceptable reasons ("initials", "order", "married name", "trade name of registered firm", "joint account with payee as first holder") plus a free-text field. Record the reason. If one reason appears often, it is a candidate for a rule.
Never ask a payee to "match" the name by editing the name you hold in your own system to whatever the bank says, without reviewing why. That turns a control into a formality.
Bulk pre-validation of a payee list
Many teams meet this endpoint through a spreadsheet: ten thousand payees uploaded for a payout run. Treat it as a batch job with rate limits, cost and resumability in mind.
Pre-validate formats first and reject malformed rows without any call. Deduplicate rows by a normalised account and IFSC so that the same account is verified once. Order the batch so that the highest-value payouts are verified first. Run a small worker pool inside your plan's rate limit (the documented error example is 60 requests per 60 seconds; read your own limit from the dashboard and the pricing page). Write each result to a table keyed by payee and account, so that a restart skips what is done, and stop the batch on a 402 wallet error instead of retrying it.
import os
import time
import requests
BASE = "https://api-b2b.stampmitra.in"
HEADERS = {
"Authorization": f"Bearer {os.environ['STAMPMITRA_API_KEY']}",
"Content-Type": "application/json",
}
def verify_row(row: dict) -> dict:
for attempt in range(4):
r = requests.post(
f"{BASE}/v1/verify/bank-account",
headers=HEADERS,
json={"accountNumber": row["account"], "ifsc": row["ifsc"], "name": row["name"]},
timeout=20,
)
if r.status_code in (429, 502):
time.sleep(2 ** attempt + 0.3)
continue
if r.status_code == 402:
raise RuntimeError("wallet empty: stop the batch")
return {"status": r.status_code, "body": r.json()}
return {"status": 0, "body": {}}
def run_batch(rows, done: set, save):
for row in rows:
key = f"{row['account']}|{row['ifsc']}"
if key in done:
continue
save(key, verify_row(row))
done.add(key)
time.sleep(1.1) # stay inside the per-minute windowAccount changes and dormant payees
Account changes are the highest-risk event in the payout lifecycle, because they are exactly what a fraudster needs. Treat every change as a new first payout with extra rules. Verify the new account with the payee's legal name. Require a fresh login and, where you have one, a second factor on the payee's verified mobile. Send a notification to the old contact details as well as the new, so that a genuine payee notices a change they did not make. Start a cooling-off period before the first payout to the new account, and make it longer for larger payees. Keep the old account on record, marked inactive, so that an investigation can see the sequence.
Dormant payees are the quieter version of the same risk. A payee who has not been paid for a long time and suddenly changes details or asks for a payout is worth a re-verification, because the stored account may have closed, and because dormant profiles are targets for takeover.
When a payout comes back
Returned payouts are information. The usual causes are a wrong account number, a closed account, a name restriction at the receiving bank, or an IFSC that does not match. When a payout returns, mark the account as failed, stop further payouts to it, tell the payee what to do, and re-verify the corrected or replacement account before paying again. Do not re-send blindly: repeated failed attempts cost money and trust, and may be a sign of an account takeover. Record the return reason alongside the verification evidence so that you can see patterns, such as one bank or one channel producing most of your returns.
Business, joint and third-party accounts
Not every payee is an individual paying into a personal savings account, and the policy should say what you do with the others.
For business payees, the account name is usually the registered name of the firm or company, and sometimes a trade name. Pair the bank check with a registry check on the entity, so that you compare the name at the bank with a legal name you have already verified. The vendor onboarding page describes that pairing. A personal account for a company payee is a red flag unless a documented reason exists, such as a sole proprietor whose account is in their own name.
For joint accounts, the name at the bank lists more than one holder, and the score against a single name may be moderate. Decide in policy whether you accept a joint account when the payee is a holder, and what evidence a reviewer needs. Whatever you decide, apply it consistently, and record the reason on the payee record.
For third-party accounts, where a payee asks you to pay someone else, the safest default is to refuse unless a documented, reviewed arrangement exists. Third-party payments are a common route for fraud and often raise questions with your payment provider and, if you are regulated, your compliance function. If you do allow them, treat the third party as a payee in their own right, verify their account, and keep the authority document with the record.
For minors and guardians, the account may be in the guardian's name or a joint name. Your policy should say which documents you need and who the legal payee is.
Payment providers, payee messages and audit questions
What your payment provider does and what this check adds
Your payment provider or bank has its own controls, and some of them check account details at the time of payment. This verification is not a replacement for those controls and not a duplicate of them. It adds three things that are hard to get from the payment rail alone.
The first is timing. You find out that an account is wrong when the payee enters it, not days later when the payout bounces. The second is the name match. A payment can succeed to an account whose holder is not the person you meant to pay, and the match gives you a signal before the money moves. The third is evidence. You have a transaction id and a decision record for each account, which you can show to an auditor or to a payee who disputes a hold.
It also changes your cost profile. Failed and returned payouts cost handling time, communication and sometimes fees. Catching a bad account at entry is cheaper than catching it at return, though we have no industry figure to quote and you should measure your own return rate before and after.
Talking to payees so that holds do not become complaints
Most payees who hit a hold are honest, and the way you tell them decides whether it becomes a support ticket. Say what you need and why, in plain words, and give a clear next step.
A good hold message names the problem in general terms ("we could not match this account to your name"), says what the payee can do ("check the account number and IFSC, or add an account in your own name"), and tells them what happens next ("your payout will be released as soon as the account is confirmed"). It shows a reference they can quote. It does not reveal the name at the bank, whether the account exists, or whether another payee uses it.
Offer one self-service retry before anything goes to a human, because most mismatches are typing errors. After that, offer a simple way to upload a document, such as a cancelled-cheque image or a bank statement page, for a reviewer to compare. Tell the payee how long review usually takes and keep the promise. If a payee waits longer than you said, tell them why.
For account changes, send notifications on the payee's verified mobile number and email, to both the old and the new contact where you hold them. A genuine payee who did not make a change will see it and report it, and that report is the earliest warning you will get of an account takeover.
Audit and finance questions you should be able to answer
Payout controls are examined by auditors, finance leads and sometimes regulators. A clean evidence record lets you answer the usual questions quickly.
How do you know a payee's account belonged to them at the time of payout? Show the verification record, its transaction id, the name score and the decision. Who approved a payout to an account with a weak match? Show the reviewer, the reason and the time. How do you stop a changed account from receiving a large payment immediately? Show the cooling-off rule and its log. How many payouts returned last quarter, and why? Show returns by reason, with the share that had no verification at the time. What happens during an outage of the verification service? Show the fail-closed rule and the held queue.
Build the evidence as an exportable report from the first day. It is much easier to define the report when the first auditor asks than to reconstruct it from logs.
Decision table: valid, mismatch, inactive, not found
| Outcome | What the response shows | Payout action | Payee message |
|---|---|---|---|
| Valid and strong name match | valid: true, valid account status, high score | Mark verified; release after any cooling-off | "Account confirmed." |
| Valid, partial name match | valid: true, score in the middle band | Review with both names; release on approval | "We are checking your account details." |
| Valid, weak name match | valid: true, low score | Hold; ask for an account in the payee's own name or a document | "We could not match this account to your name." |
| Inactive or not valid | valid: false or an account status that is not the valid value | Hold; do not retry; ask for another account | "This account could not be verified. Please check the details or use another account." |
| Not found or malformed | A 400 for a bad format, or a not-valid result for a well-formed number | Fix the input once; otherwise hold | "Please check the account number and IFSC." |
| Call failed | 429, 502 or timeout | Keep the payout held; retry with backoff | "Verification is taking longer than usual." |
Five scenarios from a payout operations desk
These are hypothetical cases.
The first payout
A seller adds an account the day their first order is delivered. The format checks pass, the endpoint returns a valid account with a strong name match, and the payout is released after the platform's standard holding period.
The relative's account
A delivery partner enters an account that belongs to their spouse. The name score is low. The platform's policy for gig partners allows a documented joint-account exception; the reviewer asks for a bank statement page showing both holders, records the reason and approves. The decision and document are attached to the payee record.
The swapped account
A seller with a long history changes their payout account the evening before a large settlement. The new account verifies as valid but the name at the bank is a different person. The change is held, the settlement goes to the old verified account, the seller is notified on their verified mobile, and the case goes to the risk queue.
The returned salary
A salary credit returns with an account-closed reason. The payroll system marks the account failed and asks the employee for a new one through the HR portal. The new account is verified before the next run, and the employee is paid by the correction run. No payment was attempted to the failed account a second time.
The bulk refund run
A retailer pre-validates 8,000 refund payees before a bulk refund after a recalled product. The batch drops 300 malformed rows without calls, deduplicates 150 repeats, and verifies the rest at a measured pace. A few hundred land in review; the rest are released. The run finishes with a reconciliation of verified, held and returned counts.
Review rules a payout team can copy
These are suggestions for your policy to adapt.
- No first payout to an unverified account. The gate lives in the payout service.
- Policy by payout type. Thresholds per type, recorded with a version.
- Hold on any change, then cool off. Re-verify the new account, notify old and new contacts, wait before the first payout.
- Value limits. Above a limit, a second approver and a fresh verification immediately before payment.
- Never auto-pay on a failed call. A timeout is not a pass.
- Duplicate detection. The same account on more than one payee goes to review.
- Review reasons are written. Reviewers pick a reason from a short list and may add text.
- Return handling. A returned payout freezes the account until it is re-verified.
Operating model
Two queues cover most needs. The payout-review queue holds partial and weak name matches, account changes and duplicates; it is worked by payout operations analysts with a named senior approver. The platform queue holds failed calls, wallet alerts and batch stops; it belongs to engineering or the on-call operator. Set targets that match payee expectations: payees waiting for money want answers the same day, so review items should be measured in hours, with the oldest item visible to the whole team. Keep a weekly review of mismatch reasons and returns so that rules improve.
What to store and for how long
Store, per verification, the referenceId, time, key response fields (valid flag, account status, score, result), the decision, the rule version, the reviewer and the reason. Store account numbers in encrypted fields with access control, show them masked, and keep them out of logs. For duplicate detection, use a keyed hash of the account and IFSC rather than the raw values. The name at the bank is personal data: keep it in the evidence store with the same controls and show it only to reviewers.
Retention depends on payments and accounting rules, tax law, your contracts, regulator requirements if you are a regulated entity, and data-protection law for individual payees. We cannot give you the periods. Ask your counsel, write them into a schedule and automate deletion. StampMitra's handling of data is described in its retention and deletion schedule and data processing addendum. You can also use GET /v1/logs to see request logs for your account and GET /v1/usage/summary for usage totals; log retention depends on your plan and the details are on the pricing page.
What it costs: flat per check, three volumes
The bank-account check is ₹4 per call on every plan, and the same on pay as you go, Growth and Scale. All figures exclude GST at 18 percent. That has one unusual consequence worth stating plainly: because the rate does not fall with the plan, a plan fee never makes this endpoint cheaper. Pay-as-you-go is the cheapest way to run bank checks alone. Growth and Scale make sense only if you also use standard calls (PAN, GSTIN and so on) that do get cheaper, or if you need the higher rate limits, longer log retention and other plan features.
The cost of one verification:
| Plan | Cost of one bank-account verification before GST |
|---|---|
| Pay as you go | ₹4 |
| Growth | ₹4 |
| Scale | ₹4 |
And the same check next to a PAN verification of the payee, as many payout flows pair them:
| Plan | Cost of PAN plus bank account before GST |
|---|---|
| Pay as you go | ₹9 |
| Growth | ₹8 |
| Scale | ₹7.50 |
The monthly view for three volumes of newly verified payees. At 1,000 payees a month, the bank checks alone:
| Plan | Usage charges | Plan fee | Subtotal | GST at 18% | Total for the month |
|---|---|---|---|---|---|
| Pay as you go | ₹4,000 | ₹0 | ₹4,000 | ₹720 | ₹4,720 |
| Growth | ₹4,000 | ₹999 | ₹4,999 | ₹899.82 | ₹5,898.82 |
| Scale | ₹4,000 | ₹4,999 | ₹8,999 | ₹1,619.82 | ₹10,618.82 |
At 10,000 payees a month:
| Plan | Usage charges | Plan fee | Subtotal | GST at 18% | Total for the month |
|---|---|---|---|---|---|
| Pay as you go | ₹40,000 | ₹0 | ₹40,000 | ₹7,200 | ₹47,200 |
| Growth | ₹40,000 | ₹999 | ₹40,999 | ₹7,379.82 | ₹48,378.82 |
| Scale | ₹40,000 | ₹4,999 | ₹44,999 | ₹8,099.82 | ₹53,098.82 |
At 100,000 payees a month, a very large platform:
| Plan | Usage charges | Plan fee | Subtotal | GST at 18% | Total for the month |
|---|---|---|---|---|---|
| Pay as you go | ₹4,00,000 | ₹0 | ₹4,00,000 | ₹72,000 | ₹4,72,000 |
| Growth | ₹4,00,000 | ₹999 | ₹4,00,999 | ₹72,179.82 | ₹4,73,178.82 |
| Scale | ₹4,00,000 | ₹4,999 | ₹4,04,999 | ₹72,899.82 | ₹4,77,898.82 |
Now suppose the 10,000 payees a month also include 3,000 PAN checks, perhaps for payee types where your policy asks for identity as well as an account. The standard calls change the plan comparison:
| Plan | Usage charges | Plan fee | Subtotal | GST at 18% | Total for the month |
|---|---|---|---|---|---|
| Pay as you go | ₹55,000 | ₹0 | ₹55,000 | ₹9,900 | ₹64,900 |
| Growth | ₹52,000 | ₹999 | ₹52,999 | ₹9,539.82 | ₹62,538.82 |
| Scale | ₹50,500 | ₹4,999 | ₹55,499 | ₹9,989.82 | ₹65,488.82 |
The pattern is clear. With bank checks alone, pay as you go wins at every volume. With a few thousand standard calls added, Growth becomes the cheapest in this model. The tables assume GST applies to the plan fee as well; check an invoice. Usage is recorded after a successful response, so calls that fail with an error are not charged, although valid: false is a successful, charged answer. Verifying the same account twice costs twice, so cache the result against a keyed hash for the period your policy allows. The spend at the largest volume is above the level at which StampMitra suggests an enterprise arrangement, which you can raise on the contact page. Weigh the figures against the cost of handling returned payouts and recovering misdirected money, using your own numbers; we do not quote an industry figure.
Rollout: sandbox, pilot, production
Sandbox. Build the gate, the review queue and the batch job on sandbox keys, where responses are sample data and the wallet is not debited. The sandbox responder has documented test values for the bank-account endpoint that return valid and invalid results, but confirm the current values in the dashboard before writing tests, since account-number formats in the live validator are nine to eighteen digits and you should check which sandbox values pass it. Any other input returns a stable but arbitrary outcome, so do not assert on it. Test every row of the decision table, the cooling-off rule, the duplicate policy, the batch restart and the 402, 429 and 502 paths.
Pilot. Request production access, which requires your organisation's KYC approval and the per-product application. Switch one payout type, such as seller payouts in one city, to the gate while the old process continues in parallel for a few weeks. Compare outcomes and returns.
Production. Roll out by payout type, strictest first. Alert on wallet balance well before it runs out, watch the metrics below, and keep the sandbox versus production keys guide for scopes and the IP allowlist.
Metrics worth watching
- Share of payees verified before the first payout, which should approach all.
- Review-band rate by payout type and the age of the oldest review item.
- Hold rate and the share of holds that were later released.
- Returned payouts per thousand, before and after the gate. This is the number that shows the gate working.
- Account changes per thousand payees, and the share held for cooling-off.
- Duplicate-account hits and their outcomes.
- Calls per payee. More than one per verified account points at retries or missing caching.
- Time from account entry to release.
Mistakes that weaken payout checks
- Verifying without a name. Without
namethere is no name match, which is the main value. - One threshold for all payout types. Tune per type.
- Blocking at entry rather than at payout. Gate the payout service.
- Skipping the account-change check. It is where fraud lives.
- Showing the name at the bank to payees. It leaks other people's information.
- Retrying
valid: false. Same answer, billed again. - Treating a timeout as a pass. Fail closed.
- Not caching results. Verify the same account once per period.
- Logging full account numbers. Mask them and keep them out of logs.
- Resending returned payouts without re-verification. It repeats the failure.
API reference at a glance
Bank Account
POST /v1/verify/bank-accountRequest parameters
| Field | Type | Description |
|---|---|---|
Authorizationrequired | header | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
accountNumberrequired | string | 9-18 digit numeric bank account number. |
ifscrequired | string | 11-character IFSC code, e.g. ICIC0001234. |
name | string | Beneficiary name to match. |
phone | string | Account holder's 10-digit Indian mobile number, when available; improves match confidence. |
POST /v1/verify/bank-account{
"referenceId": "SMV-20260927-3B71A0",
"valid": true,
"nameAtBank": "RAVI KUMAR",
"bankName": "ICICI Bank",
"utr": "017952100012345",
"city": "Mumbai",
"branch": "Andheri West",
"micr": "400229002",
"nameMatchScore": "100",
"nameMatchResult": "GOOD_MATCH",
"accountStatus": "ACCOUNT_IS_VALID",
"accountStatusCode": "1",
"ifscDetails": {
"bank": "ICICI Bank",
"ifsc": "ICIC0001234",
"micr": "400229002",
"address": "Andheri West, Mumbai",
"city": "Mumbai",
"state": "Maharashtra",
"branch": "Andheri West"
}
}POST /v1/verify/bank-accountBank Account: ₹4 per successful call, pay-as-you-go (lower on Growth and Scale).
PAN
POST /v1/verify/panRequest parameters
| Field | Type | Description |
|---|---|---|
Authorizationrequired | header | Bearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted. |
panrequired | string | PAN, format ABCDE1234F. |
name | string | Name to match against records (max 256 chars). |
POST /v1/verify/pan{
"referenceId": "SMV-20260927-8F42K7",
"pan": "ABCDE1234F",
"type": "Individual",
"valid": true,
"registeredName": "RAHUL KUMAR",
"fatherName": "SURESH KUMAR",
"panStatus": "VALID",
"panStatusCode": "E",
"panStatusDescription": "Existing and valid PAN",
"nameMatchResult": "MATCH",
"nameMatchScore": "100",
"aadhaarSeedingStatus": "y",
"aadhaarSeedingStatusDescription": "Aadhaar linked",
"lastUpdatedAt": "2023-04-01",
"message": "PAN is Valid"
}POST /v1/verify/panPAN: ₹5 per successful call, pay-as-you-go (lower on Growth and Scale).
Frequently asked questions
When should an account be verified in a payout flow?
Before the first payout to an account, whenever the payee changes account or IFSC, and when a payout to it comes back. A periodic re-check for high-value payees and a re-check after a long dormant period are sensible additions, depending on your risk policy.
Why send the payee's name with the account number?
The name is optional, but without it there is no name-match result, which is the most valuable part of the check for payouts. It tells you whether the account at the bank belongs to the person you intend to pay. Always send the payee's legal name.
What should happen when the name only partly matches?
Send the case to review with the name you supplied, the name at the bank and the score side by side, release on approval and record the reason. Common innocent causes are initials, name order, married names, trade names and joint accounts, so avoid rejecting on a middling score.
Is one name-match threshold enough for all payouts?
No. Salary, vendor, refund, claim, creator and loan payouts carry different risks and values, so tune a threshold and a review band per payout type, record the thresholds in force at the time of each payout and revisit them with real mismatch data.
How should account changes be handled?
Treat a change as a new first payout: verify the new account with the legal name, require a fresh login and a second factor where available, notify old and new contacts, start a cooling-off period before the first payout and keep the old account on record as inactive.
Does a plan upgrade make bank-account checks cheaper?
No. The bank-account rate is the same on every plan, so pay as you go is the cheapest for bank checks alone. Growth or Scale only pay off if you also run standard calls whose rates fall, or need higher limits and longer log retention.
How do I validate thousands of payees before a payout run?
Reject malformed rows locally, deduplicate by account and IFSC, run a small worker pool inside your rate limit, save each result keyed by payee and account so restarts skip finished work, stop on a 402 wallet error, and review the middling scores before releasing.
Should I retry a valid false result?
No. A valid false answer is a completed, billable call and would return again. Hold the payout, ask the payee to check the details or use another account, and retry only transport problems such as 429 and 502 with capped backoff.
What should be stored from a bank verification?
Store the referenceId, time, the validity flag, account status, score and result, your decision, rule version and reviewer. Keep account numbers encrypted and masked, use a keyed hash for duplicate detection and keep the name at the bank in the evidence store only.
Can the verification block fraud by itself?
No. It confirms what the source says about an account and a name. Combine it with cooling-off after changes, second approval above value limits, duplicate-account detection and your payment provider's own controls, and keep a human decision for anything that ends a payee's relationship.
Sources
- StampMitra bank-account verification reference, pricing page and sandbox documentation on developer.stampmitra.in (read 2026-10-29).
- IFSC structure (eleven characters, four-letter bank code, a zero in the fifth position, six-character branch code) is stated as general knowledge of the Indian Financial System Code format, not re-checked against an official source for this page in 2026; confirm before building strict rules on it.
- The Digital Personal Data Protection Act, 2023, India Code: https://www.indiacode.nic.in/handle/123456789/22037?view_type=browse (located 2026-10-16 in this site's KYC guide; confirm the current status of the rules against the official text).
- StampMitra Developer Data Retention and Deletion Schedule and Data Processing Addendum.