Last updated

Beneficiaries

The people and businesses you pay, with their attached payment methods.

A payment needs two IDs from this endpoint: beneficiaryId (who) and beneficiaryPaymentMethodId (how — which of their attached payment methods receives the funds).

Listing beneficiaries

GET /v1/beneficiaries — scope beneficiaries:read.

curl 'https://public-sandbox.tryjeeves.com/v1/beneficiaries?page=1&limit=50' \
  -H "Authorization: Bearer $JEEVES_ACCESS_TOKEN"
{
  "data": [
    {
      "beneficiaryId": "3f1c9a52-6b7e-4d80-9a13-5c2e8f0b4d76",
      "entityType": "individual",
      "firstName": "Ana",
      "lastName": "Gómez",
      "name": null,
      "bankCountry": "MX",
      "bankCurrency": "MXN",
      "createdAt": "2026-09-10T14:02:11Z",
      "paymentMethods": [
        {
          "paymentMethodId": "b7d2e4a1-8c05-49f3-a6b2-1e7d9c3f5024",
          "paymentMethod": "spei",
          "accountNumber": "••••0001"
        }
      ]
    },
    {
      "beneficiaryId": "8a4e7c13-2d95-4f6b-8e01-7b3a5d9c2f48",
      "entityType": "business",
      "firstName": null,
      "lastName": null,
      "name": "Tortillería del Norte S.A. de C.V.",
      "bankCountry": "MX",
      "bankCurrency": "MXN",
      "createdAt": "2026-09-11T09:41:55Z",
      "paymentMethods": [
        { "paymentMethodId": "c91a06b4-7f38-4e52-b8d7-0a5c4e1f9362", "paymentMethod": "spei", "accountNumber": "••••4417" },
        { "paymentMethodId": "d04b18e7-5a29-4c63-9f81-2d6e7b0a4c15", "paymentMethod": "wire", "accountNumber": "••••1897" }
      ]
    }
  ],
  "count": 42
}

Reading the shape

FieldNotes
entityTypeindividual populates firstName/lastName; business populates name.
bankCountry / bankCurrencyWhere and in what currency this beneficiary is paid — this is the destination side of your corridor.
paymentMethods[]Every live method attached to the beneficiary (spei, wire, ach, swift, …). May be empty — a beneficiary with no methods can't be paid yet.
accountNumberMasked — only the last four characters are shown. An account of four characters or fewer is masked completely, and a method with no account number is null.

There is no status field on a beneficiary or on a payment method: deleted beneficiaries and deleted payment methods are simply never returned.

Pick the method whose rail you want: for the business above, spei delivers via the local Mexican rail, wire via international wire.

Destination coverage: beneficiaries can be paid in 190+ countries. bankCountry/bankCurrency and the attached payment methods define the corridor — the local rail differs by country (SPEI in Mexico, PIX in Brazil, SEPA in the Eurozone, ACH in the US, Faster Payments in the UK, and so on), with international wire as the broad fallback. The examples in these docs use a handful of corridors for concreteness — see Destination coverage for the flagship rails and how to confirm a specific corridor.

Pagination

Page-based, matching the rest of the Jeeves Public API: pass page (1-based, default 1) and limit (default 50, values above 200 are clamped to 200, not rejected). A search parameter is also accepted — free text, up to 100 characters, matching name, firstName and lastName as a substring and a payment method's account number by suffix. Any other query parameter is rejected with 400 validation_failed and code: unknown_field — unknown parameters are not ignored.

The envelope is data and count, and nothing else. count is the total matching your query across all pages — stop once page × limit reaches it. The request page and limit are not echoed back, so keep track of them yourself.

Getting one beneficiary

GET /v1/beneficiaries/{beneficiaryId} — scope beneficiaries:read.

curl 'https://public-sandbox.tryjeeves.com/v1/beneficiaries/3f1c9a52-6b7e-4d80-9a13-5c2e8f0b4d76' \
  -H "Authorization: Bearer $JEEVES_ACCESS_TOKEN"

The response is the bare beneficiary object, identical to one entry of data[] in the list — there is no data or count envelope. It includes contactInformation and paymentMethods[]:

