Guides

Off-Ramp API for Crypto Exchanges: BRL, MXN and COP Withdrawals

How an exchange adds local-currency withdrawals: who is verified, the BRL, MXN and COP rails, the quote screen, limits, Travel Rule data and ledger states.

Caio Barbosa

Founder & CO-CEO

Forbes Under 30. One of the leading voices in Fintech & Crypto in Brazil. Writes weekly about stablecoins, payments, and the future of financial infrastructure in Latin America.

Cover image for Lumx blog article: Off-Ramp API for Crypto Exchanges: BRL, MXN and COP Withdrawals
Cover image for Lumx blog article: Off-Ramp API for Crypto Exchanges: BRL, MXN and COP Withdrawals

An off-ramp API for crypto exchanges is a service that converts a user's stablecoin balance into local currency and pays it to the user's own bank account over a local rail. The provider handles the conversion, the payout and the payment-leg compliance checks.

How does a withdrawal move from an exchange balance to a bank account?

Six steps, with the exchange's own ledger around them. The basics are in what a stablecoin off-ramp is.

The six steps of a fiat withdrawal, and who owns each

Step

What happens

Owner

1. Onboard

The user becomes a verified customer of the provider

Provider, started by the exchange

2. Register the account

The user's own bank account is stored as a destination

Exchange, checked by the provider

3. Quote

The user sees the local amount before confirming, exact on a locked quote and labelled as an estimate otherwise

Provider, shown by the exchange

4. Fund and execute

The exchange moves stablecoin to the user's wallet and submits the payout

Exchange

5. Convert and pay

The balance is sold and the local payment leaves over the rail

Provider

6. Close the ledger

The exchange marks the withdrawal done or failed from a webhook

Exchange

On Lumx, the withdrawal is an off-ramp: it debits the stablecoin wallet of the customer who owns the destination, converts it, and pays the local rail. The exchange follows it through the offramp.transferring_stablecoin, offramp.trading, offramp.transferring_fiat and offramp.success events.

Onboarding the exchange and each withdrawing user

Two parties are verified: the exchange as a business, and each withdrawing user as an individual with a wallet and a destination of their own.

A VASP (virtual asset service provider, the Financial Action Task Force's term for exchanges and custodians) is allowed with disclosure, which triggers Enhanced Due Diligence and ongoing monitoring instead of a standard review (what a VASP is). A business that runs without the licence its jurisdiction requires is not served at all. Start the exchange's own KYB (know your business, the verification of a company and its owners) first (what KYB involves).

On Lumx, the exchange registers as a business customer, picks VASP as its business activity, and submits its regulated-activity information with the licence. A VASP goes through KYB Enhanced, which targets three business days.

The users are the second half. A user who lives in Brazil is created as an individual customer with a tax ID that is valid in Brazil, accepts the terms of service and submits identity data, a document and a liveness check, and the standard KYC (know your customer, the verification of an individual) review targets one business day. An exchange that already verified the user on Sumsub can reuse that work: with a data-sharing agreement arranged through compliance@lumx.io, the exchange passes a share token when it creates the customer. With reuse the customer does not resubmit documents or liveness, and it is open to individuals only.

I recommend starting a user's verification when they first deposit or open the withdraw screen, not at the first withdrawal, so a user who has just sold is not waiting on a review. I would also keep the exchange's ledger as the source of truth and treat the provider wallet as a staging balance, filled only for a withdrawal the user is about to confirm.

Which rails can a withdrawal land on?

The user's local rail, set by the destination they register: Pix (Brazil's instant payment system, run by the Central Bank of Brazil) in Brazil, SPEI (Mexico's interbank transfer system, run by Banxico) in Mexico, and Bre-B (Colombia's instant payment system) or ACH in Colombia.

The three withdrawal rails for BRL, MXN and COP, with what the destination needs and the per-payment ceiling

Currency

Rail

What the destination needs

Ceiling per payment

Settles

BRL

Pix

The user's Pix key and tax ID. See USDC to BRL

The customer's off-ramp limit

Instant, every day at any hour, unless a review applies

