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

# Testing

> Rehearse every payment outcome in sandbox before going live.

Sandbox is selected by the key you use. A `sk_sandbox_...` key hits the same base URL, the
same endpoints and the same webhook events as live — it simply never moves real money.

```
https://api.orqex.com/v1
```

Sandbox comes with a built-in test payment gateway, so you can reproduce every outcome —
including the awkward ones — without depending on anyone else's system. Its method code is
`test`, and it exists in sandbox only.

```bash theme={null}
curl -X POST https://api.orqex.com/v1/payment/intents/pi_.../attempts \
  -H "Authorization: Bearer sk_sandbox_..." \
  -H "Content-Type: application/json" \
  -d '{
    "method_code": "test",
    "country": "US",
    "phone": { "number": "+12015550101", "country": "US" }
  }'
```

## Outcome matrix

The outcome is chosen by the **last two digits of the payer's phone number**, not by the
amount.

| Phone ends with | Outcome                                                    |
| --------------- | ---------------------------------------------------------- |
| `01`            | Stays `processing`, then completes after the pending delay |
| `02`            | Fails                                                      |
| `03`            | `collect_otp`                                              |
| `04`            | `approve_on_phone`                                         |
| `05`            | `redirect_to_url`                                          |
| `06`            | `embed_iframe`                                             |
| `07`            | `scan_qr_code`                                             |
| `08`            | `display_payment_instructions`                             |
| `09`            | `complete_with_sdk`                                        |
| anything else   | Completes immediately                                      |

A number ending in `02` always fails; one ending in `55` always succeeds. See
[Next actions](/payments/next-actions) for what to render in each case.

## Working through an OTP

<Steps>
  <Step title="Start an attempt with a phone ending in 03">
    ```bash theme={null}
    curl -X POST https://api.orqex.com/v1/payment/intents/pi_.../attempts \
      -H "Authorization: Bearer sk_sandbox_..." \
      -H "Content-Type: application/json" \
      -d '{
        "method_code": "test",
        "country": "US",
        "phone": { "number": "+12015550103", "country": "US" }
      }'
    ```

    The intent comes back with `active_attempt.next_action.type` set to `collect_otp`,
    `digits: 6` and `is_strict: true`.
  </Step>

  <Step title="Collect the code">
    In production the payer receives it by SMS. In sandbox the valid code is always
    `123456`.
  </Step>

  <Step title="Submit it">
    ```bash theme={null}
    curl -X POST https://api.orqex.com/v1/payment/intents/pi_.../authorize \
      -H "Authorization: Bearer sk_sandbox_..." \
      -H "Content-Type: application/json" \
      -d '{ "otp": "123456" }'
    ```

    The correct code completes the attempt. Anything else fails it — which is the path worth
    testing too.
  </Step>
</Steps>

## Controlling the pending delay

The `01` outcome stays processing for 20 seconds by default. Shorten it so your asynchronous
tests do not crawl:

```json theme={null}
{
  "method_code": "test",
  "country": "US",
  "phone": { "number": "+12015550101", "country": "US" },
  "gateway_options": {
    "test": { "pending_duration_seconds": 3 }
  }
}
```

Accepted range is 1 to 600 seconds.

## What to rehearse before going live

* A payment that fails, and the message you show for each
  [failure category](/errors#failure-categories).
* Each next action your interface can receive.
* A payment that completes only after the payer has left your site, so you prove your
  [webhook handler](/webhooks) works.
* The same webhook delivered twice, and out of order.
* A [refund](/payments/refunds), including a partial one.

## Going live

```diff theme={null}
- Authorization: Bearer sk_sandbox_...
+ Authorization: Bearer sk_live_...
```

That is the whole change. URLs, request shapes and response shapes are identical.

<Warning>
  The test gateway does not exist in the live environment. The `test` method code is
  rejected outside sandbox.
</Warning>

<Card title="Testing payouts" icon="money-bill-transfer" href="/payouts/testing">
  Payouts have their own test gateway and their own outcome matrix.
</Card>