{
  "beneficiaryId": "3f1c9a52-6b7e-4d80-9a13-5c2e8f0b4d76",
  "entityType": "individual",
  "firstName": "Ana",
  "lastName": "Gómez",
  "name": null,
  "bankCountry": "MX",
  "bankCurrency": "MXN",
  "contactInformation": {
    "streetAddress": null,
    "city": null,
    "state": null,
    "postcode": null,
    "countryCode": null,
    "phoneNumber": null,
    "emailAddress": null
  },
  "createdAt": "2026-09-10T14:02:11Z",
  "paymentMethods": [
    {
      "paymentMethodId": "b7d2e4a1-8c05-49f3-a6b2-1e7d9c3f5024",
      "paymentMethod": "spei",
      "accountNumber": "••••0001"
    }
  ]
}

Account numbers are masked to the last four characters (an account of four characters or fewer is masked completely, and a method with no account number is null).

An unknown, deleted, malformed or other-customer beneficiaryId returns the same 404 beneficiary_not_found body — never a 403, so the API never confirms that someone else's beneficiary exists.

Creating beneficiaries

Creating a payee takes three calls: create the beneficiary, ask what the corridor needs, then attach a payment method. All three use the beneficiaries:write scope, except the schema read, which needs beneficiaries:read. Add beneficiaries:write to the scopes you request on the token call.

1. Create the beneficiary

POST /v1/beneficiaries — scope beneficiaries:write.

curl -X POST 'https://public-sandbox.tryjeeves.com/v1/beneficiaries' \
  -H "Authorization: Bearer $JEEVES_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "individual",
    "firstName": "Ana",
    "lastName": "Gómez",
    "bankCountry": "MX",
    "bankCurrency": "MXN"
  }'
{
  "beneficiaryId": "3f1c9a52-6b7e-4d80-9a13-5c2e8f0b4d76",
  "status": "active",
  "createdAt": "2026-11-02T14:02:11Z"
}
FieldRule
entityTypeindividual or business.
firstName + lastNameFor an individual.
nameFor a business.
bankCountryUppercase ISO 3166-1 alpha-2, for example MX.
bankCurrencyOne of USD, MXN, BRL, COP, EUR, GBP, CAD, USDB, USDC, USDT, EURC. Any other value is a 400 with unsupported_value.

Each name field is at most 255 characters. A required name field that is missing, or one that belongs to the other entityType, is a 422. Unknown fields are rejected with unknown_field, and a JSON array body is a 400. The beneficiary is created with no payment methods — attach one in step 3.

StatuscodeMeaning
400validation_failed / invalid_request_bodyThe body is not valid, or could not be parsed.
422validation_failedA name field is missing (required) or belongs to the other entityType (unknown_field). The offending fields are listed in errorData.errors[], not in the top-level errors[].
422validation_failedbankCountry is well formed but not a known country: errors[] carries unsupported_value.
422validation_failed with errors[].code: duplicateA beneficiary with the same name, bank country and bank currency already exists. errors[] names name for a business, or firstName and lastName for an individual. This also matches a Boleto-source vendor that the list endpoint doesn't show.

A name-field mismatch looks like this:

{
  "message": "The name fields do not match entityType: individuals use firstName and lastName, businesses use name.",
  "code": "validation_failed",
  "statusCode": 422,
  "requestId": "7186288b-2f41-4c6a-9d85-1b0e3a7c5f92",
  "errorData": {
    "errors": [
      { "field": "firstName", "code": "required", "message": "firstName is required." },
      { "field": "lastName", "code": "required", "message": "lastName is required." },
      { "field": "name", "code": "unknown_field", "message": "name is not allowed." }
    ]
  }
}

This call is not idempotent. No Idempotency-Key is read; a header you send is ignored. The duplicate check is your retry protection. Two simultaneous identical requests can both succeed, because nothing enforces uniqueness at the database — don't fire the same create twice in parallel.

2. Ask what the corridor needs

GET /v1/beneficiary-schemas — scope beneficiaries:read.

curl 'https://public-sandbox.tryjeeves.com/v1/beneficiary-schemas?sourceCurrency=USD&productAccountType=self-funded&destinationCountry=MX&destinationCurrency=MXN&entityType=individual' \
  -H "Authorization: Bearer $JEEVES_ACCESS_TOKEN"