MXN

SPEI

A CLABE (the 18-digit Mexican bank account number), holder type, tax ID and name

The customer's off-ramp limit

Instant, every day at any hour, unless a review applies

COP

Bre-B

The receiver's Bre-B key. See USDC to COP

1,000 UVB, about COP 12.1 million

Instant, like Pix

COP

ACH Colombia

Name, document type and number, email, bank, account and account type

No per-payment limit

No fixed time quoted

Large amounts can trigger a risk review of up to two business hours, and a transaction held for an RFI (request for information, a compliance hold that asks for a document) waits until it is answered.

COP has two routes, and the user picks one when the destination is created, because the rail stays fixed on it. A Bre-B payout above the ceiling is refused, never split or moved to another rail. The ceiling comes from the Banco de la República, Circular Reglamentaria Externa DSP-465, Asunto 18, numeral 3.2 (March 31, 2026), and binds every provider. In 2026, 1,000 UVB is COP 12,110,000. A larger withdrawal needs a second destination on ACH Colombia. The full pair list is on the coverage page. For providers ranked by region, read the best stablecoin off-ramp APIs.

On Lumx, a destination for Pix or Bre-B or SPEI or ACH Colombia is created under a customer record with the holder relationship SELF when the user is paying their own account, and it goes through verification before it can be used, which the destinations.approved webhook reports.

Quote first, execute second: the withdrawal screen

The screen should show the number the user will receive before committing: a quote when the confirm step opens, then the payout when the user taps confirm. A payout without a quote lands at the market rate of that second. How long a price holds is in how long a payment quote lasts, and the layout in the cross-border payment quote screen.

The confirm screen needs the stablecoin leaving, the rate, the exchange's own fee, the local amount arriving and the time left on the price.

Use a floating rate, with no lock, for the estimate while the user types. On the confirm screen use a 30-second lock, which carries no fee. A 1-minute lock fits a 2FA step and a 5-minute lock a review step, and both carry a fee.

The payout debits the user's wallet and a lock lasts five minutes at most. A transfer between two onboarded customers settles in seconds with no FX, so the exchange can fund the wallet when the user confirms and still use the lock. Do not start the lock before the funding step is ready, or accept a floating rate and label the amount as an estimate.

For Pix, SPEI, Bre-B and ACH Colombia withdrawals on Lumx, POST /exchange-rates with type: LOCKED returns an id and an expiresAt, plus finalTargetAmount and finalExchangeRate, the figures to show on the confirm screen. The off-ramp then takes that id as exchangeRateId. An expired lock returns EXCHANGE_RATE_EXPIRED, and the fix is a new quote. The exchange's own withdrawal fee is a partner fee, in basis points, a flat dollar amount or both, applied by sending its partnerFeeId with the rate request and collected in a wallet the exchange names. A locked quote by target amount works for USDC to COP too.

How much does an off-ramp API cost an exchange?

Three prices stack on a withdrawal: the provider's fee, set by its agreement and returned on the quote, the exchange's own fee, shown as its own line on the confirm screen, and whatever the receiving bank charges.

Lumx prices on a monthly platform fee plus usage-based per-transaction fees, transparent FX on locked quotes, no pre-funding; no published plans. The exchange's own partner fee rides on the same quote. The Lumx fee is not deducted from the amount that arrives on Pix, SPEI or Bre-B: the local amount on the quote is what arrives, and only the receiving bank can charge the user. No pre-funding means no capital parked in settlement (nostro) accounts before a withdrawal, and the user's wallet balance is a separate matter.

Limits a withdrawal has to respect

A withdrawal over a limit is rejected before any money moves, so read the limit before you draw the screen. Limits follow the verification level and count per transaction type, so a deposit never uses up payout room.

Default limits by verification level, in USD, from the Lumx transaction-limits page read on November 1, 2026

Limit

KYC Standard

KYC Enhanced

KYB Standard

KYB Enhanced

Per transaction

7,500

25,000 and above

50,000

50,000 and above

Daily

15,000

50,000 and above

100,000

100,000 and above

Monthly

