> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rebelfi.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox Testing

> Test the full ramp lifecycle — KYB, on-ramp, and off-ramp — without moving real money

Test the full ramp lifecycle in sandbox without moving real money or crypto. Sandbox uses the same API endpoints and SDK methods as production — the only sandbox-specific calls are `simulate-*` endpoints that trigger transaction lifecycle progression.

## What's Real vs. Simulated

| Operation               | Sandbox Behavior                                                           |
| ----------------------- | -------------------------------------------------------------------------- |
| KYB start               | Real KYB customer created in sandbox                                       |
| KYB approve/reject      | Simulated — instant approval or rejection                                  |
| Create on-ramp account  | Real provisioning — returns real-looking bank details                      |
| Create off-ramp account | Real provisioning — returns real crypto deposit address                    |
| Create recipient        | Real provisioning — returns real recipient ID                              |
| Simulate transaction    | Simulated locally — creates DB record, progresses statuses, fires webhooks |
| List/get transactions   | Real queries against sandbox DB                                            |
| Webhook delivery        | Real webhooks to your configured URL                                       |
| Actual bank transfer    | Does not happen                                                            |
| Actual crypto transfer  | Does not happen                                                            |

## Prerequisites

* Sandbox API key (`rfk_sandbox_*`) — see [Sandbox Environment](/guides/sandbox)
* Webhook endpoint configured in dashboard (or use [webhook.site](https://webhook.site) for testing)

## Step 1: KYB Approval

Start KYB for your organization, then instantly approve it using the simulation endpoint.

<CodeGroup>
  ```bash cURL theme={null}
  # Start KYB
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/kyb/start" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx"

  # Simulate approval (sandbox only)
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/kyb/simulate-approve" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx"
  ```

  ```typescript SDK theme={null}
  import { RebelfiClient } from '@rebelfi/sdk';

  const client = new RebelfiClient({
    apiKey: 'rfk_sandbox_xxxxxxxxxxxxx',
    sandbox: true,
  });

  await client.ramp.startKyb();
  await client.ramp.simulateKybApproval();
  ```
</CodeGroup>

You can also simulate a KYB rejection:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/kyb/simulate-reject" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx"
  ```

  ```typescript SDK theme={null}
  await client.ramp.simulateKybRejection();
  ```
</CodeGroup>

## Step 2: Create Ramp Accounts

After KYB approval, create on-ramp and off-ramp accounts. These are provisioned through the sandbox banking infrastructure and return real-looking account details.

```bash theme={null}
# On-ramp account (USD → USDC)
curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/onramp-accounts" \
  -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"destinationAsset": "USDC", "orgWalletId": 1}'

# Off-ramp account (USDC → USD)
curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/offramp-accounts" \
  -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "org_wallet_id": 1,
    "source_asset": "USDC",
    "rail": "ach",
    "bank_details": {
      "routing_number": "021000021",
      "account_number": "987654321",
      "account_type": "checking",
      "account_holder_name": "Acme Corp",
      "bank_name": "Chase Bank"
    }
  }'
```

## Step 3: Simulate Transactions

Trigger transaction lifecycle simulation with a chosen scenario. The API responds immediately — the transaction progresses through statuses asynchronously in the background (\~1.5s per step).

### On-Ramp Simulation

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/simulate-transaction" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{"scenario": "success", "usd_amount": 10000}'
  ```

  ```typescript SDK theme={null}
  const { data } = await client.ramp.simulateOnrampTransaction({
    scenario: 'success',
    usdAmount: 10000,
  });
  console.log(data.simulation_id); // "sim_a1b2c3d4e5f6"
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "data": {
    "simulation_id": "sim_a1b2c3d4e5f6",
    "state": "accepted"
  }
}
```

### Off-Ramp Simulation

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/org/simulate-offramp-transaction" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{"scenario": "success", "usd_amount": 25000}'
  ```

  ```typescript SDK theme={null}
  await client.ramp.simulateOfframpTransaction({
    scenario: 'success',
    usdAmount: 25000,
  });
  ```
</CodeGroup>

## Simulation Scenarios

Choose a `scenario` to control which lifecycle path the transaction follows.

### On-Ramp Scenarios

| Scenario   | Status Progression                                                                     | Webhook                                           |
| ---------- | -------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `success`  | pending → processing → in\_progress → awaiting\_confirmation → broadcasted → completed | `transaction.completed`                           |
| `failed`   | pending → processing → failed                                                          | `transaction.failed`                              |
| `rejected` | pending → rejected                                                                     | `transaction.failed`                              |
| `reversed` | pending → ... → completed → reversed                                                   | `transaction.completed` then `transaction.failed` |

### Off-Ramp Scenarios

| Scenario  | Status Progression                                                                     | Webhook                         |
| --------- | -------------------------------------------------------------------------------------- | ------------------------------- |
| `success` | pending → processing → in\_progress → awaiting\_confirmation → broadcasted → completed | `offramp_transaction.completed` |
| `failed`  | pending → processing → failed                                                          | `offramp_transaction.failed`    |

<Info>
  Each status transition takes \~1.5 seconds. A full `success` scenario completes in \~7.5 seconds. The `reversed` scenario takes \~10.5 seconds.
</Info>

### Request Parameters

**On-ramp simulation:**

| Field               | Type                                                      | Default       | Description                       |
| ------------------- | --------------------------------------------------------- | ------------- | --------------------------------- |
| `scenario`          | `"success"` \| `"failed"` \| `"rejected"` \| `"reversed"` | `"success"`   | Lifecycle path to simulate        |
| `usd_amount`        | number                                                    | `50000`       | USD amount for the transaction    |
| `onramp_account_id` | number                                                    | first account | Target a specific on-ramp account |

**Off-ramp simulation:**

| Field                | Type                      | Default       | Description                        |
| -------------------- | ------------------------- | ------------- | ---------------------------------- |
| `scenario`           | `"success"` \| `"failed"` | `"success"`   | Lifecycle path to simulate         |
| `usd_amount`         | number                    | `50000`       | USD amount for the transaction     |
| `offramp_account_id` | number                    | first account | Target a specific off-ramp account |

## Step 4: Verify via Webhooks or Polling

When a simulated transaction reaches a terminal state, RebelFi fires the same webhook events as production to your configured endpoint.

```bash theme={null}
# Poll transaction status
curl "https://sandbox-api.rebelfi.io/v1/ramp/org/transactions" \
  -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx"
```

<Tip>
  Use [webhook.site](https://webhook.site) to quickly stand up a test endpoint and inspect incoming webhook payloads.
</Tip>

See [Webhooks](/ramping/webhooks) for the full event reference. The `reversed` scenario fires `transaction.completed` first, then `transaction.failed` with error `"reversed"`.

## Fee Calculation

Simulated transactions use fixed fee rates:

| Component     | Rate       |
| ------------- | ---------- |
| Developer fee | 5 bps      |
| Platform fee  | 15 bps     |
| **Total fee** | **20 bps** |

**Example — \$10,000 transaction:**

|           | Amount      |
| --------- | ----------- |
| Amount in | \$10,000.00 |
| Total fee | \$20.00     |
| Delivered | \$9,980.00  |

## Recipient-Level Simulation

You can also simulate transactions at the recipient level:

<CodeGroup>
  ```bash cURL theme={null}
  # Simulate on-ramp for a specific recipient
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/recipients/1/simulate-transaction" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{"scenario": "success", "usd_amount": 10000}'

  # Simulate off-ramp for a specific recipient
  curl -X POST "https://sandbox-api.rebelfi.io/v1/ramp/recipients/1/simulate-offramp-transaction" \
    -H "x-api-key: rfk_sandbox_xxxxxxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{"scenario": "success", "usd_amount": 25000}'
  ```

  ```typescript SDK theme={null}
  await client.ramp.simulateRecipientOnrampTransaction(1, {
    scenario: 'success',
    usdAmount: 10000,
  });

  await client.ramp.simulateRecipientOfframpTransaction(1, {
    scenario: 'success',
    usdAmount: 25000,
  });
  ```
</CodeGroup>

## Simulation Endpoints Reference

### Org-Level

| Method | Path                                        | Purpose                       |
| ------ | ------------------------------------------- | ----------------------------- |
| POST   | `/v1/ramp/org/kyb/simulate-approve`         | Approve KYB instantly         |
| POST   | `/v1/ramp/org/kyb/simulate-reject`          | Reject KYB instantly          |
| POST   | `/v1/ramp/org/simulate-transaction`         | Simulate on-ramp transaction  |
| POST   | `/v1/ramp/org/simulate-offramp-transaction` | Simulate off-ramp transaction |

### Recipient-Level

| Method | Path                                                    | Purpose                         |
| ------ | ------------------------------------------------------- | ------------------------------- |
| POST   | `/v1/ramp/recipients/{id}/simulate-transaction`         | Simulate on-ramp for recipient  |
| POST   | `/v1/ramp/recipients/{id}/simulate-offramp-transaction` | Simulate off-ramp for recipient |

<Warning>
  Simulation endpoints are only available in the sandbox environment. Calling them in production returns a `400` error.
</Warning>

## Testing Checklist

Use this checklist to validate your integration covers all scenarios:

<AccordionGroup>
  <Accordion title="KYB Flow" icon="user-check">
    * [ ] Start KYB and receive KYB URL
    * [ ] Simulate KYB approval and verify `customer.approved` webhook
    * [ ] Simulate KYB rejection and verify `customer.declined` webhook
    * [ ] Verify your app handles both approval and rejection gracefully
  </Accordion>

  <Accordion title="On-Ramp" icon="arrow-up">
    * [ ] Create on-ramp account and store bank details
    * [ ] Simulate `success` scenario — verify `transaction.completed` webhook and amounts
    * [ ] Simulate `failed` scenario — verify `transaction.failed` webhook and error handling
    * [ ] Simulate `rejected` scenario — verify your app handles rejections
    * [ ] Simulate `reversed` scenario — verify your app handles both completed and reversed events
    * [ ] Verify transaction appears in transaction list
  </Accordion>

  <Accordion title="Off-Ramp" icon="arrow-down">
    * [ ] Create off-ramp account with bank details
    * [ ] Simulate `success` scenario — verify `offramp_transaction.completed` webhook
    * [ ] Simulate `failed` scenario — verify `offramp_transaction.failed` webhook
    * [ ] Verify transaction appears in off-ramp transaction list
  </Accordion>

  <Accordion title="Edge Cases" icon="triangle-exclamation">
    * [ ] Call simulate endpoints before KYB approval — verify `400` error
    * [ ] Attempt to simulate with an invalid recipient ID — verify `404` error
    * [ ] Verify fee math matches expected values for your transaction amounts
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Webhooks" icon="bell" href="/ramping/webhooks">
    Full webhook event reference
  </Card>

  <Card title="Quick Start" icon="rocket" href="/ramping/quickstart">
    Production integration guide
  </Card>
</CardGroup>
