Go Back

"Receivers" to "Customers" migration: final notice and complete guide

Bernardo SimonassiAndré MayerEric Viana
Bernardo Simonassi, André Mayer, Eric Viana
•

The transition period announced in the June 4 changelog has ended, and the final release that makes "customers" the only name across the BlindPay platform is about to roll out. This post is the complete guide to everything that changes.

Timing: the renames below are not live yet. They ship with the final release, which will be announced on this changelog. Until then, the receiver_* request fields remain the accepted shape on the current API (sending customer_* request fields today is rejected). Use this guide, and the AI prompt at the end, to prepare your migration diff now, and deploy it when the release goes live.

Endpoints

Every legacy /receivers path now returns 301 Moved Permanently pointing at its /customers equivalent.

WasNow
/v1/instances/{id}/receivers[/...]/v1/instances/{id}/customers[/...]
/v1/e/instances/{id}/receivers[/...]/v1/e/instances/{id}/customers[/...]
/v1/instances/{id}/limits/receivers/{id}/v1/instances/{id}/limits/customers/{id}
/v1/instances/{id}/external-receiver-token/v1/instances/{id}/external-customer-token

This covers the customer collection and item routes plus every sub-resource: bank accounts, wallets, blockchain wallets, virtual accounts, offramp wallets, limits, limit increases, and RFIs. The /e/ external invite-flow variants redirect too.

Note that external-receiver-token is renamed even though it has no /receivers/ path segment.

Webhooks

receiver.new, receiver.update, and receiver.delete no longer fire. Subscribe to customer.new, customer.update, and customer.delete instead; they carry the same payloads. The dual-emit behavior from the transition window is gone, so you now receive exactly one event per action.

Renamed fields

WasNowWhere
receiver_idcustomer_idPayins, payouts, quotes, transfers, bank accounts, wallets, blockchain wallets, virtual accounts, offramp wallets, limit increases, RFIs, TOS. Also the path segment and list filter.
receiver_namecustomer_nameCustomer list filter query parameter
receiver_local_amountcustomer_local_amountQuotes, payouts
receiver_wallet_addresscustomer_wallet_addressTransfers, transfer quotes
receiver_networkcustomer_networkTransfers, transfer quotes
receiver_tokencustomer_tokenTransfers, transfer quotes
receiver_invite_redirect_urlcustomer_invite_redirect_urlInstance settings
receiver_rfi_emails_enabledcustomer_rfi_emails_enabledInstance settings
receivers_amountcustomers_amountGET /v1/instances, the count of customers on the instance
receiver_typecustomer_typeRFI
receiver_kyc_statuscustomer_kyc_statusRFI
receiver_aiprise_session_idcustomer_aiprise_session_idRFI
receiver_aiprise_user_profile_idcustomer_aiprise_user_profile_idRFI

The one field that keeps its name

receiver_amount is not renamed. It stays receiver_amount on quotes, payins, payouts, and transfers, because there it means "the amount the receiving side gets", a leg of the transaction rather than a reference to the customer resource.

Do not confuse it with receivers_amount (plural), which is renamed to customers_amount. That one is the customer count on an instance.

This is the single reason a blind find-and-replace of receiver to customer will break your integration.

Renamed error codes

The code field on error responses is a stable identifier meant for programmatic handling, and eleven of them changed prefix.

WasNow
RECEIVERS_NOT_FOUNDCUSTOMERS_NOT_FOUND
RECEIVERS_ALREADY_APPROVEDCUSTOMERS_ALREADY_APPROVED
RECEIVERS_KYC_NOT_APPROVEDCUSTOMERS_KYC_NOT_APPROVED
RECEIVERS_ONBOARDING_INCOMPLETECUSTOMERS_ONBOARDING_INCOMPLETE
RECEIVERS_INVALID_DATACUSTOMERS_INVALID_DATA
RECEIVERS_INVALID_PHONECUSTOMERS_INVALID_PHONE
RECEIVERS_INVALID_TAX_IDCUSTOMERS_INVALID_TAX_ID
RECEIVERS_ID_DOCUMENT_INVALIDCUSTOMERS_ID_DOCUMENT_INVALID
RECEIVERS_COUNTRY_NOT_SUPPORTEDCUSTOMERS_COUNTRY_NOT_SUPPORTED
RECEIVERS_ENHANCED_KYC_REQUIREDCUSTOMERS_ENHANCED_KYC_REQUIRED
RECEIVERS_BUSINESS_ENHANCED_NOT_AVAILABLECUSTOMERS_BUSINESS_ENHANCED_NOT_AVAILABLE

Renamed error messages

The legacy message slug also changed on the errors below. If you branch on message rather than code, update both.

