Skip to main content

Send payments to customers

To create a fiat payout for local payment rails, you must have the following:

  • Recipient's account number.
  • Recipient's bank account details:
    • For GBP payments: SORT
    • For EUR payments: IBAN
    • For USD payments: ABA routing number

If invalid bank details are provided, such as an incorrect bank code or account number, the payout request will be rejected with an error message returned.

To create a fiat payout for international payments via SWIFT, you must first acquire the following information:

  • Payee's full name or company name and address.
  • Bank Account Number (IBAN or other, depending on the currency)
  • Name and address of the payee's bank
  • Payee's SWIFT or Bank identifier Code (BIC) bank code.

Create payout

To create a payout, send the POST /payment/v2/payouts request with the payload:

{
"walletId": "a:24092324785677:o6rhCEZ:1",
"amount": 1000.5,
"currency": "EUR",
"method": "SEPA_CT",
"reference": "PAYOUT-2025-001",
"beneficiary": {
"remittanceInformation": "Payment for services",
"entity": {
"type": "INDIVIDUAL",
"firstName": "John",
"lastName": "Dove",
"dateOfBirth": "15-01-1990",
"relationshipType": "SELF_OWNED",
"address": {
"addressLine1": "123 Main St",
"city": "New York",
"region": "NY",
"postCode": "10001",
"country": "US"
}
},
"bankAccount": {
"accountNumber": "000123456789",
"accountType": "CHECKING",
"bank": {
"identificationCode": "CHASUS33",
"nid": "021000021",
"address": {
"addressLine1": "383 MADISON AVENUE",
"city": "New York",
"region": "NY",
"postCode": "10001",
"country": "US"
}
}
}
},
"fees": {
"customerFee": {
"amount": 5,
"currency": "USD"
}
},
"metadata": {
"source": "api",
"merchantId": "merchantOne"
},
"requestDetails": {
"originator": {
"ipAddress": "10.0.0.2"
}
}
}

Note the following fields:

ParameterRequiredDescription
referenceOptional. The internal reference is shown in the CSV reports for custom use cases. Can be a UUID or any string to identify the payment.

The field is for information purposes only. It will be fully supported in future releases.
methodPayment method. Mandatory for payouts in USD and optional for other currencies.

We recommend leaving it blank, so that the fastest method is selected automatically.

Depending on the specific wallet and currency, not all methods can be available for the transaction. Available options:

* SEPA_INST (EUR)
* SEPA_CT (EUR)
* ACH (USD)
* ACH_SAME_DAY (USD)
* FASTER_PAYMENT (GBP)
* SWIFT (USD, EUR, GBP)
* FEDWIRE (USD)
* BOOK (USD)
* RTP (USD)
* FEDNOW (USD)
beneficiary.remittanceInformationPayment reference that beneficiaries see in their bank statements when receiving the payment.

Can contain only alphanumeric characters (a-z, A-Z, 0-9), whitespaces, or the .,- symbols.

Other allowed characters vary depending on the used payment method or currency.
beneficiary.address.codeCountry code of the beneficiary's address. The beneficiary address must include at least this field.
bankAccount.accountTypeType of the account. Optional. Only for US banks.
bankAccount.bank.identificationCodeBank's identification number, for example, BIC for UK banks, SORT code, ABA routing number, and so on.

Optional for local payouts in EUR.
bankAccount.bank.nidNational bank identification code: country-specific code assigned to a financial institution by its central bank or banking authority. In most cases, used for SWIFT payments to US accounts.
requestDetails.originator.ipAddressIP address of the customer initiating the payout. Required when you make a payment via a customer's wallet.

While EUR local transfers have fewer requirements, for USD payments and SWIFT transactions, it's advisable to provide comprehensive details to prevent potential rejection by the banking partner.

For the detailed description of all fields, see the POST /payment/v2/payouts API reference.

In the successful response, you receive the standard payment details.

