Create a Beneficiary

Create a beneficiary, then attach a payout account you can reuse in future transaction flows.

Create a beneficiary and attach a payout account so you can reuse the destination in future transactions.

When to use this page

Use this page when you need to register a reusable payout destination before you generate a quote or execute a transaction.

Prerequisites

  1. Set your NadaPay API base URL in $baseUrl.
  2. Export your NadaPay API key as YOUR_API_KEY.
  3. Generate a unique idempotency key for each create request.

Before you continue

  • decide the payout rail you want to use
  • resolve the destination bank account first if the rail is bank-based
  • confirm the organization is ready to move beyond onboarding for the intended mode

Step 1 — Create the beneficiary

curl --request POST \
  --url $baseUrl/beneficiaries \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'x-idempotency-key: YOUR_UNIQUE_UUID' \
  --data '{
    "name": "string",
    "email": "string",
    "phone": "string",
    "currency": "USD",
    "type": "INTERNAL",
    "details": {
      "nadapayCode": "string",
      "accountNumber": "string",
      "accountName": "string",
      "networkId": "string",
      "rail": "ACH",
      "bankCode": "string",
      "country": "NG",
      "iban": "string",
      "swiftCode": "string",
      "sortCode": "string",
      "routingNumber": "string",
      "clabe": "string",
      "pixKey": "string",
      "cpf": "string",
      "chain": "ETHEREUM",
      "address": "string",
      "legalName": "string",
      "accountType": "personal",
      "phoneNumber": "string",
      "provider": "string",
      "streetLine1": "string",
      "city": "string",
      "state": "string",
      "postalCode": "string"
    }
  }'

Use the fields inside details that apply to the rail you are registering.

Start with these values for the recommended bank-transfer flow

For the fastest first integration, set these values in the example below before you customize anything else:

  • name
  • currency
  • type
  • details.rail
  • details.accountNumber
  • details.accountName
  • details.networkId
  • details.country

details by rail

ACH

FieldRequiredNotes
accountNumberYesRecipient bank account number
accountNameYesRecipient account name
routingNumberYesACH routing number
countryYesCountry for the destination bank account

Bank Transfer

FieldRequiredNotes
accountNumberYesRecipient bank account number
accountNameYesRecipient account name
networkIdYesProvider or banking network identifier
countryYesDestination country
bankCodeConditionalUse when required for the destination banking scheme
ibanConditionalUse for IBAN-based corridors
swiftCodeConditionalUse for international wire routing
sortCodeConditionalUse for UK bank routing
routingNumberConditionalUse for US bank routing when applicable
clabeConditionalUse for Mexico corridors
pixKeyConditionalUse for Brazil PIX flows
cpfConditionalUse when the corridor requires recipient CPF

Mobile Money

FieldRequiredNotes
phoneNumberYesRecipient mobile money number
providerYesMobile money provider
countryYesDestination country
networkIdConditionalUse when provider routing depends on a network identifier

Crypto

FieldRequiredNotes
chainYesBlockchain network
addressYesRecipient wallet address

For crypto rails, do not send accountName, provider, or country.

Response:

{
  "data": {
    "id": "ben_01HXXXXXXXXXXXXXXXXXX",
    "name": "John Doe",
    "type": "individual",
    "status": "active",
    "created_at": "2025-01-01T00:00:00Z"
  }
}

Save the id — you will use it to attach a payout account in the next step.

Response — error:

{
  "statusCode": 500,
  "message": "Internal server error"
}

What success looks like

  • the beneficiary is created successfully
  • you save the returned beneficiary ID
  • the beneficiary account is attached successfully when you complete Step 2

Do not continue if

  • beneficiary creation returns an error
  • the selected rail does not match the details fields you sent
  • a bank-based rail has not been resolved and confirmed first

Step 2 — Add a beneficiary account

If you are adding a bank account, resolve it first with Resolve a Bank Account.

curl --request POST \
  --url $baseUrl/beneficiaries/ben_01HXXXXXXXXXXXXXXXXXX/accounts \
  --header 'x-api-key: YOUR_API_KEY' \
  --header 'Content-Type: application/json' \
  --header 'x-idempotency-key: YOUR_UNIQUE_UUID' \
  --data '{
    "currency": "USD",
    "type": "INTERNAL",
    "details": {
      "nadapayCode": "string",
      "accountNumber": "string",
      "accountName": "string",
      "networkId": "string",
      "rail": "ACH",
      "bankCode": "string",
      "country": "NG",
      "iban": "string",
      "swiftCode": "string",
      "sortCode": "string",
      "routingNumber": "string",
      "clabe": "string",
      "pixKey": "string",
      "cpf": "string",
      "chain": "ETHEREUM",
      "address": "string",
      "legalName": "string",
      "accountType": "personal",
      "phoneNumber": "string",
      "provider": "string",
      "streetLine1": "string",
      "city": "string",
      "state": "string",
      "postalCode": "string"
    }
  }'

Use the same rail-based details rules above when you add the beneficiary account.

Response — error:

{
  "statusCode": 500,
  "message": "Internal server error"
}

What this step returns

  • beneficiary ID from Step 1
  • beneficiary account details from Step 2

Save the beneficiary ID after creation and the beneficiary account details after the account is attached.

Common reasons this step fails

  • the selected rail does not match the details fields you sent
  • required fields for the rail are missing
  • the destination configuration is invalid for the selected rail

Call this next