WasNow
receiver_not_foundcustomer_not_found
receiver_id_not_foundcustomer_id_not_found
receiver_already_approvedcustomer_already_approved
receiver_kyc_not_approvedcustomer_kyc_not_approved
receiver_not_approvedcustomer_not_approved
receiver_limit_not_foundcustomer_limit_not_found
receiver_already_has_limit_increase_in_reviewcustomer_already_has_limit_increase_in_review
vm_invalid_receiver_datavm_invalid_customer_data
vm_receiver_country_not_supportedvm_customer_country_not_supported
vm_unsupported_receiver_typevm_unsupported_customer_type
zenus_business_va_requires_business_receiverzenus_business_va_requires_business_customer
beneficiary_name_must_match_receiver_for_first_partybeneficiary_name_must_match_customer_for_first_party
blockchain_wallet_does_not_belong_to_receiverblockchain_wallet_does_not_belong_to_customer
sender_and_receiver_networks_must_be_the_samesender_and_customer_networks_must_be_the_same
sender_and_receiver_tokens_must_be_the_samesender_and_customer_tokens_must_be_the_same

Two message slugs are deliberately unchanged, because they describe the receiving leg of a transaction rather than the customer resource: otc_only_supported_for_sender_without_cover_fees_and_receiver_with_cover_fees, and every slug involving receiver_amount. The currency_type request enum also keeps its sender and receiver values.

Deprecation headers are gone

/receivers responses no longer carry Deprecation: true, Sunset, or Link: rel="successor-version". If you set up the CI smoke test suggested in the June changelog, it now passes trivially instead of catching anything. Replace it with a check that asserts no 301 responses from BlindPay.

IDs are unchanged

Customer IDs keep the re_ prefix, and customer records keep both id and its canonical alias customer_id. No data migration is needed. Do not rewrite stored IDs.

Migrate your code with an AI agent

If you use an AI coding agent (Claude Code, Codex, Cursor, Windsurf, or similar), paste the prompt below into it from the root of your integration. It contains every rename from this changelog and the June announcement, including the exceptions that make a naive find-and-replace unsafe.

text
Migrate this codebase off the deprecated BlindPay "receivers" API surface and onto
"customers". This is a rename of the API surface only: resource IDs are unchanged.

Work through the steps in order and show me a diff before applying anything.

STEP 1 - Find every call site.
Search the whole repo (including tests, fixtures, recorded HTTP cassettes, env
files, OpenAPI/Postman collections, infrastructure config, and docs) for:
  receivers, receiver_, receiverId, RECEIVERS_, "receiver." (webhook event names)

STEP 2 - Rewrite URL paths.
  /v1/instances/{id}/receivers               -> /v1/instances/{id}/customers
  /v1/e/instances/{id}/receivers             -> /v1/e/instances/{id}/customers
  /v1/instances/{id}/limits/receivers/{rid}  -> /v1/instances/{id}/limits/customers/{rid}
  /v1/instances/{id}/external-receiver-token -> /v1/instances/{id}/external-customer-token
Apply to all sub-resources as well: bank-accounts, wallets, blockchain-wallets,
virtual-accounts, offramp-wallets, limit-increase, rfi.
The old paths still answer 301, so nothing breaks immediately, but every call
costs an extra round-trip until this is done.

STEP 3 - Rename request and response fields.
  receiver_id                      -> customer_id
  receiver_name                    -> customer_name
  receiver_local_amount            -> customer_local_amount
  receiver_wallet_address          -> customer_wallet_address
  receiver_network                 -> customer_network
  receiver_token                   -> customer_token
  receiver_invite_redirect_url     -> customer_invite_redirect_url
  receiver_rfi_emails_enabled      -> customer_rfi_emails_enabled
  receivers_amount                 -> customers_amount
  receiver_type                    -> customer_type
  receiver_kyc_status              -> customer_kyc_status
  receiver_aiprise_session_id      -> customer_aiprise_session_id
  receiver_aiprise_user_profile_id -> customer_aiprise_user_profile_id

STEP 4 - CRITICAL EXCEPTION. Do NOT rename receiver_amount.
receiver_amount (singular) is still called receiver_amount on quotes, payins,
payouts, and transfers. It means "amount the receiving side gets", not a
reference to the customer resource. Renaming it will break those calls.
Note the near-miss: receivers_amount (plural, the customer count on
GET /v1/instances) IS renamed to customers_amount. Handle each explicitly.
Never run a blanket s/receiver/customer/ over this repo.

STEP 5 - Rename webhook event names and handlers.
  receiver.new    -> customer.new
  receiver.update -> customer.update
  receiver.delete -> customer.delete
Payloads are identical. Also update the subscription list in the BlindPay
dashboard; a code-only change will leave your endpoint silent.
The old dual-emit is gone, so if a handler was de-duplicating receiver.* against
customer.* for the same action, that workaround can be removed.

STEP 6 - Rename error codes checked in code.
Any comparison against the code field on an error response:
  RECEIVERS_NOT_FOUND -> CUSTOMERS_NOT_FOUND, and the same CUSTOMERS_ prefix
  swap for ALREADY_APPROVED, KYC_NOT_APPROVED, ONBOARDING_INCOMPLETE,
  INVALID_DATA, INVALID_PHONE, INVALID_TAX_ID, ID_DOCUMENT_INVALID,
  COUNTRY_NOT_SUPPORTED, ENHANCED_KYC_REQUIRED,
  BUSINESS_ENHANCED_NOT_AVAILABLE.

