# Test scenarios (/docs/payment-orchestration/test-scenarios)

Comprehensive test scenarios and sandbox testing instructions for the Precium Payment API. Contact your account manager to gain access to more advanced testing scenarios if required. Especially for s2s integrations.

## Sandbox Environment [#sandbox-environment]

### Sandbox Configuration [#sandbox-configuration]

| Setting | Value |
|---|---|
| Base URL | `https://gate.reviopay.com/api/v1/` |
| API Key | Your sandbox API key from dashboard |
| Brand ID | Your sandbox brand ID |

<Callout type="info">
Note: Sandbox and production use the same base URL but different credentials. Always verify you're using sandbox credentials when testing.
</Callout>

## Test Card Numbers [#test-card-numbers]

### Successful Payments [#successful-payments]

| Card Number | Brand | 3DS | Behavior |
|---|---|---|---|
| `4444 3333 2222 1111` | Visa | Yes | Success |
| `5555 5555 5555 4444` | Mastercard | Yes | Success |
| `4000 0000 0000 0077` | Visa | No | Success (no 3DS) |

### Test Card Details [#test-card-details]

| Field | Value |
|---|---|
| Expiry Date | Any future date (e.g., `12/28`) |
| CVC | `123` |
| Cardholder Name | Any Latin characters |

### Failed Payments [#failed-payments]

Use these card numbers to simulate failures:

| Card Number | Error Type |
|---|---|
| Invalid card number | Card declined |
| Invalid CVC | Validation error |
| Past expiry date | Expired card |

## Test Scenarios [#test-scenarios]

### Category 1: Basic Payment Flow [#category-1-basic-payment-flow]

**TC-1.1: Create Payment Link**

**Objective:** Verify payment link creation with minimal parameters

**Steps:**

1. POST to `/purchases/` with client email, product, and brand_id
2. Verify response contains `checkout_url`
3. Open `checkout_url` in browser
4. Verify the checkout page loads correctly

**Request:**

```json
{
  "client": {"email": "test@example.com"},
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Test Product", "price": 10000}]
  },
  "brand_id": "YOUR_BRAND_ID"
}
```

**Expected:** HTTP 201, response contains `checkout_url` and `id`

**TC-1.2: Complete Card Payment**

**Objective:** End-to-end card payment flow

**Steps:**

1. Create a purchase with redirect URLs
2. Navigate to `checkout_url`
3. Enter test card details
4. Complete 3DS if prompted
5. Verify the redirect to `success_redirect`
6. GET purchase to confirm the status is `paid`

**Request:**

```json
{
  "client": {"email": "test@example.com"},
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Test Product", "price": 10000}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "success_redirect": "https://example.com/success",
  "failure_redirect": "https://example.com/failure"
}
```

**Expected:**

- Payment completes
- Redirected to the success URL
- Purchase status is `paid`

**TC-1.3: Payment with Multiple Products**

**Objective:** Verify the correct total calculation

**Steps:**

1. Create a purchase with multiple products
2. Verify `purchase.total` equals the sum of all product prices
3. Complete payment
4. Verify the amount charged matches the total

**Request:**

```json
{
  "client": {"email": "test@example.com"},
  "purchase": {
    "currency": "ZAR",
    "products": [
      {"name": "Product A", "price": 5000, "quantity": "2"},
      {"name": "Product B", "price": 3000},
      {"name": "Shipping", "price": 2000}
    ]
  },
  "brand_id": "YOUR_BRAND_ID"
}
```

**Expected:** Total should be 15000 (5000Ã2 + 3000 + 2000)

### Category 2: Payment Method Restrictions [#category-2-payment-method-restrictions]

**TC-2.1: Whitelist Card Only**

**Objective:** Verify that only whitelisted methods appear

**Steps:**

1. Create a purchase with `payment_method_whitelist: ["visa", "mastercard"]`
2. Open checkout page
3. Verify that only Visa and Mastercard options appear
4. Verify EFT options are not available

**Request:**

