Skip to content
Last updated

IDR recipient verification

When you create an IDR 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 IDR recipients.

Supported recipient types

IDR supports one recipient type only:

Recipient typeAPI value Description
Indonesian LocalindonesianBank code + bank account number.

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.

Indonesian local

The following validations occur when the recipient type is indonesian:

FieldRulesError if invalid
Bank CodeMust be a valid bank code from the Wise bank list for Indonesia.NOT_VALID
Account Number7–18 digits only (bank-specific length requirements apply).NOT_VALID
NameAt least first name + last name (two words separated by a space). Max length validated.NOT_VALID

Sample field validation errors

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

Step 2: Verification

Verification checks name matching (type NAME_MATCHING) in a single call to the data provider. It only runs after all field validations pass.

How it works

  1. Wise calls the data provider API with the recipient's bank code and account number.
  2. Data provider first verifies the account exists.
    • If not, the outcome is blocking: either DOES_NOT_EXIST (account not found) or ACCOUNT_CLOSED (account has been closed). In both cases, recipient creation fails.
    • If the account exists, the data provider returns the registered name on the account.
  3. Wise compares the registered name with the name you provided using our name-matching algorithm.

The comparison produces one of two results:

ConfidenceWhat it meansOutcome Requires acceptance?
GREENNames matchSUCCESSNo. Proceed with transfer.
YELLOW/REDNames don't match (partial or complete mismatch)PARTIAL_FAILUREYes. Show result to user and call PATCH to accept.
Important!

Unlike some other currencies, IDR does not distinguish between partial and complete name mismatches at the API level. All non-matching results (whether a close match or a completely different name) produce PARTIAL_FAILURE. IDR does not have a non-blocking FAILURE outcome from name matching.

If the data provider returns an error or if the bank is not supported, the outcome is COULD_NOT_CHECK. 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)
Indonesian LocalaccountHolderName, details/bankCode, details/accountNumbername/fullName, details/bankCode, details/accountNumber

Verification blocking outcomes

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

Blocking outcome Error codeError pathWhen it happens
DOES_NOT_EXISTINVALID_ACCOUNT_NOT_EXISTdetails/accountNumberData provider says the account number does not exist.
ACCOUNT_CLOSEDINVALID_ACCOUNT_ACCOUNT_CLOSEDdetails/accountNumberData provider says the account has been closed.

Sample blocking errors

{
  "errors": [
    {
      "code": "INVALID_ACCOUNT_NOT_EXIST",
      "path": "details/accountNumber",
      "message": "The account does not exist."
    }
  ]
}

Possible outcomes for IDR

OutcomeBlocking?When it happens
SUCCESSNoName matches
PARTIAL_FAILURENoName doesn't match
COULD_NOT_CHECKNoBank is not supported by data provider verification
COULD_NOT_CHECKNoData provider API returned an error or timed out
(blocks creation)YesAccount not found at data provider
(blocks creation)YesAccount has been closed

What to do

Outcome Recipient created?What to do
SUCCESSYesProceed with the transfer. No additional action needed.
PARTIAL_FAILUREYesShow the verification result to the end user. The recommendedUpdates field contains the registered name from the bank. You can suggest the user update the name. If they accept, call PATCH /v1/accounts/{id}/confirmations (or V2 equivalent).
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": "indonesian",
  "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

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

In production, the resolvedName and providedName fields are null. Null fields may be omitted entirely from the actual API response. They are shown here as null for documentation completeness.

SUCCESS (name matched)

{
"id": 123456,
"type": "indonesian",
"accountHolderName": "Budi Santoso",
"details": {
 "bankCode": "bca",
 "accountNumber": "1234567890"
},
"confirmations": {
 "acceptedOutcomes": false,
 "acceptedAt": null,
 "quoteId": null,
 "outcomes": [
   {
     "type": "NAME_MATCHING",
     "outcome": "SUCCESS",
     "timestamp": "2026-03-08T10:30:00Z",
     "requiresCustomerAcceptance": false,
     "fieldsChecked": ["accountHolderName", "details/bankCode", "details/accountNumber"],
     "message": null,
     "resolvedName": null,
     "providedName": null,
     "recommendedUpdates": []
   }
 ]
}
}

PARTIAL_FAILURE (name doesn't match)

All name mismatches for IDR, whether a close match or a completely different name, produce PARTIAL_FAILURE. The recommendedUpdates field contains the registered name from BCA, so you can suggest the user update the name.

{
"id": 123456,
"type": "indonesian",
"accountHolderName": "Budi Santoso",
"details": {
 "bankCode": "bca",
 "accountNumber": "1234567890"
},
"confirmations": {
 "acceptedOutcomes": false,
 "acceptedAt": null,
 "quoteId": null,
 "outcomes": [
   {
     "type": "NAME_MATCHING",
     "outcome": "PARTIAL_FAILURE",
     "timestamp": "2026-03-08T10:30:00Z",
     "requiresCustomerAcceptance": true,
     "fieldsChecked": ["accountHolderName", "details/bankCode", "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": [
       {
         "path": "accountHolderName",
         "value": "Budi Santoso Wijaya"
       }
     ]
   }
 ]
}
}

COULD_NOT_CHECK (unsupported bank or service error)

Returned when an internal Wise error occurs.

{
  "id": 123456,
  "type": "indonesian",
  "accountHolderName": "Budi Santoso",
  "details": {
    "bankCode": "mandiri",
    "accountNumber": "1234567890"
  },
  "confirmations": {
    "acceptedOutcomes": false,
    "acceptedAt": null,
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "COULD_NOT_CHECK",
        "timestamp": "2026-03-08T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/bankCode", "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 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-08T10:35:00Z",
    "quoteId": null,
    "outcomes": [
      {
        "type": "NAME_MATCHING",
        "outcome": "PARTIAL_FAILURE",
        "timestamp": "2026-03-08T10:30:00Z",
        "requiresCustomerAcceptance": true,
        "fieldsChecked": ["accountHolderName", "details/bankCode", "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": [
          {
            "path": "accountHolderName",
            "value": "Budi Santoso Wijaya"
          }
        ]
      }
    ]
  }
}

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 at data provider.

IDR verification behavior in the sandbox depends on the data provider API availability. If unavailable, verification will return ``COULD_NOT_CHECK`.

Test scenarioExpected outcome
Valid account, matching nameSUCCESS
Valid account, different name (partial or complete mismatch)PARTIAL_FAILURE
Non-existent account numberBlocking error: INVALID_ACCOUNT_NOT_EXIST
Closed accountBlocking error: INVALID_ACCOUNT_ACCOUNT_CLOSED
Bank not supported by data provider verificationCOULD_NOT_CHECK (NOT_SUPPORTED_BANK)
Data provider API error/timeoutCOULD_NOT_CHECK (REMOTE_SERVER_ERROR)
Invalid account number formatBlocking field error: NOT_VALID on details/accountNumber
Single-word name (for example, "Budi")Blocking field error: NOT_VALID on name/fullName
Important!

All name mismatches for IDR produce PARTIAL_FAILURE. There is no separate FAILURE outcome for name mismatches.

The only FAILURE-mapped outcomes (DOES_NOT_EXIST, ACCOUNT_CLOSED) are blocking and result in errors, rather than non-blocking confirmation outcomes.