15,000

50,000 and above

100,000

100,000 and above

For an exchange of retail users, the first column bites: a 20,000 USD withdrawal needs Enhanced verification first, and small withdrawals can still hit the daily cap on the last one. The limits are the same in every country. Ceilings by rail are in payout limits and cut-offs by rail.

On Lumx, reading a customer with includeTransactionLimits=true returns the max, used and remaining amounts for the off-ramp window, so the screen can show "you can withdraw up to X today". A request over a limit returns TRANSACTION_LIMIT_EXCEEDED with a 422. Limits are per transaction type, so each move the exchange makes with the Transfer endpoint to fund a user wallet counts against its own transfer limit, in the KYB columns of the table: 50,000 per transaction and 100,000 per day at Standard. A limit-increase request, filed with a supporting document, targets a one-business-day review.

Travel Rule data on a withdrawal

FATF Recommendation 16, the Travel Rule (revised in June 2025), requires a VASP that sends a virtual asset transfer to pass originator and beneficiary information to the receiving VASP. That obligation sits with the exchange, and its compliance team owns the answer on which transfers carry the data, including a transfer to a user's wallet at a provider. Fields and the hold-or-return decision are in the Travel Rule guidelines.

On Lumx, every transaction is screened before it runs, in both directions, and Lumx is aligned with the Travel Rule. Destination wallet addresses will become destinations in the API, like the fiat accounts, with no date yet. Every withdrawal carries the holder details of the destination and a purpose code, which is what the compliance review reads. A user paying their own account sends PERSONAL_ACCOUNT, valid only with a SELF destination, and a holder tax ID that differs from the customer's returns HOLDER_TAX_ID_MISMATCH.

What the exchange ledger does at each off-ramp status

A withdrawal debits the user once and holds the amount as pending until a final status arrives.

Off-ramp statuses and the matching ledger action

Status

What it means

Ledger action

TRANSFERRING_STABLECOIN

Stablecoin is leaving the user's wallet

Hold the amount as pending

TRADING

The conversion is being executed

Keep holding

TRANSFERRING_FIAT

The local payment is on its way to the bank

Show "sent to your bank"

SUCCESS

The payment left the banking partner

Release the hold and close the withdrawal

FAILED

The off-ramp did not complete

Do not credit by timer; read the transaction and write to operations@lumx.io first

Store the idempotency key with the withdrawal row before you send, and reuse it on every retry. Keys expire after 24 hours, and the same key with a different body returns a 409.

Lumx calls the off-ramp complete when the payment leaves its banking partner, which is offramp.success. An RFI left unanswered for 24 hours may end with the transaction refunded to the sender.

When an off-ramp API is the wrong tool for an exchange

It is the wrong tool when the exchange cannot name who is being paid, because a pooled payout account with no per-user onboarding is nesting. Nesting needs written approval from compliance (compliance@lumx.io); without it the transaction may be delayed, rejected or reversed. It is also the wrong tool without the licence the exchange's jurisdiction asks for, since Lumx does not onboard unlicensed virtual asset providers. Fit test: does each user have a Pix key, a Bre-B key, a CLABE (the Mexican bank account number) or the ACH Colombia bank details?

How this works on Lumx

Lumx is stablecoin payments infrastructure for businesses that move money between Latin America and the rest of the world: one API to collect, hold, convert, and pay out in BRL, MXN, COP, USD, EUR, and GBP or in USDC and USDT, over local rails such as PIX, SPEI, PSE, Bre-B, ACH, FEDWIRE, SEPA, and Faster Payments, with SWIFT and on-behalf-of payments and collections (POBO and COBO) in USD, EUR, and GBP, plus named virtual accounts, custodial wallets, and KYB/KYC built in.

For an exchange, the shape is this. The exchange is one business customer. A withdrawing user who lives in Brazil is an individual customer with a wallet on each supported network and a SELF destination on Pix. For users in Mexico or Colombia, tell Lumx where your users live when you scope the integration, so the onboarding path is settled before you build the screen. Withdrawals run in USDC on Ethereum, Polygon and Base, and USDT on Ethereum, Polygon and Tron. The exchange moves stablecoin to the user's wallet, either to the address or with the Transfer endpoint between two onboarded customers, and the off-ramp then debits that wallet.