STEP 6b - Rename error message slugs checked in code.
If you branch on the message field instead of code, these changed too:
  receiver_not_found            -> customer_not_found
  receiver_id_not_found         -> customer_id_not_found
  receiver_already_approved     -> customer_already_approved
  receiver_kyc_not_approved     -> customer_kyc_not_approved
  receiver_not_approved         -> customer_not_approved
  receiver_limit_not_found      -> customer_limit_not_found
  receiver_already_has_limit_increase_in_review
    -> customer_already_has_limit_increase_in_review
  vm_invalid_receiver_data      -> vm_invalid_customer_data
  vm_receiver_country_not_supported -> vm_customer_country_not_supported
  vm_unsupported_receiver_type  -> vm_unsupported_customer_type
  zenus_business_va_requires_business_receiver
    -> zenus_business_va_requires_business_customer
  beneficiary_name_must_match_receiver_for_first_party
    -> beneficiary_name_must_match_customer_for_first_party
  blockchain_wallet_does_not_belong_to_receiver
    -> blockchain_wallet_does_not_belong_to_customer
  sender_and_receiver_networks_must_be_the_same
    -> sender_and_customer_networks_must_be_the_same
  sender_and_receiver_tokens_must_be_the_same
    -> sender_and_customer_tokens_must_be_the_same
Leave unchanged: any slug mentioning receiver_amount, and
otc_only_supported_for_sender_without_cover_fees_and_receiver_with_cover_fees.

STEP 6c - Do NOT change the currency_type request value.
currency_type still accepts 'sender' and 'receiver'. Sending 'customer' is
invalid. This pairs with the receiver_amount exception in step 4.

STEP 7 - Update the SDK accessor, if you use an official SDK.
  blindpay.receivers.*  ->  blindpay.customers.*
  blindpay.receivers.bankAccounts.create(...)
    ->  blindpay.customers.bankAccounts.create(...)
Method signatures are identical; only the accessor renames. Bump to the latest
release of your current major, which added customers with no import changes.

STEP 8 - Do NOT touch stored IDs.
Customer IDs keep the re_ prefix (re_abc123456789). Leave every stored ID,
fixture, and database value exactly as it is. There is no data migration.

STEP 9 - Verify.
  - grep the repo: no receivers, receiver_id, or receiver.* webhook names left
  - confirm receiver_amount is still present and untouched wherever it was before
  - run the test suite, and update fixtures or cassettes that assert on renamed
    fields
  - check logs for 301 responses from api.blindpay.com; each one is a path you
    missed

Report anything ambiguous rather than guessing.

What you need to do

  1. Update API paths from /receivers to /customers, including the /e/ invite-flow variants and external-customer-token.
  2. Rename request and response fields per the table above, leaving receiver_amount alone.
  3. Update error handling: code comparisons from RECEIVERS_* to CUSTOMERS_*, and message comparisons from receiver_* to customer_*.
  4. Subscribe to customer.* webhooks in the dashboard and update your handlers.
  5. Update your SDK to the latest release of its current major, then switch receivers.* calls to customers.*.
  6. Leave stored IDs untouched. The re_ prefix is permanent.

If you completed the migration before July 3, 2026, the only new work is step 3, the error code and message renames, which ship with this release.

Verification checklist

  • Logs show zero 301 responses from api.blindpay.com, since each one is an unmigrated path
  • Logs show zero requests to /v1/instances/*/receivers* and /v1/e/instances/*/receivers*
  • No code path reads response.receiver_id or any other renamed field
  • receiver_amount is still read correctly on quotes, payins, payouts, and transfers
  • No code path compares an error code against a RECEIVERS_* value, or an error message against a receiver_* slug
  • Requests still send currency_type: 'receiver', not 'customer'
  • Webhook handlers process customer.new, customer.update, and customer.delete, and the dashboard subscription lists them
  • SDK updated, with no remaining receivers.* accessor calls
  • Saved dashboard URLs use /customers/

FAQ

What breaks if I do nothing?

Requests keep working through the 301 redirects, at the cost of an extra round-trip per call, as long as your HTTP client follows redirects (browsers, curl, requests, axios, the official SDKs, and Postman all do by default). Three things break outright: receiver.* webhook subscriptions go silent, code that reads a renamed receiver_* response field gets undefined, and error handling that branches on a RECEIVERS_* code or a receiver_* message stops matching.

Do I need to migrate my stored IDs?

No. All IDs keep the re_ prefix, and both id and customer_id carry the same value. We renamed the API surface, not the underlying resource.

Why does receiver_amount keep its name?

Because it does not refer to the customer resource. On a quote or a payment it means the amount landing on the receiving side, the counterpart to sender_amount. Renaming it to customer_amount would have made it read like a property of the customer record.

Will a find-and-replace work?

Not safely. receiver_amount must survive untouched while receivers_amount must change, and stored re_ IDs must not be rewritten. Use the agent prompt above, which encodes those exceptions, or do the renames field by field.

How do I report issues with the migration?

Use the feedback button in the dashboard (under your profile dropdown) or email support@blindpay.com with migration in the subject. Including the request ID from the response (x-blindpay-request-id header) speeds up the lookup.