```json
{
  "client": {"email": "test@example.com"},
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Test", "price": 10000}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "payment_method_whitelist": ["visa", "mastercard"]
}
```

**Expected:** Only card payment options visible on checkout

**TC-2.2: Whitelist EFT Only**

**Objective:** Verify non-card methods work

**Steps:**

1. Create a purchase with `payment_method_whitelist: ["ozow"]`
2. Open checkout page
3. Verify that only Ozow option appears
4. Verify card options are not available

**Expected:** Only Ozow payment option visible

### Category 3: Pre-Authorization (Hold Funds) [#category-3-pre-authorization-hold-funds]

**TC-3.1: Create Pre-Authorization**

**Objective:** Reserve funds without capture

**Steps:**

1. Create a purchase with `skip_capture: true`
2. Complete payment
3. Verify the status is `hold` (not `paid`)
4. Verify funds are reserved on the test card

**Request:**

```json
{
  "client_id": "CLIENT_UUID",
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Hotel Deposit", "price": 500000}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "skip_capture": true,
  "success_redirect": "https://example.com/success",
  "failure_redirect": "https://example.com/failure"
}
```

**Expected:** Status `hold` after payment completion

**TC-3.2: Capture Pre-Authorization (Full)**

**Objective:** Capture the full held amount

**Steps:**

1. Create pre-auth purchase (TC-3.1)
2. Complete payment
3. POST to `/purchases/{id}/capture/` with full amount
4. Verify status changes to `paid`

**Request:**

```bash
POST https://gate.reviopay.com/api/v1/purchases/{id}/capture/
{"amount": 500000}
```

**Expected:** Status changes to `paid`

**TC-3.3: Capture Pre-Authorization (Partial)**

**Objective:** Capture less than held amount

**Steps:**

1. Create pre-auth for 500000 cents
2. Complete payment
3. Capture only 300000 cents
4. Verify capture succeeds
5. Verify the remaining 200000 is released

**Request:**

```bash
POST https://gate.reviopay.com/api/v1/purchases/{id}/capture/
{"amount": 300000}
```

**Expected:** Capture succeeds with a partial amount

**TC-3.4: Release Pre-Authorization**

**Objective:** Release held funds without capture

**Steps:**

1. Create a pre-auth purchase
2. Complete payment (status = `hold`)
3. POST to `/purchases/{id}/release/`
4. Verify status changes to `released`
5. Verify funds are released on the test card

**Expected:** Status `released`, funds returned

### Category 4: Refunds [#category-4-refunds]

**TC-4.1: Full Refund**

**Objective:** Refund the entire payment

**Steps:**

1. Create and complete a payment
2. Verify the status is `paid`
3. POST to `/purchases/{id}/refund/` with an empty body
4. Verify the refund is processed
5. Check the purchase for refund status

**Request:**

bash

```bash
POST https://gate.reviopay.com/api/v1/purchases/{id}/refund/
{}
```

**Expected:** Refund processed, status updated

**TC-4.2: Partial Refund**

**Objective:** Refund portion of payment

**Steps:**

1. Complete payment for 10000 cents
2. POST refund for 3000 cents
3. Verify partial refund succeeds
4. Verify the remaining balance is 7000

**Request:**

```bash
POST https://gate.reviopay.com/api/v1/purchases/{id}/refund/
{"amount": 3000}
```

**Expected:** Partial refund of 3000 cents processed

**TC-4.3: Multiple Partial Refunds**

**Objective:** Issue multiple refunds on the same purchase

**Steps:**

1. Complete payment for 10000 cents
2. Refund 3000 cents (success)
3. Refund another 4000 cents (success)
4. Verify the total refunded is 7000
5. Verify the remaining is 3000

**Expected:** Multiple refunds succeed up to the original amount

**TC-4.4: Refund Exceeds Amount**

**Objective:** Verify refund limit enforcement

**Steps:**

1. Complete payment for 10000 cents
2. Attempt to refund 15000 cents
3. Verify request fails with appropriate error