{
"id": "550e8400-e29b-41d4-a716-446655440000",
"method": "SEPA_CT",
"reference": "PAYOUT-2025-001",
"status": "PROCESSING",
"type": "payment:payout:fiat",
"direction": "OUT",
"fees": {
"customerFee": {
"amount": 5,
"currency": "EUR"
},
"processingFee": {
"amount": 1,
"currency": "EUR"
}
},
"originator": {
"amount": 1000.5,
"currency": "EUR",
"walletId": "a:24092324785677:o6rhCEZ:1"
},
"beneficiary": {
"remittanceInformation": "Payment for services",
"amount": 1000.5,
"currency": "EUR",
"entity": {
"type": "INDIVIDUAL",
"firstName": "John",
"lastName": "Dove",
"relationshipType": "BENEFICIARY"
},
"bankAccount": {
"accountNumber": "000123456789",
"bank": {
"identificationCode": "CHASUS33"
}
}
},
"createdAt": "2024-01-15T10:30:00Z",
"updatedAt": "2024-01-15T10:35:00Z",
"metadata": {
"source": "api",
"merchantId": "merchantOne"
}
}
ParameterDescription
typeType of the response.
originator.amountAmount of funds sent to the beneficiary. For fiat transactions, it will always be the same as beneficiary.amount.

In case of payment in Euro, the transaction is subject to Verification of Payee (VoP).

Request VoP

VoP is a SEPA (Single Euro Payments Area) service that verifies a beneficiary's name against their IBAN to prevent fraud and errors. Before a SEPA Credit Transfer (SCT) or SEPA Instant Transfer (SCT inst) is authorized, the originator's bank will check the provided name and IBAN with the beneficiary's bank and report the result (Match, Close match, or No match) back to the originator. This is a regulatory requirement under the Instant Payments Regulation to enhance security for euro transfers within the SEPA zone.

VoP flow

When performing VoP, the system may return one of the following results:

  • Successful verification: The beneficiary's name matches. The payment proceeds automatically.
  • Partial match: The provided name is similar to the one associated with the IBAN, but not an exact match. You may still send the payment at your own risk, but there is a chance it may not be processed successfully.
  • No match: The beneficiary's name does not match at all. You may still attempt to send the payment, but the likelihood of rejection increases.
  • Failed verification due to other reasons:
    • For instance, technical issues may arise if the verification service is unavailable.
    • Others, for example, if a beneficiary's bank decides not to conduct verification.

All results, except for the successful verification, indicate that if the beneficiary's name in the request doesn't match the name in the beneficiary's bank account, the bank will issue a warning about the inconsistency. In this case, the status 202 is returned.

{
"id": "UUID",
"requiredAction": "CONFIRM_BENEFICIARY",
"status": "PAYEE_VERIFICATION_REQUIRED",
"verificationResult": {
"matchStatus": "PARTIAL_MATCH",
"actualName": "George D Collins", // Only present if status is Partial Match
"providedName": "George Colline"
}
}
🚧 Your transaction is not created yet.

Status 202 means that you must send another request to confirm the operation. See Send confirmation below.

You can also test how verification works in the sandbox. For that, use the following test names and IBANs, when sending the payment request:

  • First Name: John Smith
  • Last Name: Doe
  • IBAN: MT45SYPL39480744067217548372015
  • BIC: SYPLMTM2XXX

There are two ways of verifying the beneficiary's name:

  • As part of the Payout process: by calling another endpoint to confirm the payout operation. See Confirm payout.
  • As a separate two-step process, where you verify a beneficiary via a separate endpoint and then make the payout using the received verificationId. See Integrate two-step verification.

Confirm payout

You can use this method after making a payout in euros described earlier and receive a response with any of the following status values :

  • PARTIAL_MATCH
  • NO_MATCH
  • NOT_POSSIBLE
  • TECHNICAL_ERROR

The statuses indicate that the beneficiary's name doesn't match the one associated with the beneficiary's bank account or cannot be verified.

If you are aware of this inconsistency and would like to proceed with the payment anyway, send a POST /payment/v2/payouts/{id}/actions request with id of the transaction received in the 202 response and the following body.

{
"type": "CONFIRM_BENEFICIARY"
}

