Skip to content
Last updated

INR recipient verification

When you create an INR recipient via the Wise API, we automatically run a series of validations (format checks) and verifications (Confirmation of Payee, or CoP) before returning the response.

This guide provides details specific to the verification that occurs when creating INR recipients.

Supported recipient types

INR supports two recipient types:

Recipient typesAPI value Description
Bank accountindianIFSC code + bank account number.
UPIindian_upiUPI Virtual Payment Address (VPA). A unique ID (for example, name@bankprovider) that maps to a bank account and lets recipients receive payments instantly via India's Unified Payments Interface.

Step 1: Field-level validation

Field-level validation checks the format and correctness of input fields. If any fail, the recipient is not created and the API returns a validation error.

Bank account

The following validations occur when the recipient type is indian:

FieldRulesError if invalid
Account number5–20 alphanumeric charactersACCOUNT_NUMBER_NOT_VALID
IFSC Code11 characters, format XXXX0XXXXXX (4 letters, 0, 6 alphanumeric)NOT_VALID
IFSC Bank CodeFirst 4 characters must map to a known bankINDIA_LOCAL_IFSC_UNKNOWN_BANK_DISALLOWED
NameAt least first name + last name (two words separated by a space); max 140 charactersNOT_VALID

UPI

The following validations occur when the recipient type is indian_upi:

FieldRulesError if invalid
VPA (accountNumber)5–255 characters, format username@providerNOT_VALID
NameAt least first name + last name (two words separated by a space); max 140 charactersNOT_VALID

Sample field validation errors

If you provide a single-word name like "Rajesh" instead of "Rajesh Kumar":

{
 "errors": [
   {
     "code": "NOT_VALID",
     "path": "name/fullName",
     "message": "The name provided is not valid."
   }
 ]
}

Step 2: Verification

Verification runs only after all field validations pass. The result is reported in the confirmations object of the response.

How it works