**Expected:** HTTP 400, error `refund_exceeds_amount`

### Category 5: Recurring Payments [#category-5-recurring-payments]

**TC-5.1: Tokenize Card**

**Objective:** Save card for future payments

**Steps:**

1. Create a purchase with `force_recurring: true`
2. Complete payment
3. GET `/clients/{id}/recurring_tokens/`
4. Verify the token is created

**Request:**

```json
{
  "client_id": "CLIENT_UUID",
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Subscription", "price": 29900}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "force_recurring": true,
  "success_redirect": "https://example.com/success",
  "failure_redirect": "https://example.com/failure"
}
```

**Expected:** Recurring token created after payment

**TC-5.2: Zero-Amount Tokenization**

**Objective:** Save the card without charging

**Steps:**

1. Create a purchase with `price: 0` and `skip_capture: true`
2. Complete checkout (no charge)
3. Verify that the token is created
4. Use the token for subsequent charges

**Request:**

```json
{
  "client_id": "CLIENT_UUID",
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Card Authorization", "price": 0}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "skip_capture": true,
  "force_recurring": true,
  "success_redirect": "https://example.com/success",
  "failure_redirect": "https://example.com/failure"
}
```

**Expected:** Token created, no charge to card

**TC-5.3: Charge with Token**

**Objective:** Process payment using saved token

**Steps:**

1. Complete tokenization (TC-5.1)
2. Create a new purchase for the same client
3. POST to `/purchases/{id}/charge/` with `recurring_token`
4. Verify payment succeeds without customer interaction

**Request:**

```bash
POST https://gate.reviopay.com/api/v1/purchases/{new_id}/charge/
{"recurring_token": "ORIGINAL_PURCHASE_ID"}
```

**Expected:** Payment succeeds, status `paid`

**TC-5.4: Charge with Invalid Token**

**Objective:** Verify invalid token handling

**Steps:**

1. Create purchase
2. Attempt charge with non-existent token ID
3. Verify the appropriate error returned

**Expected:** HTTP 404, error `recurring_token_not_found`

### Category 6: Billing Templates (Subscriptions) [#category-6-billing-templates-subscriptions]

**TC-6.1: Create Subscription Plan**

**Objective:** Create a monthly subscription template

**Steps:**

1. POST to `/billing_templates/`
2. Verify template created
3. Check subscription settings are correct

**Request:**

```json
{
  "title": "Monthly Premium",
  "purchase": {
    "currency": "ZAR",
    "products": [{"name": "Premium Plan", "price": 29900}]
  },
  "brand_id": "YOUR_BRAND_ID",
  "is_subscription": true,
  "subscription_active": true,
  "subscription_period": 1,
  "subscription_period_units": "months",
  "force_recurring": true
}
```

**Expected:** Template created with subscription configuration

**TC-6.2: Add Subscriber**

**Objective:** Subscribe the client to a plan

**Steps:**

1. Attempt to create another with the same email

**TC-6.3: Add Subscriber with Override**

**Objective:** Subscribe with custom pricing

**Steps:**

1. Create a template with a standard price
2. Add subscriber with override price
3. Verify the subscriber has a custom price
4. Complete payment
5. Verify the charged amount matches the override

**Request:**

```json
{
  "client_id": "CLIENT_UUID",
  "override": {
    "products": [{"name": "Discounted Plan", "price": 19900}]
  }
}
```

**Expected:** Subscription uses override pricing

### Category 7: Client Management [#category-7-client-management]

**TC-7.1: Create Client**

**Objective:** Create a new client record

**Steps:**

1. POST to `/clients/` with email and details
2. Verify client created
3. Verify all fields are saved correctly

**Request:**

```json
{
  "email": "test@example.com",
  "full_name": "Test User",
  "phone": "+27821234567"
}
```

**Expected:** HTTP 201, client ID returned

**TC-7.2: Search Client**

**Objective:** Find a client by email

**Steps:**

1. Create client
2. GET `/clients/?email=test@example.com`
3. Verify the client found in the results

