Skip to main content
MoonPay provides a test mode for integration development and testing. Test mode uses testnet blockchains and simulated payments. No real assets are transferred.

Enabling test mode

Test mode is determined by the API key you use when creating a session. Use your test API key (sk_test_...) to enable test mode. Use your live API key (sk_live_...) for production. You can find your API keys on the Developers page in your MoonPay dashboard.
All frames and SDK methods automatically operate in test mode when initialized with a session token created using test API keys.

Test accounts

When creating test accounts:
  • MoonPay simulates KYC verification - it does not verify documents. To force a specific approve or reject outcome, see First names (KYC outcome)
  • Use a US or UK address for test accounts, as these work best with test payment cards
  • You can skip document submission by clicking “Skip document submission” if prompted

Test data

Test mode reserves a set of test values that produce deterministic outcomes. Use them to run the full sign-up and verification journey without a real inbox, a real phone, or a real identity check. Test email addresses and test first names are case-insensitive. None of these values work in live mode:
  • Test email addresses are rejected with a 400 error.
  • Test first names are treated as ordinary names, and a real identity check runs.
  • Test phone numbers are not simulated. MoonPay passes them to its SMS provider, which does not support them for verification, so verification fails. Use a real number in live mode.

Email addresses

Sign in with a MoonPay test email address of the form test-<label>@moonpay.test, where <label> is any combination of letters, numbers, hyphens, and underscores. For example, test-signup-flow@moonpay.test. Every test address verifies with the code 123456. MoonPay sends no email to these addresses. Each unique address creates a separate customer, so you can generate as many test customers as you need. As with real addresses, you cannot reuse one address across two customers. To exercise real email delivery instead, use an inbox you can access. MoonPay sends a one-time passcode (OTP) to the address for login verification.

Phone numbers

Verify with MoonPay’s reserved test phone numbers. These are not real phone numbers, and MoonPay sends no SMS to them. Every test number follows the format +1500555000X, where the final digit selects the outcome.

Verification succeeds

All three verify with the code 123456.

MoonPay rejects the number

MoonPay rejects these wherever it validates a phone number. On PATCH /platform/v1/customers/{id}/kyc, the request fails with 400 and an invalid_request error on the phoneNumber.number field, carrying the message below. Only mobile numbers are accepted, so the first three share one error message. Use the specific test number to control which case you are exercising.

The OTP send fails

These only occur in the OTP flow. The Customer API does not send an OTP. Simulated send failures do not block the number or the customer. Every attempt with one of these numbers returns the same error. You can retry right away, or switch the same customer to a success number.
A real phone number belongs to one customer at a time, so verifying it on a new customer removes it from the previous one. Test numbers are exempt: any number of test customers can hold the same test number at once.

First names (KYC outcome)

Set the customer’s first name to a test value when completing identity verification. MoonPay returns the outcome you specify instead of running a real identity check. With the Customer API, submit it in the basicDetails requirement on PATCH /platform/v1/customers/{id}/kyc:
MoonPay simulates only the verification outcome. Everything else behaves normally, including webhooks, analytics, and transaction gating. Test-Approve also approves any submitted documents and any pending SSN check. Test-Reject rejects the session. Test first names work for both Express Checkout and full KYC sessions.

SSN (US residents)

Enter any 9-digit value. Test mode does not verify SSN values. The format is enforced in both modes: submit nine digits with no hyphens or spaces. Any other length, or a value containing -, fails with a 400 and an invalid_request error on taxIdentifiers.value.
Do not use your real Social Security number. Use a fake value like 123456789.

Test payment cards

Use the following test cards to simulate payments. Do not enter real payment card information. Use any valid 3-digit CVV and any future expiration date.

US customers

UK customers

EU customers

3D Secure test cards

3D Secure (3DS) is an additional verification step the customer’s bank may require during a card payment. The cards below trigger deterministic 3DS outcomes so you can test your challenge handling end to end.
  • Frictionless outcomes complete without any customer interaction.
  • Challenge outcomes render a 3DS challenge frame the customer must complete or cancel.