For INR, verification confirms both account existence (type ACCOUNT_EXISTENCE) and name matching (type NAME_MATCHING) in a single call. These happen sequentially — account existence is verified first, and if the account exists, then name matching runs.

  1. Wise calls the external verification provider with the recipient's account details.
  2. The provider first verifies the account exists.
  • If not, the outcome is FAILURE (account doesn't exist) and name matching is skipped.
  • If the account exists, the provider returns the registered name on the account.
  1. Wise compares the registered name with the name you provided using our name-matching algorithm.

The comparison produces one of three confidence levels:

ConfidenceWhat it meansOutcomeRequires acceptance?
GREENNames matchSUCCESSNo. Proceed to transfer.
YELLOWClose match (partial name overlap)PARTIAL_FAILUREYes. Show result to user, make PATCH request to accept.
REDNames don't matchFAILUREYes. Show result to user, make PATCH request to accept.

If the verification provider returns an error or times out, the outcome is COULD_NOT_CHECK. In this case, the recipient is still created, but you should inform the user that verification wasn't possible.

Fields checked by recipient type

Recipient typeFields checked (V1)Fields checked (V2)
Bank account
  • accountHolderName
  • details/accountNumber
  • details/ifscCode
  • name.fullName
  • details/accountNumber
  • details/ifscCode
UPI
  • accountHolderName
  • details/accountNumber
  • name/fullName
  • details/accountNumber

Verification blocking outcomes

In some cases, verification discovers the account details are invalid at the provider level. These are blocking outcomes, meaning they cause recipient creation to fail, even though field-level validation passed.

Blocking outcome Account typeWhen it happens
INVALID_ACCOUNT_NUMBERBank accountBank says the account number is invalid.
INVALID_ACCOUNT_DETAILSBank accountBank says the account number or IFSC is invalid
INVALID_IFSC_CODEBank accountBank says the IFSC is invalid or disallowed
INVALID_UPI_IDUPIUPI provider says the VPA is invalid

Possible outcomes for INR

Bank account recipient type

OutcomeBlocking?When it happens
SUCCESSNoName matches
PARTIAL_FAILURENoName partially matches
FAILURENoName doesn't match
FAILURENoAccount not found at the bank
COULD_NOT_CHECKNoError during name comparison
COULD_NOT_CHECKNoInternal service error
COULD_NOT_CHECKNoInternal timeout
COULD_NOT_CHECKNoBank provider returned an error
COULD_NOT_CHECKNoBank provider timed out
(blocks creation)YesBank says account number is invalid
(blocks creation)YesBank says account number or IFSC is invalid
(blocks creation)YesBank says IFSC is invalid

UPI recipient type

OutcomeBlocking?When it happens
SUCCESSNoName matches
PARTIAL_FAILURENoName partially matches
FAILURENoName doesn't match
FAILURENoVPA not found
COULD_NOT_CHECKNoError during name comparison
COULD_NOT_CHECKNoInternal service error
COULD_NOT_CHECKNoInternal timeout
COULD_NOT_CHECKNoUPI provider returned an error
COULD_NOT_CHECKNoUPI provider timed out
(blocks creation)YesUPI says VPA is invalid

What to do

Outcome Recipient created?What to do
SUCCESSYesProceed with the transfer. No additional action needed.
PARTIAL_FAILUREYesShow the verification result to the user. If they accept, call PATCH /v1/accounts/{id}/confirmations (or V2 equivalent).
FAILUREYesShow warning to the end user. If they choose to proceed anyway, make PATCH request to accept the risk.
COULD_NOT_CHECKYesInform the user that verification wasn't possible. If they accept, make PATCH request to proceed.
(blocking error)NoFix the invalid input and retry recipient creation

V1 vs V2 endpoints

Both V1 and V2 endpoints run the same validations and verifications. The difference is the field naming and how the confirmation result is returned.

Aspect/v1/accounts//v2/accounts/
Confirmations in responseAlways included in the recipient response (if available)Only included if you request them via responseConfiguration.additionalInformation
Name field path in confirmationsaccountHolderNamename/fullName
Recommended update pathaccountHolderNamename/fullName
Accept confirmationPATCH /v1/accounts/{id}/confirmationsPATCH /v2/accounts/{id}/confirmations

V2 request confirmations

When creating a recipient with V2, include the following in your request to receive the confirmations field:

{
  "type": "indian",
  "details": { ... },
  "responseConfiguration": {
    "additionalInformation": ["CONFIRMATION_RESULT"]
  }
}

Without this, V2 will create the recipient and run all checks, but will not include the confirmations field in the response. You would then need to fetch it separately via GET /v2/accounts/{id}.

Sample payloads: Bank account

All payloads below show the confirmations field as it appears in the response after creating a recipient.

The resolvedName and providedName fields are null in production responses.

SUCCESS

{
 "id": 123456,
 "type": "indian",
 "accountHolderName": "Rajesh Kumar",
 "details": {
     "accountNumber": "1234567890",
     "ifscCode": "SBIN0001234"
      },
 "confirmations": {
 "acceptedOutcomes": false,
 "acceptedAt": null,
 "quoteId": null,
 "outcomes": [
     {
     "type": "NAME_MATCHING",
     "outcome": "SUCCESS",
     "timestamp": "2026-03-07T10:30:00Z",
     "requiresCustomerAcceptance": false,
     "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
     "message": null,
     "resolvedName": null,
     "providedName": null,
     "recommendedUpdates": []
     }
   ]
 }
}

PARTIAL_FAILURE

{
  "id": 123456,
  "type": "indian",
  "accountHolderName": "Rajesh Kumar",
  "details": {
      "accountNumber": "1234567890",
      "ifscCode": "SBIN0001234"
  },
  "confirmations": {
      "acceptedOutcomes": false,
      "acceptedAt": null,
      "quoteId": null,
      "outcomes": [
          {
          "type": "NAME_MATCHING",
          "outcome": "PARTIAL_FAILURE",
          "timestamp": "2026-03-07T10:30:00Z",
          "requiresCustomerAcceptance": true,
          "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
          "message": "The name you entered doesn't match the account holder's name. Please check and try again.",
          "resolvedName": null,
          "providedName": null,
          "recommendedUpdates": []
      }
      ]
  } 
}

FAILURE NO_MATCH_NAME

{
  "id": 123456,
  "type": "indian",
  "accountHolderName": "Rajesh Kumar",
  "details": {
    "accountNumber": "1234567890",
    "ifscCode": "SBIN0001234"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
        "message": "The name you entered doesn't match the account holder's name. Please check and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

FAILURE DOES_NOT_EXIST

V1 response (V2 uses name/fullName instead of accountHolderName in fieldsChecked):

{
  "id": 123456,
  "type": "indian",
  "accountHolderName": "Rajesh Kumar",
  "details": {
    "accountNumber": "1234567890",
    "ifscCode": "SBIN0001234"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
        "message": "We couldn't verify this account. Please check the details and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

COULD_NOT_CHECK

For a service error or timeout.

V1 response (V2 uses name/fullName instead of accountHolderName in fieldsChecked):

{
  "id": 123456,
  "type": "indian",
  "accountHolderName": "Rajesh Kumar",
  "details": {
    "accountNumber": "1234567890",
    "ifscCode": "SBIN0001234"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "COULD_NOT_CHECK",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
        "message": "We couldn't verify the account holder's name right now. You can still proceed.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

Sample payloads: UPI

UPI payloads have the same structure as Bank Account, but fieldsChecked contains only 2 fields (no IFSC):

  • V1: ["accountHolderName", "details/accountNumber"]
  • V2: ["name/fullName", "details/accountNumber"]

SUCCESS

{
  "id": 789012,
  "type": "indian_upi",
  "accountHolderName": "Priya Sharma",
  "details": {
    "accountNumber": "priya.sharma@okicici"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "SUCCESS",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": false,
        "fieldsChecked": ["accountHolderName", "details/accountNumber"],
        "message": null,
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

PARTIAL_FAILURE

{
  "id": 789012,
  "type": "indian_upi",
  "accountHolderName": "Priya Sharma",
  "details": {
    "accountNumber": "priya.sharma@okicici"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "PARTIAL_FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber"],
        "message": "The name you entered doesn't match the account holder's name. Please check and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

FAILURE NO_MATCH_NAME

V1 response (V2 uses name/fullName in fieldsChecked):

{
  "id": 789012,
  "type": "indian_upi",
  "accountHolderName": "Priya Sharma",
  "details": {
    "accountNumber": "priya.sharma@okicici"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber"],
        "message": "The name you entered doesn't match the account holder's name. Please check and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

FAILURE DOES_NOT_EXIST

V1 response (V2 uses name/fullName in fieldsChecked):

{
  "id": 789012,
  "type": "indian_upi",
  "accountHolderName": "Priya Sharma",
  "details": {
    "accountNumber": "invalid.vpa@okicici"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber"],
        "message": "We couldn't verify this account. Please check the details and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

COULD_NOT_CHECK

V1 response (V2 uses name/fullName instead of accountHolderName in fieldsChecked):

{
  "id": 789012,
  "type": "indian_upi",
  "accountHolderName": "Priya Sharma",
  "details": {
    "accountNumber": "priya.sharma@okicici"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "COULD_NOT_CHECK",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber"],
        "message": "We couldn't verify the account holder's name right now. You can still proceed.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

Accept confirmation outcomes

The requiresCustomerAcceptance field is true when the outcome value is PARTIAL_FAILURE, FAILURE, or COULD_NOT_CHECK.

Before you can use the recipient for a transfer, you must make a PATCH request to confirm the user has acknowledged the result.

Request

Endpoint: PATCH /v1/accounts/{accountId}/confirmations or PATCH /v2/accounts/{accountId}/confirmations

Body:

{
  "acceptedOutcomes": true
}

Response after acceptance

The response mirrors the original confirmations object, but now acceptedOutcomes is true and acceptedAt contains a timestamp:

{
  "confirmations": {
    "acceptedOutcomes": true,
    "acceptedAt": "2026-03-07T10:35:00Z",
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "FAILURE",
        "timestamp": "2026-03-07T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/accountNumber", "details/ifscCode"],
        "message": "The name you entered doesn't match the account holder's name. Please check and try again.",
        "resolvedName": null,
        "providedName": null,
        "recommendedUpdates": []
      }
    ]
  }
}

Test in the sandbox

  1. Create a recipient via POST /v1/accounts/ (or V2) with valid details.
  2. Inspect the response. Check the confirmations.outcomes.outcome field.
  3. If outcome requires acceptance (requiresCustomerAcceptance: true), call PATCH /v1/accounts/{id}/confirmations with {"acceptedOutcomes": true}.
  4. Create a transfer using the accepted recipient.

How to trigger each verification outcome

The verification result depends on the relationship between the name you provide when creating the recipient and the registered name on the actual bank account or UPI.

PRIVATE entity type

Registered name at bankName you provideExpected outcome
Rajesh Kumar SinghRajesh Kumar SinghSUCCESS — exact match
Rajesh Kumar SinghRajesh KumarPARTIAL_FAILURE — partial overlap
Rajesh Kumar SinghRajesh SinghPARTIAL_FAILURE — partial overlap
Rajesh Kumar SinghJohn DoeFAILURE — no match

BUSINESS entity type

Registered name at bankName you provideExpected outcome
ACME Technologies Private LimitedACME Technologies Private LimitedSUCCESS
ACME Technologies Private LimitedAcme Technologies Pvt LtdSUCCESS — abbreviation understood
ACME Technologies Private LimitedAcme Pvt LtdPARTIAL_FAILURE — missing key words
ACME Technologies Private LimitedTotally Different Company LtdFAILURE
Important!

You don't control the registered name. It comes from the bank/UPI provider. To trigger PARTIAL_FAILURE, you need to know the actual registered name and provide a partial match. An exact match gives SUCCESS. A completely different name gives FAILURE.

Other scenarios

Test scenarioExpected outcome
Valid account, matching nameSUCCESS
Valid account, close namePARTIAL_FAILURE
Valid account, completely wrong nameFAILURE (NO_MATCH_NAME)
Non-existent account number / VPAFAILURE (DOES_NOT_EXIST)
Invalid account number + IFSC combination (bank)Blocking error: ACCOUNT_NUMBER_NOT_VALID on details/accountNumber
Invalid VPA format (UPI)Blocking error: INDIAN_UPI_NOT_VALID
Invalid account number format (bank)Blocking error: ACCOUNT_NUMBER_NOT_VALID
Invalid or disallowed IFSC (bank)Blocking error: INDIA_LOCAL_IFSC_UNKNOWN_BANK_DISALLOWED
Single-word name (for example, "Rajesh")Blocking error: NOT_VALID on name/fullName
Provider timeout/errorCOULD_NOT_CHECK