StampMitraDevelopers

Use cases

Bank Account Verification Before Payout: Controls and Cost

Verify a bank account before the first payout, whenever it changes and when a payout returns. Call the bank-account endpoint with the payee's legal name, read the validity flag, account status and name-match score, set thresholds per payout type, gate the payout service rather than the form, and cache results. The rate is flat on every plan.

By StampMitra Developer TeamLast updated: Read this in Hindi

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-account with accountNumber, ifsc, and ideally name, plus an optional phone. Read valid, accountStatus, nameAtBank, nameMatchScore and nameMatchResult, and keep the referenceId.
  • 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: false is 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:

JSON
{
  "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"
  }
}
FieldWhat it tells youHow to use it
referenceIdStampMitra's transaction id for this call, present on negative results tooStore it with the payee record; quote it to support
validWhether the verification succeeded for the accountfalse means do not pay this account; ask the payee for another
accountStatus and accountStatusCodeThe account state as returned by the sourceTreat only the value that means a valid account as a pass; send anything else to review, including values you have not seen before
nameAtBankThe holder name as the bank reports itShow to reviewers only; do not display it to the payee or the public
nameMatchScoreA number, as a string, for how the supplied name compares with nameAtBankConvert to a number and compare with your threshold
nameMatchResultA label for the comparison, such as the good-match value in the sampleUse it as a secondary signal; treat unknown labels as review
utrA reference for the verification transaction, where returnedStore with the evidence
bankName, branch, city, micrWhat the IFSC resolves toCompare the bank with the one the payee declared
ifscDetailsStructured branch detailsUseful 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 pointTriggerCheckDecision
1, first payoutA payee adds an account or a payout is first scheduledVerify account with legal nameRelease or hold
2, account changeA payee edits account or IFSCVerify new account; restart cooling-offRelease after cooling-off, or hold
3, dormant reactivationA payee returns after a long gapRe-verify the stored accountUpdate status
4, return handlingA payout bouncesRe-verify, ask the payee to confirmFix or replace the account
5, periodic refreshPolicy interval for high-value payeesRe-verifyUpdate 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

  1. 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".
  2. 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.
  3. 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.
  4. Call the endpoint. POST /v1/verify/bank-account with accountNumber, ifsc, name and optionally phone. Decision tree below.
  5. Interpret the response. valid: false: hold and ask for another account. valid: true with a strong score: mark verified. A middling score: review. A weak score: hold.
  6. 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.
  7. 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.
  8. 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.
  9. Record the evidence. referenceId, time, the key fields, your decision and rule version.
cURL
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.

JavaScript
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 typeTypical riskSuggested stance
Salary or wagesRepeated, moderate value, long relationshipStrict on first payout; allow review for initials and married names; re-verify on any change
Vendor or supplier paymentsLarge value, business names, trade namesCompare 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 refundsSmall to moderate, many payees, accounts entered onceSlightly looser threshold, with a review band; many refunds go to joint or family accounts
Insurance or claim settlementHigher value, fraud pressureStrict thresholds; second approver above a value limit; verify immediately before payment, not at claim intake
Creator or seller payoutsFrequent, variable, many new accountsModerate threshold, cooling-off after changes, duplicate-account detection
Loan disbursalHigh value, one-offStrict; 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.

Python
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 window

Account 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

OutcomeWhat the response showsPayout actionPayee message
Valid and strong name matchvalid: true, valid account status, high scoreMark verified; release after any cooling-off"Account confirmed."
Valid, partial name matchvalid: true, score in the middle bandReview with both names; release on approval"We are checking your account details."
Valid, weak name matchvalid: true, low scoreHold; 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 validvalid: false or an account status that is not the valid valueHold; do not retry; ask for another account"This account could not be verified. Please check the details or use another account."
Not found or malformedA 400 for a bad format, or a not-valid result for a well-formed numberFix the input once; otherwise hold"Please check the account number and IFSC."
Call failed429, 502 or timeoutKeep 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:

PlanCost 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:

PlanCost 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:

PlanUsage chargesPlan feeSubtotalGST 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:

PlanUsage chargesPlan feeSubtotalGST 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:

PlanUsage chargesPlan feeSubtotalGST 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:

PlanUsage chargesPlan feeSubtotalGST 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 name there 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

Bank Account: paramsPOST /v1/verify/bank-account

Request parameters

Request parameters
FieldTypeDescription
AuthorizationrequiredheaderBearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted.
accountNumberrequiredstring9-18 digit numeric bank account number.
ifscrequiredstring11-character IFSC code, e.g. ICIC0001234.
namestringBeneficiary name to match.
phonestringAccount holder's 10-digit Indian mobile number, when available; improves match confidence.
Bank Account: responsePOST /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"
  }
}
Bank Account: pricePOST /v1/verify/bank-account

Bank Account: ₹4 per successful call, pay-as-you-go (lower on Growth and Scale).

PAN

PAN: paramsPOST /v1/verify/pan

Request parameters

Request parameters
FieldTypeDescription
AuthorizationrequiredheaderBearer <api-key> (e.g. sk_test_... in sandbox, sk_live_... in production). The x-api-key header is also accepted.
panrequiredstringPAN, format ABCDE1234F.
namestringName to match against records (max 256 chars).
PAN: responsePOST /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"
}
PAN: pricePOST /v1/verify/pan

PAN: ₹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.