**Expected:** Client returned in search results

**TC-7.3: Duplicate Client Prevention**

**Objective:** Verify duplicate email handling

**Steps:**

1. Create a client with an email
2. Attempt to create another with the same email
3. Verify the appropriate error

**Expected:** HTTP 409, error `duplicate_client`

### Category 8: Webhooks [#category-8-webhooks]

**TC-8.1: Payment Success Webhook**

**Objective:** Verify webhook delivery on payment

**Steps:**

1. Configure the webhook for `purchase.paid`
2. Create and complete a payment
3. Verify the webhook was received
4. Verify payload contains purchase data

**Expected:** Webhook delivered with correct event type

**TC-8.2: Payment Failure Webhook**

**Objective:** Verify the webhook on failed payment

**Steps:**

1. Configure the webhook for `purchase.payment_failure`
2. Create purchase
3. Attempt payment with an invalid card
4. Verify failure webhook received

**Expected:** Webhook delivered with failure details

**TC-8.3: Webhook Signature Verification**

**Objective:** Verify webhook authenticity

**Steps:**

1. Receive webhook
2. Extract signature header
3. Calculate the expected signature using the secret
4. Verify signatures match

**Expected:** Calculated signature matches header

### Category 9: Error Handling [#category-9-error-handling]

**TC-9.1: Invalid API Key**

**Objective:** Verify authentication error

**Steps:**

1. Make a request with an invalid API key
2. Verify HTTP 401 returned
3. Verify the error message is clear

**Expected:** HTTP 401, `invalid_token` error

**TC-9.2: Missing Required Field**

**Objective:** Verify validation error

**Steps:**

1. POST purchase without `brand_id`
2. Verify HTTP 400 returned
3. Verify field-specific error message

**Expected:** HTTP 400, `required` error for `brand_id`

**TC-9.3: Invalid UUID**

**Objective:** Verify UUID validation

**Steps:**

1. GET `/purchases/invalid-uuid/`
2. Verify the appropriate error

**Expected:** HTTP 400 or 404 with clear error

**TC-9.4: Rate Limiting**

**Objective:** Verify rate limit handling

**Steps:**

1. Make requests rapidly (>100/minute)
2. Observe rate limit response
3. Verify the retry-after information provided

**Expected:** HTTP 429 after limit exceeded

## Test Checklist [#test-checklist]

**Pre-Integration Checklist**

- Sandbox API key obtained
- Brand ID configured
- Webhook endpoint ready
- Test card numbers available

**Basic Flow Tests**

- TC-1.1: Create payment link
- TC-1.2: Complete card payment
- TC-1.3: Multiple products
- TC-2.1: Payment method whitelist

**Advanced Flow Tests**

- TC-3.1: Pre-authorization
- TC-3.2: Full capture
- TC-3.3: Partial capture
- TC-3.4: Release hold
- TC-4.1: Full refund
- TC-4.2: Partial refund
- TC-5.1: Card tokenization
- TC-5.3: Token charge
- TC-6.1: Create subscription
- TC-6.2: Add subscriber

**Error Handling Tests**

- TC-9.1: Invalid API key
- TC-9.2: Validation errors
- TC-9.3: Invalid UUID
- TC-9.4: Rate limiting

**Production Readiness**

- Webhook handling implemented
- Error handling complete
- Idempotency implemented
- Logging configured
- Production credentials ready

## Go-Live Checklist [#go-live-checklist]

Before going live:

1. **Credentials**

- Production API key configured
- Production brand ID configured
- Sandbox credentials removed from production

1. **Webhooks**

- Production webhook URL configured
- Webhook signature verification implemented
- All relevant events subscribed

1. **Error Handling**

- All error codes handled gracefully
- User-friendly error messages displayed
- Errors logged for debugging

1. **Security**

- API keys stored securely (not in code)
- HTTPS enforced
- Webhook signatures verified

1. **Testing**

- End-to-end test in production sandbox
- Small live transaction tested
- Refund tested
