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

# Testing

> Sandbox testing guide for Payfonte integrations, including provider simulators, webhook validation, and test scenarios.

Use sandbox first for all integration validation before moving to production.

## Sandbox Setup

<Steps>
  <Step title="Use sandbox base URL">
    API base URL: `https://sandbox-api.payfonte.com`
  </Step>

  <Step title="Use sandbox credentials">
    Get your `client-id` and `client-secret` from `Settings -> Security ->  API Keys and Webhooks` in [sandbox-app.payfonte.com](https://sandbox-app.payfonte.com).
  </Step>

  <Step title="Set webhook endpoint">
    Configure a test callback URL so you can validate async transaction updates.
  </Step>
</Steps>

## What To Validate Before Go-Live

<CardGroup cols={2}>
  <Card title="Auth and Headers" icon="key">
    Confirm all requests include `client-id` and `client-secret`.
  </Card>

  <Card title="Amount Format" icon="hashtag">
    Confirm you send integer minor-unit values only. Decimals are not supported.
  </Card>

  <Card title="Status Lifecycle" icon="repeat">
    Validate pending/processing to final states (`success` or `failed`) in your
    business flow.
  </Card>

  <Card title="Webhook Handling" icon="bell">
    Verify signature validation, retries, idempotency, and response timing.
  </Card>
</CardGroup>

## Core Test Scenarios

| Scenario              | Expected Result                                   |
| --------------------- | ------------------------------------------------- |
| Valid charge request  | `201` response with transaction reference         |
| Invalid credentials   | Authentication failure (`401`/`403`)              |
| Decimal amount sent   | Validation/provider failure                       |
| Duplicate reference   | `409` with `DuplicateTransactionReference`        |
| Invalid provider slug | Error with `InvalidProvider`                      |
| Webhook delivery      | Callback received and processed once (idempotent) |

## Simulate Success, Failed, and Pending Outcomes

For both collections and disbursements in sandbox, you can control the expected transaction outcome by changing the mobile money phone number used in the request.

| Phone Number Pattern      | Expected Result | How To Use It                                                        |
| ------------------------- | --------------- | -------------------------------------------------------------------- |
| Any other phone number    | `success`       | Sandbox treats all other phone numbers as successful transactions    |
| Number ending in `000000` | `failed`        | Sandbox forces the transaction to fail                               |
| Number ending in `111111` | `pending`       | Sandbox keeps the transaction pending so you can test async handling |

<Info>
  Apply this rule to the phone number field you send for the transaction. For
  collections, use the customer's mobile money number. For disbursements, use
  the recipient phone number.
</Info>

When testing pending flows, do not treat the initial API response as final. Wait for webhook updates or verify the transaction status from your backend before marking the transaction as `success` or `failed`.

## Card Test Details

Use these sandbox card details to test card collection authentication paths and final outcomes.

| Number                         | Expiry  | CVV   | PIN    | OTP      | Test Case            | Status  |
| ------------------------------ | ------- | ----- | ------ | -------- | -------------------- | ------- |
| `5061 4604 1012 1111 101`      | `12/50` | `557` | `1102` | `543210` | Pin                  | PENDING |
| `5061 4604 1012 1111 102`      | `12/50` | `558` | `1103` | `543210` | Pin+OTP              | PENDING |
| `5061 4604 1012 1111 103`      | `12/50` | `559` | `1107` | `543210` | Pin+3DS              | PENDING |
| `5061 4604 1012 1111 104`      | `12/50` | `560` | `1104` | `543210` | Pin                  | SUCCESS |
| `5061 4604 1012 1111 105`      | `12/50` | `561` | `1105` | `543210` | Pin+OTP              | SUCCESS |
| `5061 4604 1012 1111 106`      | `12/50` | `562` | `1106` | `543210` | Pin+3DS              | SUCCESS |
| `5061 4604 1012 1111 107`      | `12/50` | `563` | `1107` | `123456` | Pin                  | FAIL    |
| `5061 4604 1012 1111 108`      | `12/50` | `564` | `1108` | `245678` | Pin+OTP              | FAIL    |
| `5061 4604 1012 1111 109`      | `12/50` | `565` | `1109` | `456789` | Pin+3ds              | FAIL    |
| `5061 4604 1012 1111 110`      | `12/50` | `566` | `1110` | `234567` | No auth              |         |
| `5061 4604 1012 1111 111`      | `12/50` | `567` | `1111` | `334455` | Insufficient balance |         |
| `5061 4604 1012 1111 112`      | `3/50`  | `568` | `1111` | `334455` | Expired card         |         |
| `4508 7500 15741 019(USD)`     | `12/50` | `100` |        |          | 3DS                  | SUCCESS |
| `4012 0000 3333 0026(USD)`     | `12/50` | `100` |        |          | 3DS                  | SUCCESS |
| `5123 4500 0000 0008(USD)`     | `12/50` | `100` |        |          | 3DS                  | SUCCESS |
| `2223 0000 0000 0007(USD)`     | `12/50` | `100` |        |          | 3DS                  | FAIL    |
| `5111 1111 1111 1118(USD)`     | `12/50` | `100` |        |          | 3DS                  | FAIL    |
| `2223 0000 0000 0007(USD)`     | `12/50` | `100` |        |          | 3DS                  | FAIL    |
| `5061 4604 1012 1111 103(USD)` | `12/50` | `100` | `1107` |          | 3DS                  | PENDING |

## Provider-Specific Test Data

<AccordionGroup>
  <Accordion title="Orange Ivory Coast OTP simulator" icon="mobile-screen-button" defaultOpen>
    For Orange Ivory Coast testing on Payfonte:

    1. Open [https://mpayment.orange-money.com/mpayment-otp/login](https://mpayment.orange-money.com/mpayment-otp/login)
    2. Sign in with:
       * Username: `7701901040`
       * Password: `MerchantWP01040`
    3. Generate OTP with:
       * Phone Number: `7701101040` (usually pre-loaded)
       * PIN: `1791`
    4. Use the generated OTP on the payment platform.
  </Accordion>

  <Accordion title="Safaricom / Equitel / T-Kash / Telkom" icon="phone">
    * Success example: `254700123456`
    * Failed example: `254700000000`
    * Pending example: `254711111111`
  </Accordion>

  <Accordion title="Airtel / Telecel / MTN (Ghana)" icon="phone">
    * Success example: `233242426222`
    * Failed example: `233240000000`
    * Pending example: `233241111111`
  </Accordion>
</AccordionGroup>

## Quick Sandbox Request

```bash theme={null}
curl --location 'https://sandbox-api.payfonte.com/payments/v1/checkouts' \
  --header 'client-id: <your-client-id>' \
  --header 'client-secret: <your-client-secret>' \
  --header 'Content-Type: application/json' \
  --data '{
    "reference": "test-001",
    "amount": 10000,
    "currency": "NGN",
    "country": "NG",
    "user": {
      "phoneNumber": "08012345678"
    }
  }'
```

## Related Docs

<CardGroup cols={3}>
  <Card title="Environments" icon="server" href="/en/guides/introductions/environments">
    Sandbox and production URLs and credential setup.
  </Card>

  <Card title="Webhooks" icon="bell" href="/en/guides/collections/webhook">
    Verify callback payloads and signature handling.
  </Card>

  <Card title="Error Codes" icon="triangle-exclamation" href="/en/guides/introductions/error-codes">
    Troubleshoot failed test requests quickly.
  </Card>
</CardGroup>
