> ## Documentation Index
> Fetch the complete documentation index at: https://dev.enterprise.moonpay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox

> Test your MoonPay Enterprise integration against api.sandbox.iron.xyz. Covers sandbox access, differences from production, and simulating transactions.

## Sandbox Location

* **Partner Dashboard:** [https://app.sandbox.iron.xyz](https://app.sandbox.iron.xyz)
* Please reach out to request access to your sandbox environment.

## Differences to Production

The Sandbox is optimized to test and integrate the MoonPay Enterprise APIs. Therefore, it has multiple differences compared to the production system in order to make it easy to work with.

* In production, only an administrator can create an API Key (and then give it to an engineer with an Editor role). In the sandbox, an Editor can also create API Keys to make it easy to test.
* In the sandbox, fiat and crypto flows are simulated. Neither real IBANs nor testnet crypto is used. Instead, we offer a [Sandbox API](/reference/sandbox/mock-a-transaction) to create mock incoming fiat or crypto transactions.
* Any accept/reject flow can be controlled by the user. Instead of going through an email flow, there's a convenient control center where the engineer can decide whether to accept or reject customer fiat accounts, Autoramps, etc.
* The sandbox offers a Reset function to remove all data and start from a pristine state.
* The sandbox has additional `/sandbox` APIs to fully control all the above features. See [Sandbox API](#sandbox-api) below.

## Managing the Sandbox

You can manage the Sandbox in the **Sandbox** area of the [Partner Dashboard](/partner-dashboard).

<Steps>
  <Step>
    Log in to the Partner Dashboard.
  </Step>

  <Step>
    Navigate to **Developer → Sandbox**.
  </Step>
</Steps>

<Frame caption="The Sandbox page, with New Transaction and Reset Sandbox in the header.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-register-fiat-account/01-unverified-fiat-accounts.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=788ff55641fea9a70cbc7b751f43d594" alt="Sandbox page on the Fiat Accounts tab, listing one unverified account, with New Transaction and Reset Sandbox buttons in the header" width="1600" height="1000" data-path="images/clips/sandbox-register-fiat-account/01-unverified-fiat-accounts.png" />
</Frame>

## Sandbox Operations

The Sandbox page is organised into **Fiat Accounts**, **Autoramps**, **Customers**, and **Transactions** tabs, with **New Transaction** and **Reset Sandbox** in the top right.

Each tab lists one status, so a row leaves its tab as soon as you act on it. An empty tab means nothing is waiting on you.

| Tab | Lists | What you can do |
| - | - | - |
| Fiat Accounts | Fiat accounts in `RegistrationPending` | Register the account |
| Autoramps | Autoramps in `Created` | Set `Created`, `Authorized`, or `Rejected` |
| Customers | Customers in `IdentificationRequired` or `SigningsRequired` | Create an identification, set its status, sign terms |
| Transactions | Transactions in `FundsReviewInProgress` | Accept, reject, or set a specific state |

### Manage Pending Fiat Accounts

When a sandbox customer registers a new fiat account, it appears under **Unverified Fiat Accounts** on the **Fiat Accounts** tab. Open the status dropdown on the row and pick **Registered**. The account then leaves the tab, because the tab only lists accounts in `RegistrationPending`.

<Frame caption="The status dropdown on an unverified fiat account.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-register-fiat-account/02-status-options.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=2fb881d8f88eaa32a9885dd16479ba69" alt="Status dropdown open on an unverified fiat account, listing AuthorizationRequired, AuthorizationFailed, RegistrationPending, RegistrationFailed and Registered" width="1600" height="1000" data-path="images/clips/sandbox-register-fiat-account/02-status-options.png" />
</Frame>

<Note>
  The dashboard sends `Registered` for every option in this dropdown. To move an account to a failure status, call [`PUT /api/sandbox/fiat-verification/{id}`](#update-fiat-address-registration-status) with the status you want.
</Note>

### Manage Pending Autoramps

When a sandbox customer creates a new Autoramp, it appears under **Unverified Autoramps** on the **Autoramps** tab. The status dropdown offers **Created**, **Authorized**, and **Rejected**.

<Frame caption="The status dropdown on an unverified Autoramp.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-authorize-autoramp/02-status-options.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=431975bd4b4053eae1b1a2747bf7d7d5" alt="Status dropdown open on an unverified autoramp row, offering Created, Authorized and Rejected" width="1600" height="1000" data-path="images/clips/sandbox-authorize-autoramp/02-status-options.png" />
</Frame>

<Note>
  Choose **Authorized** to provision the mock deposit account, which is what a simulated deposit needs. Sending `"Approved"` to `PUT /api/sandbox/autoramp/{id}` provisions the same account and also moves the autoramp to `Approved`, so use the API call if you want to see the `Approved` status your integration waits for.
</Note>

### Drive a Customer Through Onboarding

The **Customers** tab lists every customer with a `status` of `IdentificationRequired` or `SigningsRequired`, alongside the `identification_status` of their latest identification. Only customers of the partner selected at the top of the page are listed, since the sandbox actions run against one partner at a time.

<Frame caption="The Customers tab. Each row offers the action its own state needs.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-onboarding-3-approve-identification/01-identification-pending.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=a100ab546b4e64793860c145477081cc" alt="Sandbox Customers tab listing customers with their status, identification status, and either an Update Status dropdown or a Create Identification button" width="1600" height="1000" data-path="images/clips/sandbox-onboarding-3-approve-identification/01-identification-pending.png" />
</Frame>

Each row offers the action its current state needs:

| Row state | Action |
| - | - |
| No identification yet | **Create Identification** starts KYC with a link-type identification, the same call as [Create Customer Identification V2](/reference/customer/create-customer-identification-v2) |
| Identification exists | The **Update Status** dropdown sets the identification to any status, the UI equivalent of [`POST /api/sandbox/identification/{id}/status`](#set-identification-status) |
| `SigningsRequired` | **Sign terms** signs every outstanding terms document for that customer |

The dropdown reaches `Pending`, `Processed`, `PendingReview`, `Approved`, `Declined`, `Expired`, and `Archived`. The sandbox ignores the normal transition rules, so you can jump straight to the status you want to test instead of walking the whole flow. In production, the MoonPay Enterprise compliance team drives these transitions.

**Status guide** in the tab header opens the status combinations and what to show for each one. It is the same mapping as [Mapping Onboarding Statuses in Your App](/onboarding#mapping-onboarding-statuses-in-your-app).

<Frame caption="Status guide: every status combination and what to show for it.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-onboarding-4-status-guide/01-status-mapping-guide.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=695f6914115ff35f8e52d65be5478c01" alt="Status guide dialog mapping customer status and identification status to the screen your app should show" width="1280" height="800" data-path="images/clips/sandbox-onboarding-4-status-guide/01-status-mapping-guide.png" />
</Frame>

### Create a Transaction

**New Transaction** opens the **Create New Sandbox Transaction** screen, the UI equivalent of [`POST /api/sandbox/transaction`](#create-a-sandbox-transaction). Select a **Customer**, pick a **Ramp** from that customer's autoramps, enter an **Amount** in the ramp's input currency, then click **Execute Transaction**.

<Frame caption="Create New Sandbox Transaction. The Customer field defaults to your newest customer and is searchable.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-create-transaction/01-transaction-parameters.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=a773f167587aa991e1ac1a740360a159" alt="Create New Sandbox Transaction form with Customer, Ramp and Amount fields and an Execute Transaction button" width="1600" height="1000" data-path="images/clips/sandbox-create-transaction/01-transaction-parameters.png" />
</Frame>

The **Amount** field stays disabled until you pick a ramp, and its label then shows the ramp's input currency.

This bypasses the normal deposit flow and builds the transaction directly from the autoramp configuration. It does not use testnet funds.

Executing returns you to the Sandbox page on the **Fiat Accounts** tab. The new transaction starts in `PendingPayin`, so it does not appear on the **Transactions** tab, which lists only `FundsReviewInProgress`. To settle it, call [`PUT /api/sandbox/transaction/{id}/state`](#update-sandbox-transaction-state).

### Settle a Transaction

Pending transactions are listed under **Pending Transactions** on the **Transactions** tab, with **Accept** and **Reject** buttons and a state dropdown for moving a transaction to a specific state. **Accept** sets `Completed` and **Reject** sets `Failed`. All three controls call [`PUT /api/sandbox/transaction/{id}/state`](#update-sandbox-transaction-state).

<Frame caption="Pending Transactions, with Accept, Reject and the state dropdown.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-settle-transaction/01-pending-transactions.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=660a390070ff889cdb4d88adeb55b509" alt="Pending Transactions table listing a transaction in FundsReviewInProgress with Accept, Reject and a state dropdown" width="1600" height="1000" data-path="images/clips/sandbox-settle-transaction/01-pending-transactions.png" />
</Frame>

### Reset Sandbox

**Reset Sandbox** removes all customers, wallets, fiat accounts, transactions, and Autoramps. It asks you to confirm first, and it cannot be undone.

<Frame caption="Reset Sandbox lists what it deletes before you confirm.">
  <img src="https://mintcdn.com/moonpayiron/sUF2AMT2dLNIqek1/images/clips/sandbox-reset/02-reset-confirmation.png?fit=max&auto=format&n=sUF2AMT2dLNIqek1&q=85&s=2125aadaf81c5ed540d09ff79a397b12" alt="Reset Sandbox confirmation dialog warning that customers, wallets, fiat accounts, transactions and autoramps will be deleted" width="1600" height="1000" data-path="images/clips/sandbox-reset/02-reset-confirmation.png" />
</Frame>

<Note>
  The tables do not clear themselves after a reset. Reload the page to see the empty tabs.
</Note>

## Sandbox API Key

<Note>
  The Sandbox APIs require an API Key just like the rest.
</Note>

You can create a sandbox API key in your dashboard: [https://app.sandbox.iron.xyz/dashboard/keys](https://app.sandbox.iron.xyz/dashboard/keys)

<CodeGroup>
  ```bash theme={null}
  curl -X POST https://api.sandbox.iron.xyz/api/sandbox/reset \
    -H "X-API-Key: YOUR-API-KEY" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)"
  ```
</CodeGroup>

<Note>
  Replace `YOUR-API-KEY` with the actual API key you generated. The `X-API-Key` header is required for every request. API Base URL: [https://api.sandbox.iron.xyz](https://api.sandbox.iron.xyz)
</Note>

## Sandbox API

The sandbox offers additional APIs that do not exist in production, grouped under **Sandbox** in the [API reference](/reference/sandbox/mock-a-transaction). They let you create mock transactions, control approval flows, and reset your environment.

<Note>
  All paths below are relative to the API base URL: `https://api.sandbox.iron.xyz`
</Note>

### Create a Sandbox Transaction

`POST` `/api/sandbox/transaction`

Creates a transaction directly from an autoramp configuration. This bypasses the normal deposit flow and creates a ramp transaction with the specified amount using the autoramp's currencies, customer, and recipient.

| Field | Required | Description |
| - | - | - |
| `autoramp_id` | Yes | The autoramp UUID to create the transaction against |
| `amount` | Yes | Deposit amount in the autoramp's input currency (decimal string) |
| `amount_out` | No | Output amount. If omitted, calculated from `amount`, `fee`, and `fx_rate` |
| `fee` | No | Fee amount (defaults to 0.25% of `amount`) |
| `fx_rate` | No | Exchange rate. If omitted, the live mid-market rate for the currency pair is used |
| `initial_state` | No | Starting state: `Pending`, `Completed`, or `Failed` |
| `input_currency` | No | Override the input currency (Fiat or Crypto object) |
| `source` | No | Override the transaction source (bank account or wallet) |
| `transaction_id` | No | Deterministic transaction UUID instead of auto-generated |
| `deposit_id` | No | Deterministic deposit UUID instead of auto-generated |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X POST "https://api.sandbox.iron.xyz/api/sandbox/transaction" \
    -H "Content-Type: application/json" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)" \
    -H "X-API-Key: $API_KEY" \
    -d '{
      "autoramp_id": "d3c2b1a4-e5f6-78a9-0123-fedcba654321",
      "amount": "100"
    }'
  ```
</CodeGroup>

**Example response:**

The response `state` is the internal transaction state, for example `PendingPayin`, not the `Pending`, `Completed`, or `Failed` value you send in `initial_state`.

<CodeGroup>
  ```json JSON theme={null}
  {
    "id": "7d834f68-cea8-496a-8eae-bb0772365028",
    "autoramp_id": "d3c2b1a4-e5f6-78a9-0123-fedcba654321",
    "amount_in": "100",
    "currency_in": "EUR",
    "amount_out": "99.75",
    "currency_out": "EURC",
    "customer_id": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
    "state": "PendingPayin",
    "created_at": "2026-01-15T10:30:00Z"
  }
  ```
</CodeGroup>

### Update Sandbox Transaction State

`PUT` `/api/sandbox/transaction/{id}/state`

Transition a sandbox transaction to a different state for testing purposes.

| Field | Required | Description |
| - | - | - |
| `state` | Yes | Target state: `Pending`, `Completed`, or `Failed` |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X PUT "https://api.sandbox.iron.xyz/api/sandbox/transaction/<transaction_id>/state" \
    -H "Content-Type: application/json" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)" \
    -H "X-API-Key: $API_KEY" \
    -d '{ "state": "Completed" }'
  ```
</CodeGroup>

### Set Identification Status

`POST` `/api/sandbox/identification/{id}/status`

Set a customer's identification to any status, bypassing the normal transition rules, so you can rehearse every branch of your onboarding UI. In production, MoonPay Enterprise's compliance team drives these transitions.

| Field | Required | Description |
| - | - | - |
| `status` | Yes | Target status: `Pending`, `Processed`, `PendingReview`, `Approved`, `Declined`, `Expired`, or `Archived` |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X POST "https://api.sandbox.iron.xyz/api/sandbox/identification/<identification_id>/status" \
    -H "Content-Type: application/json" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)" \
    -H "X-API-Key: $API_KEY" \
    -d '{ "status": "Approved" }'
  ```
</CodeGroup>

The identification must belong to a customer of the partner the API key resolves to. Otherwise the call returns 404:

<CodeGroup>
  ```json JSON theme={null}
  "Identification belongs to another partner's customer. Select that partner and retry."
  ```
</CodeGroup>

### Update Identification Status (deprecated)

`POST` `/api/sandbox/identification/{id}`

Approve or reject a pending customer identification. Use [Set Identification Status](#set-identification-status) instead: it reaches every status, not just approved and rejected.

| Field | Required | Description |
| - | - | - |
| `approved` | Yes | `true` to approve, `false` to reject |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X POST "https://api.sandbox.iron.xyz/api/sandbox/identification/<identification_id>" \
    -H "Content-Type: application/json" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)" \
    -H "X-API-Key: $API_KEY" \
    -d '{ "approved": true }'
  ```
</CodeGroup>

### Update Fiat Address Registration Status

`PUT` `/api/sandbox/fiat-verification/{id}`

Set the registration status of a fiat address. The request body is a plain JSON string (one of the enum values below).

| Status | Description |
| - | - |
| `RegistrationPending` | Registration is being processed |
| `Registered` | Account is active and ready for payouts |
| `RegistrationFailed` | Registration failed |
| `AuthorizationRequired` | Additional authorization needed |
| `AuthorizationFailed` | Authorization was rejected |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X PUT "https://api.sandbox.iron.xyz/api/sandbox/fiat-verification/<fiat_address_id>" \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $API_KEY" \
    -d '"Registered"'
  ```
</CodeGroup>

### Update Autoramp Status

`PUT` `/api/sandbox/autoramp/{id}`

Set the status of an autoramp. The request body is a plain JSON string (one of the enum values below).

| Status | Description |
| - | - |
| `Created` | Initial state |
| `EditPending` | Edit is being processed |
| `Authorized` | Authorized by the system |
| `DepositAccountAdded` | Deposit account has been provisioned |
| `Approved` | Fully approved and ready to process transactions |
| `Rejected` | Rejected |
| `Cancelled` | Cancelled |

<CodeGroup>
  ```bash Bash theme={null}
  curl -X PUT "https://api.sandbox.iron.xyz/api/sandbox/autoramp/<autoramp_id>" \
    -H "Content-Type: application/json" \
    -H "X-API-Key: $API_KEY" \
    -d '"Approved"'
  ```
</CodeGroup>

### Reset the Sandbox

`POST` `/api/sandbox/reset`

Deletes all customers, wallets, fiat accounts, transactions, and autoramps. Requires an `IDEMPOTENCY-KEY` header.

<CodeGroup>
  ```bash Bash theme={null}
  curl -X POST "https://api.sandbox.iron.xyz/api/sandbox/reset" \
    -H "IDEMPOTENCY-KEY: $(uuidgen)" \
    -H "X-API-Key: $API_KEY"
  ```
</CodeGroup>