Query parameterNotes
sourceCurrencyRequired. The currency you pay from — one of the supported currencies listed for bankCurrency above.
productAccountTypeRequired. credit-line, self-funded or crypto-wallet.
destinationCountryRequired. Uppercase ISO 3166-1 alpha-2.
destinationCurrencyRequired. The currency the beneficiary receives — one of the supported currencies listed for bankCurrency above.
entityTypeRequired, because the form depends on it.
paymentMethodOptional. Narrows the response to one method, using a paymentMethod value as this endpoint returns it.
{
  "paymentMethods": [
    {
      "paymentMethod": "local_bank_transfer",
      "fields": [
        {
          "fieldName": "accountNumber",
          "type": "string",
          "required": true,
          "pattern": "^\\d{10,18}$",
          "description": "Account number"
        },
        {
          "fieldName": "bankCode",
          "type": "string",
          "required": true,
          "description": "Bank code"
        }
      ],
      "contactFields": [],
      "purposeCodes": [
        { "code": "purchase_of_services", "description": "Purchase of services" },
        { "code": "travel", "description": "Travel" }
      ]
    }
  ]
}

The values above are illustrative — always read the real list for your corridor.

KeyWhat it is
paymentMethodThe value to send, unchanged, as paymentMethod in step 3.
fields[]{ fieldName, type, required, pattern?, allowedValues?, description }, with type one of string, enum or number; allowedValues entries can be strings or numbers. The fieldName values are the keys of bankingInformation in step 3.
contactFields[]The same shape. The fieldName values are the keys of contactInformation. Empty when the method needs none.
purposeCodes[]{ code, description } — the exact list that payment-time validation accepts.

Patterns and purposeCode are enforced again when you create the payment. Your company must hold the funding source you name with sourceCurrency and productAccountType; the methods and purpose codes returned are those for that funding source.

Two vocabularies. paymentMethod here (for example local_bank_transfer) is the value you send in step 3. When you later read the beneficiary, its methods are reported in a normalised vocabulary (ach, spei, wire, and so on — see Coverage), so the two are not interchangeable.

StatuscodeMeaning
400validation_failedA query parameter is missing or invalid. A missing one appears as errors[].code: required — there is no missing_parameter code. A currency outside the supported list, or a destinationCountry that is not an alpha-2 code, reports unsupported_value.
422unsupported_corridorNo payment method is available for this destination.
422unsupported_payment_methodThe paymentMethod you asked for isn't offered for this corridor.
422validation_failederrors[] reports unsupported_value on sourceCurrency when your company doesn't hold that funding source.

3. Attach a payment method

POST /v1/payment-methods — scope beneficiaries:write.

curl -X POST 'https://public-sandbox.tryjeeves.com/v1/payment-methods' \
  -H "Authorization: Bearer $JEEVES_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "beneficiaryId": "3f1c9a52-6b7e-4d80-9a13-5c2e8f0b4d76",
    "paymentMethod": "local_bank_transfer",
    "bankingInformation": { "accountNumber": "0123456789", "bankCode": "021000021" }
  }'
{
  "paymentMethodId": "b7d2e4a1-8c05-49f3-a6b2-1e7d9c3f5024",
  "status": "active"
}

Send the returned paymentMethodId as beneficiaryPaymentMethodId when you create a payment.

  • No corridor parameters. The corridor is taken from the beneficiary's stored bank country and currency.
  • paymentMethod must be a value from the schema response in step 2, sent unchanged.
  • bankingInformation keys must equal fields[].fieldName, and each value is checked against its pattern.
  • contactInformation phoneNumber takes the form +<dialing code> <number> (for example +1 2125551234) and postcode is at most 15 characters; both are published as pattern in contactFields. It is required when the method's contactFields is not empty, unless the beneficiary already has that value stored. When contactFields is empty, any contact key is rejected with unknown_field.
StatuscodeMeaning
404beneficiary_not_foundUnknown, deleted, malformed or other-customer beneficiaryId.
409payment_method_already_existsThe beneficiary already has a payment method on this rail.
422validation_failederrors[] names bankingInformation.<field> for banking fields, keeps contactInformation.<field> for contact fields and uses paymentMethod for the method itself. Reasons: required, invalid_format (the value fails its pattern, which the message names), unsupported_value (a paymentMethod the corridor doesn't offer), unknown_field. A wallet blocked by screening is also a 422 validation_failed, with no per-field detail.

One payment method per rail per beneficiary. The duplicate check uses paymentMethod only, not the account number. To replace a method you would have to delete the old one first, and the public API has no delete — plan the account number before you attach it.

This call is not idempotent. No Idempotency-Key is read, and a retry after a success gets 409.

Bank-detail validation is corridor-specific — a detail that fails the corridor's rules at payment time surfaces as 422 validation_failed.