In the successful response, you receive the standard payout details, as shown earlier.

If the operation is not confirmed within five minutes, it expires.

If you provide the wrong transaction ID or send the confirmation request after its expiration, an error is returned. In this case, you will have to create a new payout.

Integrate two-step verification

Alternatively, you can verify the beneficiary's name using the verification endpoint. Note that in case you follow this approach, step 1 of the following procedure must be completed before creating the payout.

To verify the beneficiary's name, do the following:

  1. Send the POST /platform/v1/beneficiaries/verification request.

    {
    "accountNumber": "GB29NWBK60161331926819",
    "bankCode": "NWBKGB2L",
    "firstName": "John",
    "lastName": "Smith",
    "businessName": "Acme Corporation Ltd",
    "currency": "GBP"
    }

    In the request body, provide the following fields:

    FieldDescription
    accountNumberThe beneficiary's bank account number.
    bankCodeThe beneficiary's bank code.
    firstNameThe beneficiary's first name. Only for "type": "INDIVIDUAL".
    lastNameThe beneficiary's last name. Only for "type": "INDIVIDUAL".
    businessNameThe beneficiary's business name. Only for "type": "COMPANY".
    currencyThe currency of the beneficiary's bank account.

    In the successful response, you receive the name match status and validation period:

    {
    "id" : "550e8400-e29b-41d4-a716-446655440000",
    "matchStatus" : "MATCH",
    "providedName" : "John Smith",
    "actualName": "J. Smith", // only present for partial match
    "validUntil" : "2025-01-15T14:30:00Z" // when the verification will expire
    }

    Note the following fields:

    FieldDescription
    matchStatusStatus of the name verification. The following name statuses are available:

    * MATCH
    * PARTIAL_MATCH
    * NO_MATCH
    * NOT_REQUIRED
    * NOT_POSSIBLE
    * TECHNICAL_ERROR
    validUntilTime period during which the verification request is valid. By default, five minutes.
  2. Send the POST /payment/v2/payouts request as described earlier. Remember to include the verification Id, acquired on step 1 in the response, as the X-Verification-Id header.

    If you provide a valid verificationId regardless of status, BVNK verifies that it exists in the records and is not expired, then executes the payment regardless of the matchStatus value.

    The following outcomes are possible:

    • If the verification session is still valid, the payout will be created, and there will be no need to verify the beneficiary.
    • If the verification session is expired or verificationId is not found within BVNK records, the payout will not be created, and you will receive a 400 error.

Check payout status

To check the status of a payout, send the GET /payment/v2/payouts/{transactionReference} request.

In the successful response, you receive the details on the transaction and its status.

{
"transactionReference": "123e4567-e89b-12d3-a456-426614174000",
"paymentReference": "Payment for invoice #12345",
"amount": {
"value": 1000,
"currency": "GBP"
},
"fee": {
"value": 0.00,
"currency": "GBP"
},
"walletId": "a:24071743003474:xE95Oq7:1",
"status": "PROCESSING",
"createdAt": "2024-09-26T14:30:00Z",
"details": {
"type": "FIAT",
"beneficiary": {
"entityType": "COMPANY",
"businessDetails": {
"businessName": "Doe Corp"
},
"address": {
"addressLine1": "123 Main St",
"addressLine2": "Apt 4B",
"region": "London",
"city": "London",
"country": "GB",
"postCode": "EC2R 8AH",
"fullAddress": "123 Main St Suite 500"
},
"bankAccount": {
"format": "IBAN",
"bankName": "NatWest Bank",
"accountNumber": "GB29NWBK60161331926819",
"bankCode": "NWBKGB2L",
"bankAddress": {
"addressLine1": "123 Main St",
"addressLine2": "Suite 500",
"region": "London",
"city": "London",
"country": "GB",
"postCode": "12345",
"fullAddress": "123 Main St Suite 500"
}
},
"correspondentBic": "ABCDEF12"
}
},
"metadata": {
"field1": "field1 value",
"field2": "field2 value"
}
}

Also, you can listen to the following webhooks to get notified when the status of the payment changes: