Skip to main content
A payout Autoramp gives your customer a liquidation address: a deposit address that accepts stablecoins and pays the proceeds out as fiat to a bank account you registered. The dashboard calls it an Offramp, and the API calls it an Autoramp with kind: Offramp. See Autoramp for how Autoramps work in general. Examples:
  • An address that turns incoming USDC on Base into EUR and pays it to a German IBAN
  • An address that turns incoming USDC on Solana into USD and pays it to a US account over ACH
  • An address that pays a supplier’s bank account abroad over SWIFT

How it works

1

Register the bank account

Register the account that receives the fiat with POST /api/addresses/fiat, or POST /api/addresses/pix for BRL. Wait until it’s Registered.
2

Create the payout Autoramp

POST /api/autoramps with a stablecoin source, a fiat destination, and the registered account as recipient_account.
3

Share the deposit address

Once the Autoramp is Approved, deposit_rails holds the deposit address. Show it to your customer with the tokens and chains the Autoramp accepts.
4

Stablecoins arrive, fiat goes out

Each deposit is converted and paid out to the bank account. The address stays live, so your customer can send to it again at any time.

Coverage

Which rails a specific customer can use depends on their onboarding. Read abilities.fiat_payout from GET /api/customers/{customer_id}/abilities before you register an account. For example, abilities.fiat_payout.usd.swift_thirdparty tells you whether the customer can pay a third party over SWIFT. See Ability Status. RTP is listed in the abilities response, but no provider supports RTP payouts, so it’s never Active in production. Sandbox reports it as Active. EUR and GBP have no SWIFT payouts.

Standing Autoramp or exact-out quote

Most payout integrations start with an exact-out quote, because the payer usually owes a precise fiat amount. A quote-based Autoramp keeps accepting new quotes over time, so one deposit address can pay many invoices.

Before you create a payout Autoramp

1

The customer is Active

The customer’s status is Active: terms signed, identification approved, and nothing outstanding in GET /api/customers/{customer_id}/required-signings. Otherwise POST /api/autoramps returns 403 with "Customer is not active". See Onboarding.
2

The rail is Active for this customer

An Active customer can still be waiting on a specific rail. Read GET /api/customers/{customer_id}/abilities and create the Autoramp only once its rail reads Active. A rail that isn’t Active yet returns 422 with "Customer is unable to complete the action. Consult the customer abilities API". Subscribe to the customer_fiat_abilities webhook instead of polling. See Ability Status.
3

The recipient is registered

Register the wallet or bank account that receives the converted funds before you create the Autoramp, and pass the same details in recipient_account:
  • Wallet: see Crypto Addresses. An unknown wallet returns 400 with "Recipient wallet not verified for customer".
  • Bank account: see Fiat Addresses. It must reach Registered. An account that isn’t registered yet returns 400 with "recipient fiat account not verified".

Bank account registration

A bank account starts in RegistrationPending and moves to Registered once a payout provider accepts it. Only Registered accounts work as a recipient_account.
  • Registered: ready for payouts
  • RegistrationPending: still registering. Some accounts register right away, others wait for the payee to be activated
  • RegistrationFailed: no provider accepted the account, or registration kept failing for more than 24 hours. Register a corrected account
ownership_verified on the account is true only for an IBAN that MoonPay Enterprise already holds on an internal verified list. It’s false for every other account, including every non-SEPA account, and doesn’t affect registration. Each status change fires the register_fiat_address_status webhook. Every currency page lists the exact fields and validation for its rail. See Fiat Addresses for listing and deleting accounts.

The sending wallet

Your customer doesn’t have to register the wallet they send stablecoins from, but registering it changes what happens to large deposits and returns:
  • Under €1,000: a deposit from a wallet you never registered passes the Travel Rule check automatically, if nothing else flags it
  • €1,000 or more: the deposit goes to AML review, unless the sending wallet is a self-hosted wallet you registered, or the sending institution’s Travel Rule data matches. See Travel Rule
  • Returns: a deposit MoonPay Enterprise can’t process goes back to the sender automatically only when the wallet was registered with a signature. See Verify a self-hosted crypto address. Otherwise the return waits for a manual review
Pass is_third_party=false when you request a quote for a payout. The quote’s is_third_party becomes the Autoramp’s source flag, and POST /api/autoramps rejects a third-party source on a payout with 400. Whether the bank account belongs to a third party is set on the registered account instead, with is_third_party in POST /api/addresses/fiat.

Payout with an exact-out quote

Use this when your customer owes a precise fiat amount. You ask for the output, and MoonPay Enterprise tells you the stablecoin input. Set these in your shell first. Every command on this page reuses them.
1

Request the quote

GET /api/autoramps/quoteSet amount_out to the fiat amount you need to land in the bank. Set amount_in instead to price a known stablecoin amount. Never set both. recipient_account_id is the ID of the registered bank account.
The fee object above is trimmed. See Fees and Invoices for every field.
amount_in is what your customer must send: 111.19863 USDC to receive exactly 100 EUR, with the fees itemized.
2

Create the Autoramp from the quote

POST /api/autorampsSubmit the signed quote payload verbatim. Set the payment reference, swift_purpose_code, and batch_payout on the quote request in step 1: they’re part of the signature, and adding them here returns 400 with "Invalid signature".
The quote is signed. Changing any value or leaving out any field makes the request fail with 400 and "Invalid signature". Create the Autoramp before the rate lock passes: an expired lock returns 400 with "Rate lock has expired".
3

Share the deposit address and amount

Once the Autoramp is Approved, deposit_rails contains the deposit address. Show your customer the address and the exact amount_in.A deposit matches a quote only when its amount and source currency equal the quote’s amount_in. A deposit that matches no active quote, or only an expired one, is returned under the sending wallet rules above.
POST /api/autoramps requires an Idempotency-Key header. A missing key returns 400. Only successful responses are cached, so a retry after an error runs again. See Idempotency.

Rate locks and expiry

rate_lock_duration_minutes is optional and is capped for the pair. A stablecoin to a different fiat currency (for example USDC to EUR) locks for up to 10 minutes. A stablecoin to its own currency (a USD stablecoin to USD, a EUR stablecoin to EUR) locks for up to 2 days. rate_expiry_policy decides what happens when funds arrive after the rate lock passes:
  • Return: the quote is valid only during the rate lock. Late funds are returned
  • Slippage: the quote stays valid until expiry_in_hours. Late funds are repriced at the current rate and execute if the rate moved less than slippage_tolerance_in_bips. Otherwise they’re returned
To pay another invoice from the same address, request a new quote with GET /api/autoramps/{autoramp_id}/quote and attach it. See Quotes.

Payout with a standing Autoramp

Use this when you want an address that converts whatever arrives, with no amount agreed up front.
recipient_account.account_identifier must match a bank account you registered for this customer, exactly as stored. Registration removes spaces from IBANs and dashes from sort codes, so send them that way, or copy the values from GET /api/addresses/fiat. Anything else returns 400 with "recipient fiat account not verified". The payment reference field depends on the rail: see the currency pages, and Autoramp for every request field.
201 Created
The response is trimmed. Poll GET /api/autoramps/{autoramp_id} or listen for register_autoramp_status until the Autoramp is Approved, then read the address from deposit_rails:

One address per chain family

deposit_rails shows a single deposit address. Every EVM chain on an Autoramp shares it, so one Autoramp can accept USDC on Ethereum, Base, and Arbitrum. To accept a non-EVM chain such as Solana, create a separate Autoramp for it. A deposit converts only when its token and chain are listed in source_currencies. A token sent on an EVM chain you didn’t declare isn’t converted, even though the address matches. Show your customer the exact tokens and chains the address accepts.

Errors

Client errors return a plain string body. A bank account that isn’t Registered for this customer returns 400:
400 Bad Request
That includes an account still in RegistrationPending. See Autoramp for the other common errors.

Batch payouts

Set batch_payout: true to pay out once a day instead of after every deposit. The Autoramp collects each day’s converted deposits and sends one transfer for the total. BRL Autoramps can’t batch, a batch payout Autoramp can’t be edited, and its fee profile can’t deduct a payout banking fee. See End of Day Settlement.

What can go wrong