Compliance sits inside the API: KYB for the exchange, KYC for each user through Sumsub, verification of each destination and monitoring of blockchain transactions through Chainalysis. The product is under global payments, the calls in how to integrate a stablecoin API, and the corridors on the operator map. An API integration takes 2 to 3 weeks to go-live.

The first sandbox run should cover the cases a happy path hides: a withdrawal followed to offramp.success, a lock left to expire so the exchange sees EXCHANGE_RATE_EXPIRED, an amount over the limit that returns TRANSACTION_LIMIT_EXCEEDED, a retry with the same idempotency key, an offramp.failed event that leaves the ledger pending, and a Bre-B payout above the ceiling.

Verified on November 1, 2026. Operational context, not legal, tax, or investment advice.

Cover photo: Leo chen on Unsplash.

  • How does an off-ramp API for crypto exchanges work?

    The exchange verifies each withdrawing user with the provider, registers the user's own bank account, requests a quote, moves stablecoin to the user's wallet and submits the payout. The provider converts and pays the local rail, and webhooks tell the exchange when to close the withdrawal. On Lumx, the user is a customer with a wallet, the bank account is a SELF destination, and the off-ramp debits that wallet.

  • How long should the withdrawal quote last?

    Long enough to read the screen and confirm, since a longer lock costs more. On Lumx, a withdrawal rate locks for 30 seconds at no fee, or 1 or 5 minutes with a fee, and the off-ramp takes the quote's exchangeRateId. An expired lock returns EXCHANGE_RATE_EXPIRED, so request a new one.

  • How much does an off-ramp API cost an exchange?

    The exchange pays the provider's fees and chooses whether to add its own. On Lumx, pricing is a monthly platform fee plus usage-based per-transaction fees, transparent FX on locked quotes, no pre-funding; no published plans, and the Lumx fee is not deducted from the amount that arrives on Pix, SPEI or Bre-B.

  • How long does a fiat withdrawal take?

    On Pix and SPEI the payment is instant at any hour, every day. A large amount can add up to two business hours of risk review, and an RFI holds the transaction until it is answered. On Lumx, offramp.success means the payment has left the banking partner, and the receiving bank can still hold funds for its own review.

  • What should the exchange do when a withdrawal fails?

    Keep the amount pending, never credit it by timer, and read the transaction first. On Lumx, offramp.failed is the event to watch. Its payload says "Your transaction has failed. Please contact support.", so the ledger step, a credit back or a retry, follows the exchange's own policy and a check of the transaction.

Stay up to date with what Lumx is developing.

Sign up to receive them by email.

Share on socials:

off-ramp-api-for-crypto-exchanges

A

off-ramp-api-for-crypto-exchanges

Off-Ramp API for Crypto Exchanges: BRL, MXN and COP Withdrawals

Copy link

Copied!

off-ramp-api-for-crypto-exchanges

TALK TO OUR TEAM

Ready to transform your business with stablecoins?

Discover how our infrastructure can seamlessly integrate stablecoins into your financial operations quickly, securely, and efficiently.

Guides

In this page

©2026. All rights reserved.

Lumx US OP LLC ("Lumx") is a financial technology and payments infrastructure company. Lumx US OP LLC is a Money Service Business (MSB) registered with the Financial Crimes Enforcement Network (FinCEN) (MSB #31000316459619). Lumx is not a state-licensed money transmitter and does not, in its own capacity, engage in the provision of regulated money transmission services. All such regulated activities are conducted exclusively through, and under the licenses of, duly authorized financial-institution partners.


Lumx is not a bank, financial institution, payment institution, or custodian of client funds. Certain services made available through the Platform may be provided by duly authorized and regulated third-party partners, in accordance with applicable laws and regulations.

Please refer to Lumx’s Terms of Use and Privacy Notice for further information regarding the conditions governing the use of the Platform and the processing of your personal data.