When a card triggers a 3DS challenge, the simulator prompts for a password. Enter Checkout1! to complete the challenge.

Frictionless

Challenge

Declined transactions

Use these cards to test error handling for different failure scenarios.

Apple Pay

In test mode, the Apple Pay frame renders a mock Apple Pay button instead of the native Apple Pay UI. When a customer taps the mock button, a browser confirmation dialog (window.confirm) appears in place of the Apple Pay payment sheet:
  • Ok simulates a successful transaction.
  • Cancel simulates a failed transaction.
This lets you test the full Apple Pay flow without a real Apple Pay account or Safari-specific setup.
If you embed the Apple Pay frame in an iframe with a sandbox attribute, include allow-modals in the sandbox value. This allows window.confirm to work cross-origin inside the frame. See the Apple Pay frame reference for details.

Google Pay

In test mode, the Google Pay frame renders a mock Google Pay button instead of the native Google Pay sheet. When a customer taps the mock button, a browser prompt (window.prompt) appears in place of the Google Pay payment sheet:
  • OK authorizes the payment using the billing address in the prompt.
  • Cancel declines the payment.
The prompt is pre-filled with a US billing address you can edit as JSON before confirming:
Keep phoneNumber in E.164 format (for example +14155551234). Invalid JSON in the prompt falls back to this default address. This lets you test the full Google Pay frame flow without a Google Pay account or the native payment sheet. The mock applies only when the frame uses this prompt. MoonPay treats the resulting token as a test-mode mock (authorized or declined). A real Google Pay payment token in test mode still goes to the sandbox payment processor.
If you embed the Google Pay frame in an iframe with a sandbox attribute, include allow-modals in the sandbox value. This allows window.prompt to work cross-origin inside the frame. See the Google Pay frame reference for details.

Triggering challenges

In test mode, you can force a challenge by setting the buy amount to a specific value. This lets you test how your integration renders and resolves a challenge without reproducing the real-world conditions that normally trigger one. The amount must match exactly. For example, a quote for 49 triggers the CVV challenge, but 49.01 does not. These triggers only apply in test mode and have no effect with a live API key.
Challenges are surfaced by a challenge event that points to the challenge frame. See Handle challenges for how to render and resolve one.

Bank transfers

Bank-transfer buy transactions (sepa for EUR) settle asynchronously. In production, the transaction settles when the customer’s deposit arrives and is confirmed. That confirmation never happens in test mode, so a pending bank-transfer transaction cannot complete on its own without sending real money. Use the simulate bank-transfer settlement endpoint to drive a bank-transfer transaction to a terminal state without real funds.

Prerequisites

  • The transaction is a bank transfer with paymentMethod.type set to sepa and is in pending.
  • The request uses the access token of the transaction’s own customer. Another customer’s transaction returns 404.
  • Test mode only. A live-mode transaction returns 403.
Open-banking bank transfers settle through a different flow and are not supported by the simulator.

Outcomes

Set the required outcome field to one of the following:

Poll for the terminal state

Settlement is asynchronous, so the response reflects the transaction’s current state rather than its terminal state. Poll getTransaction or GET /platform/v1/transactions/{id} for the outcome. The timeout outcome is immediate; settled completes after the simulated deposit is processed.

Model a specific sender (optional)

The simulator synthesizes sender bank details per the transaction’s currency. To model a specific incoming deposit, pass a senderBankAccount object with an accountHolderName and the account identifiers for the currency:
  • sepa (EUR): provide an iban.
Simulate a settled SEPA deposit
See the simulate bank-transfer settlement reference for the full request and response shape.

Test assets

Test mode supports the following assets and testnets:
This table helps you plan your integration; it is not a contract. The set of assets available in test mode shifts over time.
Test-mode purchases deliver 1/100th of the quoted amount because MoonPay holds limited testnet funds. A purchase quoted at 0.1 ETH delivers 0.001 ETH to your test wallet. Quote requests for assets that aren’t available in test mode fail with a 400 invalid_request error. Use an asset such as SOL or ETH when testing.

Troubleshooting

Common errors