Change Log
July 1, 2026
Reminders
- The following fields in the GET /payments, GET /payments/:id, and payment related webhooks were deprecated in the last change log:
chainin the source, destination, and funding instructions object of the response payloaddocumentReference
- Please make sure you are using IP whitelisting for your Production API Keys. If you already have whitelisting enabled on your API key, please make sure that the IP address you have listed matches the server from which you are sending requests
Customers
ReminderEmails: When creating Customers, please ensure to use real emails and phone numbers, as 1) they are often explicitly required by our underlying bank partners, and 2) we use this information as part of our AML and fraud signals. Note that we do not use this information to contact your Customers at any time. Finally, to be very explicit, we will not allow Customers to be created with standardized emails under your Team email (e.g. [team_name]+[customer_name]@[teamURL].com).
Starting July 31, the KYC/KYB process will require the following changes (Breaking Change). Note that we highly recommend completing these updates ASAP as it will improve compliance processing speeds and reduce RFIs.
- All Business customers will require a Proof of Nature of Business document (e.g. invoices, receipts, commercial contracts, bills of lading, etc.)
- Instead of a Bank Statement document, all Business customers will require a Proof of Address document (e.g., bank statement, utility bill, government-issued letter, residential lease agreement) and Proof of Source of Funds document (e.g., bank statement, investment documents, audited financial statements, sale of assets). The reason for removing the Bank Statement requirement is to allow onboarding of companies who may not have one. Note that it is still strongly recommended to provide a bank statement (if available) as the proof of address and proof of source of funds as this is the best document for a rapid KYB process
- Teams who have reliance agreements with Walapay will need to include a Proof of Verification document in the supporting documents section of the customer creation API payload. This document contains the output from an identity verification check done by the provider of your choice (available through Sumsub, Persona, Onfido, AiPrise, etc)
- The following fields will be required for all businesses:
- estimatedAnnualRevenueUSD
- expectedMonthlyPaymentsUSD
- operatesInProhibitedCountries
- highRiskActivities
- conductsMoneyServices
- actingAsIntermediary
- sourceOfFundsDescription
- High Risk countries will require a selfie for individuals (including associated persons)
accountPurposewill be required for all customersbusinessDescriptionmust be at least 200 characterstitlewill be required for all Associated Persons
Please also note that the list of high-risk and prohibited countries has changed. The list of changes is below. The countries moved to prohibited will immediately stop being accepted. For the countries in the High Risk category, we will require the EDD questionnaire to be filled out (see Requirements for Individuals page for questions) starting July 31 (Breaking Change).
- Moved from High Risk to Prohibited: Lebanon and West Bank (effective immediately)
- Moved from Prohibited to High Risk: Central African Republic, Guinea, and Mali
- Added to High Risk: Åland Islands, Antarctica, Benin, Bolivia, Bouvet Island, British Indian Ocean Territory, Bulgaria, Cabo Verde, Central African Republic, Chad, Christmas Island, Cocos (Keeling) Islands, Comoros, Cook Islands, Djibouti, Equatorial Guinea, Eswatini, Falkland Islands, Faroe Islands, French Southern Territories, Gabon, Guinea, Heard Island and McDonald Islands, Kiribati, Kuwait, Kyrgyzstan, Lesotho, Maldives, Mauritania, Montserrat, Norfolk Island, Palau, Panama, Papua New Guinea, Pitcairn, Saint Helena, Ascension and Tristan da Cunha, Saint Kitts and Nevis, Sao Tome and Principe, Sierra Leone, South Georgia and the South Sandwich Islands, Sri Lanka, Svalbard and Jan Mayen, Tajikistan, Thailand, Tokelau, Turkmenistan, Tuvalu, United Arab Emirates, United States Minor Outlying Islands, and Virgin Islands (British)
- Removed from High Risk: Albania, Cayman Islands, Jordan, Kosovo, Morocco, North Macedonia, and Qatar
Accounts
Starting July 31, the following changes will be implemented (Breaking Change):
- The following values will be removed from the accounts requirement endpoint: account holder first name, account holder last name, account holder business name, account type, and bank country code. Note that these values are only included in a small subset of responses; this change will ensure the response format is the same for all country/currency pairs
- JPY accounts will separate the current
bankCodefield into two distinct fields:bankCodeandbranchCode. You can already begin using these two fields - All EUR and GBP external accounts will require the account holder postal code
- CAD accounts will separate the current
transitNumberfield into two distinct fields:bankCodeandtransitNumber. You can already begin using these two fields - When creating a Hong Kong external account, the bank name dropdown will be replaced by a SWIFT code input (in other words, instead of choosing a bank name from a list, you will input the SWIFT code of the bank you want to send funds to).
- For SWIFT payments to Individuals, the ABA routing number of the intermediary bank (ie. the recipient bank's US correspondent bank routing number) must be included in the
routingNumberfield when creating the external account
Some other non-breaking changes:
- Account Holder Country Code is no longer required for the Get External Account Requirements endpoint. The result only depends on the Bank Country Code and Currency Code
- Account Holder Email is no longer a required field when creating an External Account
Payments
ReminderNested flows: Please make sure that you are always selecting underlying Customers as the senders of Payments rather than your own Entity. For Customers who are themselves PSPs / FIs, please make sure you've created a Customer object corresponding to their ultimate end users. Failure to do this can lead to broad freezing of External Accounts and Customers, and even to platform offboarding.
Starting July 31, the following changes will be implemented (Breaking Change).
- Rail options not in the enum provided in the API Reference will return a 400 error. The values themselves have not changed, but we will start enforcing validation (e.g., providing FPS currently does not throw an error, but will after the 31st).

- The payment reason enum will be updated as follows. Please note that the payment reason field currently does not get validated to ensure it matches the below list. We highly recommend you ensure you are using the fields from this list as this may already be causing some of your payments to fail.
Before Changes After REMITTANCE
CAPITAL_CONTRIBUTIONS
CHARITABLE_CONTRIBUTIONS
CONSULTING_FEES
CORPORATE_TAX_PAYMENTS
DOWN_PAYMENTS_FOR_REAL_ESTATE
EDUCATION_FEES
EMPLOYEE_SALARIES_OR_WAGES
EXPENSES_REIMBURSEMENT
GIFTS
GOVERNMENT_GRANTS
INCOME_TAX_PAYMENTS
INHERITANCE_PAYMENTS
INSURANCE_CLAIM_PAYOUTS
INSURANCE_PREMIUM_PAYMENTS
INVESTMENTS
LOAN_ADVANCES
MORTGAGE_PAYMENTS
OTHER
PAYMENT_FOR_GOODS_AND_SERVICES
PURCHASE_OF_GOODS
PURCHASE_OF_SERVICES
PERSONAL_TRANSFERS
REAL_ESTATE_PURCHASES
REMITTANCES
RENT
REPAYMENT_OF_LOANS
ROYALTIES
TRUST_FUND_DISTRIBUTIONS
UTILITY_BILLS
WELFARE_OR_BENEFITS
WINNINGS_AND_PRIZES
AUTO_LIQUIDATIONRemoved (-):
REMITTANCE
CAPITAL_CONTRIBUTIONS
CONSULTING_FEES
CORPORATE_TAX_PAYMENTS
DOWN_PAYMENTS_FOR_REAL_ESTATE
EXPENSES_REIMBURSEMENT
GOVERNMENT_GRANTS
INCOME_TAX_PAYMENTS
INHERITANCE_PAYMENTS
INSURANCE_CLAIM_PAYOUTS
INSURANCE_PREMIUM_PAYMENTS
LOAN_ADVANCES
MORTGAGE_PAYMENTS
OTHER
PAYMENT_FOR_GOODS_AND_SERVICES
REAL_ESTATE_PURCHASES
REMITTANCES
ROYALTIES
TRUST_FUND_DISTRIBUTIONS
WELFARE_OR_BENEFITS
WINNINGS_AND_PRIZES
REPAYMENT_OF_LOANSAdded (+):
FAMILY_AND_FRIENDS_SUPPORT
INSURANCE
INTERCOMPANY_TRANSFER
REAL_ESTATE
TAXES
TRAVEL
LOANSCHARITABLE_CONTRIBUTIONS
EDUCATION_FEES
EMPLOYEE_SALARIES_OR_WAGES
FAMILY_AND_FRIENDS_SUPPORT
GIFTS
INSURANCE
INTERCOMPANY_TRANSFER
INVESTMENTS
LOANS
PERSONAL_TRANSFERS
PURCHASE_OF_GOODS
PURCHASE_OF_SERVICES
REAL_ESTATE
RENT
TAXES
TRAVEL
UTILITY_BILLS
March 4, 2026
Reminders
The following were marked as deprecated in previous posts and are now passed their expiration deadline. Please ensure these are no longer used by your team as code related to them can be deleted at any time.
- CRYPTO should no longer be used as a rail option in POST /payments (use the actual blockchain name instead, like "POLYGON")
- chain field should no longer be used in POST /payments (replaced by using the blockchain name in the "rail" param as described above)
- memo field should no longer used in POST /payments (use "reference" instead)
- POST /configuration/corridors should no longer be used (use POST /payments/corridors instead)
- entityId field in GET /payments/:id response should no longer be used (use "customerId" instead)
- stateOrProvince field should no longer be used in POST /customers or POST /accounts (use stateRegionOrProvince instead)
- estimatedSourceAmount, estimatedDestinationAmount, and estimatedTotalFeeInSourceCurrency fields should no longer be used in GET /payments (use source.amount, destination.amount, and fee fields instead)
- paymentAccountHolder object from the GET /accounts response should no longer be used
- GET /payments/entity/:entityId and GET /payment/recipient/:recipient should no longer be used (use GET /payments/customer/:customerId instead)
IP Whitelisting
If you've created API keys with IP whitelisting, this whitelisting will start being enforced on March 30th (Breaking Change).
Rate Limit
The rate limit described in the Rate Limits page of the documentation will start being enforced on March 15th (Breaking Change).
Customers
Beginning March 30th (Breaking Change), if onboarding an individual, they must be between 18 and 60 years old.
Payments
Error Codes
The following new error codes for failed/refunded payments will start being used on March 15th:
- FUNDING_RECEIVED_AFTER_QUOTE_EXPIRED
- INVALID_EXTERNAL_ACCOUNT_NUMBER
- INVALID_EXTERNAL_ACCOUNT_HOLDER_NAME
- INVALID_EXTERNAL_ACCOUNT_HOLDER_ADDRESS
- FUNDS_RETURNED_BY_RECEIVING_BANK
- EXTERNAL_ACCOUNT_HOLDER_ADDRESS_IS_PMB_OR_PO_BOX
- RFI_NOT_ANSWERED_IN_TIME
- EXTERNAL_ACCOUNT_DEPOSIT_LIMIT_EXCEEDED
Payment Reason
Payment reason OTHER will no longer be an acceptable option starting March 30th (Breaking Change).
POST Response, GET Response, and Webhook standardization
Current State and Issue
The POST /payments response, GET /payments response, GET /payments/:id response, and payment webhook events all have different response structures.
Solution
All POST/GET responses and webhook events related to payments will have the same structure. To avoid breaking changes, this update will occur in 2 steps. The first step is purely additive, which means we combined all the fields across all responses and webhooks. On March 30th, the second step will then be to remove the fields marked for removal below (Breaking Change). This will ensure a cleaner and normalized payload for responses and webhooks.
Structure starting today until March 30th:
{
"id": "wm5tzpjwzigabt199y529t17",
"lifecycle": {
"createdAt": "2026-02-18T18:53:03.109Z",
"sentAt": "2026-02-18T18:53:03.109Z",
"completedAt": "2026-02-18T18:53:03.109Z",
"expiredAt": null,
"refundedAt": null
},
"createdAt": "2026-02-18T18:53:03.109Z", // To be removed (replaced by lifecycle.createdAt)
"updatedAt": "2026-02-19T16:15:04.283Z", // To be removed
"sentAt": null, // To be removed (replaced by lifecycle.sentAt)
"completedAt": null, // To be removed (replaced by lifecycle.completedAt)
"entityId": "cm5e74nqk0003x228bspddfe8", // To be removed (replaced by customerId)
"customerId": "cm5e74nqk0003x228bspddfe8",
"status": "PROCESSING",
"statusReasons": null,
"error": null,
"type": "EXTERNAL",
"paymentType": "EXTERNAL", // To be removed (replaced by type)
"comment": null,
"memo": null, // To be removed (replaced by reference)
"reference": null,
"documentReference": null, // To be removed
"returnAddress": null,
"reason": "PAYMENT_FOR_GOODS_AND_SERVICES", // To be removed (replaced by paymentReason)
"paymentReason": "PAYMENT_FOR_GOODS_AND_SERVICES",
"fee": 1.07,
"developerFee": {
"fixed": null,
"variable": null,
"total": null
},
"exchangeRate": 1, // To be removed (replaced by quote.exchangeRate)
"quote": {
"exchangeRate": 1,
"expiresAt": null
},
"traceNumber": null, // To be removed (replaced by tracking.traceNumber)
"omad": null, // To be removed (replaced by tracking.omad)
"imad": null, // To be removed (replaced by tracking.imad)
"uetr": null, // To be removed (replaced by tracking.uetr)
"tracking": {
"traceNumber": null,
"omad": null,
"imad": null,
"certificate": null,
"uetr": null
},
"files": [
"https://walapay-..."
],
"estimatedTotalFeeInSourceCurrency": 1.07, // To be removed
"configurations": {
"expiredQuoteBehavior": "REFUND_PAYMENT"
},
"source": {
"amount": 10,
"estimatedSourceAmount": 10, // To be removed
"currencyCode": "USDC",
"accountId": null,
"rail": "POLYGON",
"chain": "POLYGON", // To be removed (replaced by rail)
"fromAddress": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"transactionHash": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"fromAccountNumber": null,
"accountNumber": null // To be removed (replaced by fromAccountNumber)
},
"destination": {
"amount": 8.93,
"estimatedAmount": 8.93, // To be removed
"rail": "SWIFT",
"currencyCode": "USD",
"chain": null, // To be removed (replaced by rail)
"accountId": "cmlrcej3j0001kysadfjor6sdl7x",
"transactionHash": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"account": { // Only available for GET response + To be removed
"id": "cmlrcej3j0001ky7ljor6rl7x",
"accountHolderName": "ACME LIMITED",
"type": "EXTERNAL_BANK_ACCOUNT",
"accountType": "CHECKING",
"bankName": "Zheshang Chouzhou Commercial Bank Co., Ltd.",
"accountNumber": "123456789",
"routingNumber": null,
"iban": null,
"bicSwift": "CZCBCN2XXXX",
"ifscCode": null,
"sortCode": null,
"bsbNumber": null,
"nccNumber": null,
"transitNumber": null,
"bankCode": null,
"clabeNumber": null,
"routingCode": null,
"branchCode": null,
"clearingCode": null,
"cnapsCode": null,
"nubanCode": null,
"pixCode": null,
"address": null
}
},
"fundingInstructions": {
"rail": "POLYGON",
"chain": "POLYGON", // To be removed (replaced by rail)
"amount": 10,
"toAddress": "0xExampleAddress1234567890098765432",
"fromAddress": "0x82553ce775b52e0CaB198bc057bb0c21f10D5F07",
"currencyCode": "USDC"
},
"customer": { // Only available for GET response + To be removed
"id": "cm5e74nqk0003x228bspddfe8",
"type": "INDIVIDUAL",
"name": "John Doe",
"email": "[email protected]"
},
"sendingCustomer": { // Only available for GET response + To be removed
"id": "cm5e74nqk0003x228bspddfe8",
"name": "John Doe",
"type": "INDIVIDUAL",
"email": "[email protected]"
}
}Structure starting March 30th:
{
"id": "wm5tzpjwzigabt199y529t17",
"lifecycle": {
"createdAt": "2026-02-18T18:53:03.109Z",
"sentAt": "2026-02-18T18:53:03.109Z",
"completedAt": "2026-02-18T18:53:03.109Z",
"expiredAt": null,
"refundedAt": null
},
"customerId": "cm5e74nqk0003x228bspddfe8",
"status": "PROCESSING",
"statusReasons": null,
"error": null,
"type": "EXTERNAL",
"comment": null,
"reference": null,
"returnAddress": null,
"paymentReason": "PAYMENT_FOR_GOODS_AND_SERVICES",
"fee": 1.07,
"developerFee": {
"fixed": null,
"variable": null,
"total": null
},
"quote": {
"exchangeRate": 1,
"expiresAt": "2026-02-18T18:53:03.109Z"
},
"tracking": {
"traceNumber": null,
"omad": null,
"imad": null,
"certificate": null,
"uetr": null
},
"files": [
"https://walapay-...."
],
"configurations": {
"expiredQuoteBehavior": "REFUND_PAYMENT"
},
"source": {
"amount": 10,
"currencyCode": "USDC",
"accountId": null,
"rail": "POLYGON",
"fromAddress": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"transactionHash": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"fromAccountNumber": null
},
"destination": {
"amount": 8.93,
"rail": "LOCAL",
"currencyCode": "GBP",
"transactionHash": "0x82553ce775b52e0cab198bc057bb0c21f10d5f07",
"accountId": "cmlrcej3j0001ky7ljor6rl7x"
},
"fundingInstructions": {
"rail": "POLYGON",
"amount": 10,
"toAddress": "0xExampleAddress1234567890098765432",
"fromAddress": "0x82553ce775b52e0CaB198bc057bb0c21f10D5F07",
"currencyCode": "USDC"
},
}Expiration
Current State and Issue
Payments have a guaranteed source/destination quote as long as they are funded before the expiration period (e.g, 15 minutes). For payments that include a source.accountId in the payload, this is not relevant since funds are immediately pulled from the source account. For payments without a source.accountId, however, this can mean that a payment status changes from AWAITING_FUNDS to EXPIRED if not funded in time (and funds sent to an EXPIRED payment are refunded). This method has two issues:
- It's not clear at what point exactly the status will change to EXPIRED
- There is an edge case where a customer can send funding before the expiry deadline, but because of blockchain delays, Walapay isn't notified of this transaction until after expiration. This can cause the following scenario:
- Customer sends funds before expiry deadline but there are blockchain delays in receiving the notification
- Quote expires and the user sees the payment change from AWAITING_FUNDS to EXPIRED
- User doesn't understand what happened to the funds they sent
- The payment then completes after the blockchain traffic clears and the status changes from EXPIRED to SENT (and then COMPLETED). User is now even more confused
Solution
To fix this, we are changing how payments expire:
- To make it clear when the expiration window closes, we have added the quote.expiresAt field in the payment response (see previous section). This is the exact time at which the quote is no longer valid. Any funds that are sent before this deadline will guarantee the quote (even if there are blockchain or bank delays that mean Walapay receives the notification after the expiry time)
- The payment response will also include the configurations.expiredQuoteBehavior field, which describes the expected behavior when funds are sent after the quote expiry. Currently, REFUND_PAYMENT is the default and only option (we will soon be expanding this)
- The EXPIRED status of a payment no longer represents when the quote expires. Instead, quote validity is defined only by a new quote.expiresAt field. A payment will stay in AWAITING_FUNDS for 3 business days if it is not funded. If no funds arrive in that period, the payment is then moved to EXPIRED purely for housekeeping (so very old, unused payments do not stay open forever).
The scenario described in issue 2 would now go like this:
- Customer sends funds before expiry deadline, but there are blockchain or banking delays
- Payment quote expires (i.e., the expiresAt time is now past), but the payment status itself stays on AWAITING_FUNDS
- Funding notification is received after delays cleared and Walapay sees that the funds were sent before the expiry deadline. The payment goes to PENDING and continues as a normal payment
This expiresAt parameter is available today and should be used as the source of truth for quote validity. The change to EXPIRED status occurring after 3 business days, however, will start taking effect on March 30th. (Breaking Change).
September 12, 2025
- When creating an external digital asset wallet, you no longer need to match the
accountHolder.address.countryCodeto the country for which you would like to onramp funds. In the past, if you wanted to do a BRL to USDC onramp, you would have to create the external digital asset wallet with theaccountHolder.address.countryCodeof BR. If you wanted to use the same wallet address to onramp from PHP, you would have to create another external digital asset wallet withaccountHolder.address.countryCodeof PH. This is no longer the case. One external digital asset wallet can be used for all onramps (andaccountHolder.address.countryCodeshould represent where the user actually lives) - External digital asset wallets will start requiring currency codes. This means that if you want to use one address to send USDC and USDT, you will need to create two accounts to represent each currency (with only the currency code differing between the two). Breaking change: Starting October 10th, creating an external digital asset wallet will return an error if no currency code is provided. For all existing wallets that don't have a currency code by that date, these will be automatically updated to have the currency code of their last payment (defaulting to USDC if no payment exists). EDIT: The breaking change date for this has been postponed. We will provide a new breaking change date shortly.
- For virtual bank accounts with liquidation information,
liquidationAccountIdcan be provided instead ofliquidationInformation. To do this, the liquidation account must first be created and its ID can then be used in theliquidationAccountIdfield for a virtual bank account. Breaking change: Starting October 10th, theliquidationInformationparameter will be deprecated entirely. EDIT: The breaking change date for this has been postponed. We will provide a new breaking change date shortly. - When creating a business customer, the
estimatedAnnualRevenueUSDfield had two incorrect options:FIFTY_MILLION_TO_TWENTY_FIVE_MILLIONandOVER_TWENTY_FIVE_MILLION. Two new options have been added to replace these:FIFTY_MILLION_TO_TWO_HUNDRED_AND_FIFTY_MILLIONandOVER_TWO_HUNDRED_AND_FIFTY_MILLION. Breaking change: Starting October 10th, the old incorrect fields will be removed - You can now include a
returnAddressfield when creating a stablecoin-to-fiat payment in case you want the funds returned to a specific address in case of payment failure - The
referencefield for payments will replace thememofield. Breaking change: Starting October 10th, thememofield will be deprecated - In the GET /accounts/:id and accounts webhook events, the
accountHolderobject will replacepaymentAccountHolder. Currently, both are present. Breaking change: Starting October 10th, onlyaccountHolderwill remain
September 8, 2025
Summary: Deposits are being replaced with payments of type PAYIN.
Previously, when funds were sent to a Virtual Account, a new deposit record was created with details regarding the source of the money. However, for Virtual Accounts with automatic conversion to stablecoins or fiat, no data was provided regarding where the money was sent. To fix this issue, we are deprecating the use of deposits entirely and introducing a new paymentType parameter for payments. The types are described below:
- INTERNAL: Funds are sent from a Virtual Account to another Virtual Account (e.g., from a virtual bank account to a virtual digital asset wallet)
- PAYIN: Funds are sent from an External Account to a Virtual Account (e.g., from an external bank account to a virtual bank account). This will replace the deposit record
- PAYOUT: Funds are sent from a Virtual Account to an External Account (e.g., from a virtual bank account to an external digital asset wallet)
- EXTERNAL: Funds are sent from an External Account to another External Account (e.g., from an external bank account to an external digital asset wallet).
By representing deposits as payments, you will be able to see all money movement in a chronological order and keep track of automatic conversions. Below is a short representation of the change:
Before:
- Funds are sent to a virtual account
- A deposit record is created and an account.deposit webhook is triggered
- No record is created or webhook triggered for the automatic conversion
After:
- Funds are sent to a virtual account
- A PAYIN payment record is created and a payment.created webhook is triggered
- Another payment record is created to represent the automatic conversion (PAYOUT or INTERNAL depending on the destination account type) and a payment.created webhook is triggered
Breaking Change: Deposits will be deprecated fully on September 30th. Before then, your existing deposits will be transferred to your payments as PAYINs.
August 25, 2025
Summary: The main objective of this release is to allow developers to select a specific rail for a payment. Previously, only LOCAL, CRYPTO, and WIRE were allowed. The dashboard has NOT yet been updated to use these new endpoints.
Corridors
The first step was creating a new GET /payments/corridors endpoint that allows you to see which corridors/rails are available. A few notes:
- "rails" now contains all supported blockchains and all supported fiat rails. "chain" has been deprecated
- "currencyCodes" and "rails" are now arrays, allowing us to greatly reduce the number of objects returned by the response. Instead of having an object for every permutation of blockchain and stablecoin (e.g., POLYGON/USDC, ETHEREUM/USDC, BASE/USDC), these are all concatenated into one object
- Instead of having fees for LOCAL, CRYPTO, and WIRE, fees are now specific to the source and destination rail combination.
Breaking Change: GET configurations/corridors will be deprecated September 30th.
Before (GET configurations/corridors):
"data": [
{
"source": {
"currencyCode": "USDC",
"chain": "POLYGON"
},
"destination": {
"currencyCode": "BRL",
"chain": null,
"countryCode": "BR"
},
"fees": {
"LOCAL": {
"fixedFeeInUSD": 1,
"variableFeeInSourceCurrency": 0.005
},
"CRYPTO": {
"fixedFeeInUSD": 1,
"variableFeeInSourceCurrency": 0.005
},
"WIRE": {
"fixedFeeInUSD": null,
"variableFeeInSourceCurrency": null
}
}
}
]After (GET payments/corridors):
"data": [
{
"source": {
"currencyCodes": [
"USDC",
"USDT",
"EURC"
],
"rails": [
"POLYGON",
"ETHEREUM",
"BASE",
"SOLANA",
"TRON"
]
},
"destination": {
"currencyCodes": [
"BRL"
],
"rails": [
"TED"
],
"countryCode": "BR"
},
"fees": {
"fixed": 1,
"variable": 0.005
}
}
]Customers
Previously, if your team had USD corridors enabled, all onboarded customers would require passing through compliance checks mandated by US banks (which tend to be slower). Since it's possible not all your customers need access to USD corridors, you can now specify which capabilities you would like to enable for the onboarded customer: USD and OTHER (putting both or not including the capabilities parameter in the request will give the customer access to all corridors).
Important note: USD capability also covers EUR onramps.
Example
{
"type": "INDIVIDUAL",
"capabilities": ["OTHER"], // Optional
"firstName": "Jason",
"lastName": "Smith",
....
}Accounts
GET /requirements
With the ability to choose which rail to send the payment, it is also important to know which parameters are required for each rail when creating an account. We have therefore created a new GET /accounts/requirements endpoint to replace the existing GET /accounts/requirements/external-bank-accounts endpoint. A few notes:
- Objects are not grouped by INDIVIDUAL and BUSINESS anymore. Instead, each variable will have an accountHolderTypes array to designate to whom it applies
- The regex provided for IBANs is now specific to the country
Breaking Change: GET /accounts/requirements/external-bank-accounts will be deprecated September 30th.
Before (GET /accounts/requirements/external-bank-accounts):
{
"INDIVIDUAL": [
{
"variableName": "bank.accountNumber",
"regex": "^[0-9]{2,15}$",
"example": "001000456789",
"enum": []
},
....
],
"BUSINESS": [
{
"variableName": "bank.accountNumber",
"regex": "^[0-9]{2,15}$",
"example": "001000456789",
"enum": []
},
...
]
}After (GET /accounts/requirements):
[
{
"variableName": "bank.accountNumber",
"rails": [
"TED"
],
"accountHolderTypes": [
"INDIVIDUAL",
"BUSINESS"
],
"regex": "^[0-9]{2,15}$",
"example": "001000456789",
"enum": []
},
...
{
"variableName": "bank.pixCode",
"rails": [
"PIX"
],
"accountHolderTypes": [
"INDIVIDUAL",
"BUSINESS"
],
"regex": "^.{1,100}$",
"example": "01.234.456/5432-10 (cnpj) | 123.456.789-87 (cpf) | +5511912345678",
"enum": []
}
]POST /accounts
In addition to the revamped requirements endpoint, you can now specify the rails you want to unlock for the account you create. Currently, this can be done for two different countries:
- US: ACH, ACH_SAME_DAY, and DOMESTIC WIRE. Some US banks don't have all three rails for their accounts, so it's important to designate which rails can be used to send funds. If you do not include the "rails" field in the request, the account will get access to all 3 by default
- BR: TED and PIX. These rails have different field requirements. By selecting which rail you want to enable for the account, you can make sure to only ask your customer for the actual fields required for the rail you want to use. If you do not include the "rails" field in the request, the account will get access to TED by default
Example
{
"type": "EXTERNAL_BANK_ACCOUNT",
"currencyCode": "BRL",
"isThirdParty": true,
"rails": ["TED", "PIX"],
"bank": {
"name": "BANCO DO BRASIL S.A",
....
}Payments
GET /rate
With the introduction of specific rails, the GET /payments/rate/walapay has also been replaced with GET /payments/rate to provide the details of the specific rail chosen. A few notes:
- Instead of query parameters sourceChain and destinationChain, it is sourceRail and destinationRail
- You can still use LOCAL as the value for "rail". Behind the scenes, we map this value to the appropriate country-specific rail
- The current /payments/rate/walapay will append the results of the new endpoint automatically so that you can transition from one to the other smoothly
Breaking Change: GET /payments/rate/walapay will be deprecated September 30th.
Before (GET /payments/rate/walapay):
{
"midMarketRate": 5.4952529294,
"invertedMidMarketRate": 0.1819755763,
"walapayFees": {
"description": "The Walapay fees for the payment based on the destination rail",
"LOCAL": {
"fixed": 1,
"variable": 0.001
},
"WIRE": {
"fixed": 45,
"variable": 0.0065
},
"CRYPTO": {
"fixed": null,
"variable": null
}
},
"walapayRates": {
"description": "[Deprecated] The mid market rate minus the Walapay variable fee: mid market rate * (1 - Walapay variable fee)",
"LOCAL": 5.4897576764706,
"WIRE": 5.459533785358901,
"CRYPTO": null
},
"developerFees": {
"description": "The developer fees for the payment. Added on top of the walapay fees.",
"fixed": null,
"variable": null
},
"calculatedAmounts": {
"LOCAL": {
"sourceAmount": 679.27,
"destinationAmount": 3723.52,
"totalFeeInSourceCurrency": 1.68
},
"WIRE": {
"sourceAmount": 727.03,
"destinationAmount": 3723.52,
"totalFeeInSourceCurrency": 49.44
},
"CRYPTO": {
"sourceAmount": null,
"destinationAmount": null,
"totalFeeInSourceCurrency": null
}
},
"quoteId": "cmdxts4kx0000dunid010mqd7"
}After (GET /payments/rate):
{
"midMarketRate": 5.495449870300001,
"invertedMidMarketRate": 0.18196857419999998,
"walapayFee": {
"fixed": 1,
"variable": 0.007
},
"developerFee": {
"fixed": 1,
"variable": 0.01
},
"calculatedAmount": {
"description": "The calculated amounts for the payment, along with total fee (both walapay and developer).destinationAmount = (((sourceAmount - walapayFixedFee) * (1 - walapayVariableFee)) - developerFixedFee) * midMarketRate * (1 - developerVariableFee). sourceAmount = (destinationAmount / (midMarketRate * (1 - developerVariableFee)) + developerFixedFee) / (1 - walapayVariableFee) + walapayFixedFee.",
"sourceAmount": 691.24,
"destinationAmount": 3723.52,
"totalFeeInSourceCurrency": 13.68
},
"quoteId": "cmdxtdy6e000010y04ovhu28i"
}POST /payments
In addition to the new rate endpoint, the POST /payments endpoint has been updated to allow you to choose a country-specific rail if desired. A few notes:
- To start, the currencies that will have multiple options:
- USD: ACH, ACH_SAME_DAY, DOMESTIC_WIRE
- BRL: TED, PIX
- INR: IMPS, IMPS_WITH_FIRC
- You can still use LOCAL if you want Walapay to choose the default option on your behalf
- You can still use CRYPTO in the request if the rail is a blockchain. We will map the value provided for
chainto replace CRYPTO under the hood. The mapped value will be saved as the rail - For SWIFT payments, you should use the rail type "SWIFT" (WIRE is deprecated)
Before:
{
"source": {
"currencyCode": "USDC",
"amount": 10,
"rail": "CRYPTO",
"chain": "POLYGON",
"fromAddress": "0x9dE08B842B9f9E27c478fF816330118939a7BF90"
},
"destination": {
"currencyCode": "USD",
"rail": "LOCAL",
"accountId": "cmca02pfl000cfc5qjs3emffc"
},
"comment": "Test Transaction",
"memo": "Test",
"paymentReason": "CONSULTING_FEES",
"documentReference": "Test"
}After (with "source.rail" as "POLYGON" and "destination.rail" as "ACH_SAME_DAY"):
{
"source": {
"currencyCode": "USDC",
"amount": 10,
"rail": "POLYGON",
"fromAddress": "0x9dE08B842B9f9E27c478fF816330118939a7BF90"
},
"destination": {
"currencyCode": "USD",
"rail": "ACH_SAME_DAY",
"accountId": "cmca02pfl000cfc5qjs3emffc"
},
"comment": "Test Transaction",
"memo": "Test",
"paymentReason": "CONSULTING_FEES",
"documentReference": "Test"
}Updated 17 days ago