Completed means MoonPay Enterprise handed the payout to the bank or rail. When the money reaches the recipient depends on the rail. See Settlement Times by Payment Method, and Trace a payout to give the recipient’s bank a reference.

Fees

Each payout reports its fees in the source stablecoin, with each fee either deducted from the payout or settled later on your invoice. Banking fees per rail come from the Autoramp’s fee profile. See Fees and Fees and Invoices.

Test the full flow in Sandbox

Creating the is half the integration. Simulate a deposit to confirm your webhook handler and reconciliation logic work before you take real money.
1

Simulate an incoming deposit

POST /api/sandbox/transaction builds a transaction directly from the route, reusing its currencies, customer, and recipient.
The response carries amount_in, amount_out, currency_in, currency_out, and state. See Sandbox for the optional fee, fx_rate, and initial_state fields.
On a quote-based Autoramp, set amount to the quote’s exact amount_in, as a real deposit must. Any other amount returns 400 because production would return that deposit. fee, fx_rate, and amount_out come from the quote and return 400 if you send them.
2

Drive the transaction to Completed

The simulated transaction starts in PendingPayin, which reads as ConversionInProgress in transaction_status. Advance it to trigger the rest of the status webhooks.
3

Check the webhooks you received

Creating the transaction sent a transaction event and a transaction_status event with ConversionInProgress. Advancing it sent a second transaction_status event with Completed. The sandbox writes the state you ask for straight onto the transaction, so it skips the intermediate PayoutInProgress status that a live deposit produces.If the customer has a pending EDD review, or the deposit takes the customer over the sandbox volume threshold, the transaction starts in FundsReviewInProgress instead. Approve the pending identification before you advance it.Read transaction_status, not the deprecated status field, for the current state. Payload shapes and the full status table are in Monitoring payments; signature verification is in Webhooks.

Simulate it in the Dashboard

Register the bank account first under My Address → Linked Bank Accounts in the App view. Sandbox registers it automatically. If it’s still listed under Developer → Sandbox → Fiat Accounts → Unverified Fiat Accounts, set it to Registered there. Until the account is registered, the payout Autoramp has nowhere to pay out.
You can run this same flow without writing a single API call. The Partner Dashboard covers every step, from creating the route to settling a simulated deposit.
1

Create the route

Switch the sidebar to the App view and pick your customer in the customer selector at the top. Open Operations → Routes, then click on the card and choose .
2

Authorize the route

Go to Developer → Sandbox and open the Autoramps tab. Your new route appears under Unverified Autoramps. Set its status to Authorized using the dropdown on the right.
The dropdown offers Created, Authorized, and Rejected. Pick Authorized: that provisions the mock deposit account, which is what the simulated deposit needs. Sending "Approved" to PUT /api/sandbox/autoramp/{id} provisions the same account and also moves the route to Approved, so use the API call if you want to see the Approved status your integration waits for.
3

Create the simulated deposit

Still under Developer → Sandbox, click New Transaction in the top right. On the Create New Sandbox Transaction screen:
  1. Customer: search by name, email, or ID and select the customer who owns the route.
  2. Ramp: pick it from the dropdown. This field still uses the older wording for a route. Entries are labelled by currency pair, for example .
  3. Amount: enter the deposit amount in the route’s input currency.
Click Execute Transaction. This bypasses the normal deposit flow and builds the transaction straight from the route configuration.
4

Settle the transaction

Back on the Sandbox page, open the Transactions tab. Your transaction is listed under Pending Transactions with Accept and Reject buttons. Choose Accept to complete it, or use the Change state dropdown to move it to a specific state and test how your integration reacts.
5

Check the result

Open the transaction from Operations → Transactions to see amounts, fees, and . Webhooks fire exactly as they do on the API path, so this is a good way to exercise your endpoint before you write any integration code.
Use Reset on the Sandbox page to clear all customers, wallets, fiat accounts, transactions, and autoramps and start from a clean state.

Move to production

Remove every /api/sandbox/* call from your integration. Those endpoints don’t exist in production.

Payouts by currency

USD

ACH, Wire, FedNow, and SWIFT

EUR

SEPA to any IBAN in the SEPA zone

GBP

Faster Payments and CHAPS

BRL

PIX by key or bank details