- Freelancers in emerging markets receiving USD or EUR payments
- Banking apps issuing multi-currency accounts
- Crypto/DeFi wallets offering named accounts with local payment rails
autoramp, the standing rule that says which stablecoin the incoming fiat becomes and which wallet receives it. Examples:
- A vIBAN which turns EUR into USDC on Solana address 1
- A vIBAN which turns EUR into USDC on Arbitrum address 1
- A vIBAN which turns EUR into EURC on Arbitrum address 2
Named accounts
Each virtual account is issued in the user’s own name, not a pooled or generic account. Incoming payments clear faster, pass compliance checks more reliably, and feel like a real bank account to the sender. Example: a USD account issued for Jane DoeHow it works
autoramp which turns EUR into USDC on Solana address 3DkN…BV4LmKey concepts
Virtual accounts are payment routing targets, not holding accounts. They’re designed for efficient payment ingestion and reconciliation.- Payment routing only: virtual accounts don’t hold funds. Every received payment is immediately processed per your configured autoramp settings.
- Open to any sender: the account works like a normal bank account. Anyone can send fiat to it using the account credentials. No sender pre-approval is required.
- Named to your customer: each account is issued in the customer’s verified name, so incoming payments clear faster and pass compliance checks more reliably.
- Automatic returns: payments that fail compliance checks or arrive with incorrect details are returned to the sender.
Prerequisites
Every step must complete before moving to the next. Sandbox-only steps are marked. Set these in your shell first. Every command on this page reuses them.Customer is Active
Active status: terms signed and identification (KYC/KYB) approved, with nothing outstanding in required-signings. Active alone is not always enough — check that the specific rail you need is Active in the customer’s abilities too.Expand the walkthrough below if you have not onboarded a customer yet.Register the recipient wallet address
recipient_account must match an address you have already registered for this customer.(Optional) Get a quote
GET /api/autoramps/quote. See Quotes below. Otherwise, the onramp executes at the current mid-market rate.Create the onramp autoramp
POST /api/autoramps using the registered wallet address as the recipient. See the implementation example below.Sandbox: approve the autoramp
Authorized status. In Sandbox you advance it yourself, which also provisions the mock deposit account that a simulated deposit needs:Approved on its own once its deposit account is provisioned and verified.Onboard a customer from scratch
Full onboarding walkthrough (Sandbox)
Full onboarding walkthrough (Sandbox)
- A Sandbox API key from the Partner Dashboard
- An Ethereum wallet with signing capability (e.g. ethers.js, viem, or a similar library), required to sign a proof-of-ownership message
Create a customer
POST /api/customersCreate a customer record with customer_type set to Person (individual) or Business (company). Sending X-API-Version: 2026-08-01 starts the customer in SigningsRequired, so the terms step comes first; without it the customer starts in IdentificationRequired. See API Versions.id. You need it in every subsequent step.Present and sign the terms and conditions
GET /api/customers/{id}/required-signingsFetch and present the terms, then record acceptance via POST /api/customers/{id}/signings. The terms contain the data sharing agreement, so your customer must accept them before MoonPay Enterprise collects KYC data. See Terms and Conditions.GET /api/terms-and-conditions?country={ISO3} returns the same document and is the endpoint to use before a customer record exists. country is required there but no longer affects which document you get back.url from the terms response to your customer for review. The signing request takes content_id (the id from the terms response) and signed: true.Create a Link identification
POST /api/customers/{id}/identifications/v2Create an identification with type: "Link". MoonPay Enterprise returns a URL where your customer completes KYC (individuals) or KYB (businesses) through the hosted verification interface.url to your customer to complete verification. Save the identification id.Approve the identification (Sandbox only)
POST /api/sandbox/identification/{id}In Sandbox, you control whether an identification is approved or rejected.Confirm the customer is Active
GET /api/customers/{id}/required-signingsCheck the customer status after approval. Having signed the terms earlier, it should be Active — nothing is outstanding and you can move on.If the status is SigningsRequired instead, documents are waiting: call required-signings, present each returned document, and mark each as signed. The customer becomes Active once none are left. 2026-08-01 and later return 200 with an empty list when nothing is outstanding; earlier versions return 409 Conflict.SigningsRequired whenever MoonPay Enterprise publishes a new document, and cannot transact until they sign it. See Signing new terms later.Register a crypto address
POST /api/addresses/crypto/selfhostedRegister the wallet where stablecoins will be delivered. Required for Travel Rule compliance before creating any autoramp.Implementation
Create an autoramp that converts EUR to USDC on Ethereum.mp CLI creates one against your own account: mp virtual-account onramp create --fiat EUR --stablecoin USDC --wallet <registered-wallet-address>. See CLI. The API flow below is the one to integrate when you are onramping on behalf of your customers.POST /api/autoramps requires an Idempotency-Key header. Send the same key to safely retry a request without creating a duplicate autoramp.Request
$AUTORAMP_ID lets you paste the remaining commands on this page straight into the same shell.
Response
deposit_rails is empty at Authorized. Poll GET /api/autoramps/{id} or subscribe to webhooks until status = Approved before sharing deposit details with end users. See Autoramp Status.Deposit rails
Once the autoramp reachesApproved, the response includes the virtual account under deposit_rails. Display these to your customer so they (or third parties) can send fiat payments.
type. A EUR account is SEPA, a USD account is one of ACH, Wire, RTP, or FedNow, and a GBP account is CHAPS or FPS. SWIFT, Pix, Spei, MobileMoney, AfricanBankTransfer, and Crypto cover the remaining rails. Fields differ per type; a SEPA rail carries:
deposit_rails array contains the payment details. The legacy deposit_account field is deprecated.Error response
Validation failures return the error as a plain string body, not a structured object. Arecipient_account that does not match a wallet address you’ve already registered via Crypto Addresses returns 400:
422 covers the cases where the request is well formed but the customer cannot complete the action yet, for example "Customer is unable to complete the action. Consult the customer abilities API", which points you at GET /api/customers/{id}/abilities (see Onboarding).
Lock a rate with a quote
By default an onramp executes at the current mid-market rate. Request a quote first if you need a locked rate. Pegged pairs (EUR to a EUR-stablecoin, USD to a USD-stablecoin) can lock for up to 2 days. Cross-currency pairs such as EUR to USDC lock for up to 10 minutes.POST /api/autoramps to create a quote-source autoramp. Quote-source autoramps can keep accepting new quotes over time via POST /api/autoramps/{autoramp_id}/quotes; standalone autoramps created without an initial quote cannot.
See Quotes for rate lock caps, expiry policies, and multi-currency input.
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.Simulate an incoming deposit
POST /api/sandbox/transaction builds a transaction directly from the route, reusing its currencies, customer, and recipient. amount_in, amount_out, currency_in, currency_out, and state. See Sandbox for the optional fee, fx_rate, and initial_state fields.Drive the transaction to Completed
Pending. Advance it to trigger the rest of the status webhooks.Check the webhooks you received
transaction event when the deposit landed, followed by transaction_status events as it moved through FundsReviewInProgress, ConversionInProgress, PayoutInProgress, and Completed.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
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.Create the route
Authorize the route
"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.Create the simulated deposit
- Customer: search by name, email, or ID and select the customer who owns the route.
- Ramp: pick it from the dropdown. This field still uses the older wording for a route. Entries are labelled by currency pair, for example .
- Amount: enter the deposit amount in the route’s input currency.
Settle the transaction
Check the result
Move to production
/api/sandbox/* call from your integration. Those endpoints do not exist in production.
Monitoring payments
Webhooks are the recommended way to track incoming payments. Without them, you would need to poll the API for transaction updates.Setup
Register a webhook endpoint in the Partner Dashboard under Developer → Webhooks, or use the Webhooks API. Subscribe to at least theTransaction and TransactionStatus topics. Topic names are PascalCase; the type on a delivered event is the snake_case form (transaction, transaction_status).
Relevant events
When a payment arrives at a virtual account, MoonPay Enterprise fires the following events in order:transaction event tells you a payment arrived. The transaction_status events tell you where it is in the conversion pipeline.
Example: transaction received
When fiat lands on the vIBAN, you receive atransaction event with the customer_id and a transaction id you can use to query details:
Example: transaction status update
As the payment moves through conversion and payout, you receivetransaction_status events. Use transaction_status (not the deprecated status field) for the current state:
transaction_status becomes Completed and transaction_hash contains the on-chain transaction hash.
Transaction status reference
200 OK to acknowledge receipt. Non-2xx responses trigger retries with exponential backoff. See Webhooks for signature verification and full implementation details.