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

# Test in Sandbox

> Validate your integration using the Grain sandbox environment

## Configure for Sandbox

Point the SDK to the sandbox API by setting the host environment variable:

```bash theme={null}
CUBEPAY_API_HOST=https://api.sandbox.pay.grain.inc
```

All other environment variables (`NEXT_PUBLIC_CUBEPAY_MERCHANT_ID`, `CUBEPAY_API_KEY`) use your sandbox credentials from the [Grain Dashboard](https://dashboard.grain.inc).

***

## Run an End-to-End Test

<Steps>
  <Step title="Create a payment session">
    Use your server to create a session against the sandbox API.

    ```bash theme={null}
    curl -X POST https://api.sandbox.pay.grain.inc/payment-sessions \
      -H "Authorization: Bearer your-sandbox-api-key" \
      -H "Content-Type: application/json" \
      -d '{"amount": "10.00", "currency": "USD"}'
    ```
  </Step>

  <Step title="Open the payment modal">
    Launch the SDK on the client with the returned session credentials. In sandbox, the SDK connects to test blockchain networks (Sepolia) automatically.
  </Step>

  <Step title="Complete the payment">
    Connect a wallet funded with testnet tokens and approve the transaction. The SDK handles network switching automatically.
  </Step>

  <Step title="Verify in the dashboard">
    Go to the [Grain Dashboard](https://dashboard.grain.inc) and navigate to **Transactions**. Confirm your test payment appears with the expected status.
  </Step>
</Steps>

***

## Test Webhook Delivery

Sandbox webhooks work identically to production. Configure your webhook URL in the dashboard and use a tunneling tool to receive webhooks locally:

```bash theme={null}
# Expose your local server
ngrok http 3000
```

Then update your webhook URL in the Grain Dashboard to point to your ngrok URL:

```
https://your-subdomain.ngrok.io/api/transactions/webhook
```

### Simulate Payment Statuses

Each webhook delivery contains a `status` field. In sandbox, payments progress through the full lifecycle:

| Status      | When It Fires                                  |
| ----------- | ---------------------------------------------- |
| `PENDING`   | Session created                                |
| `FUNDED`    | Testnet tokens received at the one-time wallet |
| `SUCCEEDED` | Simulated sweep to settlement                  |
| `CANCELED`  | Payment cancelled (timeout or user action)     |
| `ERROR`     | Simulated error condition                      |

Verify your webhook handler processes each status correctly by monitoring your server logs as you complete test payments.

***

## Sandbox vs Production

| Behavior           | Sandbox                     | Production                 |
| ------------------ | --------------------------- | -------------------------- |
| Blockchain network | Sepolia (testnet)           | Ethereum, Base (mainnet)   |
| Tokens             | Test USDC (no real value)   | Real USDC                  |
| Settlement         | Simulated                   | Real on-chain settlement   |
| Webhooks           | Delivered to your endpoint  | Delivered to your endpoint |
| API host           | `api.sandbox.pay.grain.inc` | `api.pay.grain.inc`        |

<Warning>
  Always test the full payment flow in sandbox before switching to production. Verify that your webhook handler, success screen, and error handling all work as expected.
</Warning>
