# Test scenarios (/docs/server-to-server/test-scenarios)

## Precium S2S Testing Checklist [#precium-s2s-testing-checklist]

This document provides a comprehensive testing checklist to ensure your integration handles all payment scenarios correctly before going live.

## Pre-Testing Setup [#pre-testing-setup]

Before running tests, ensure you have:

- Sandbox API credentials configured
- Standard API Key and S2S API Key available
- Brand ID configured for sandbox
- Webhook endpoint deployed and accessible
- Logging enabled for all API calls and responses
- Test card numbers ready (see Test Cards Reference below)

## Test Categories Overview [#test-categories-overview]

| Category | Tests | Priority |
|---|---|---|
| Happy Path | 8 | Critical |
| Pre-Authorization & Capture | 6 | Critical |
| Void/Cancel Operations | 4 | High |
| Refund Scenarios | 5 | High |
| Error Handling | 12 | Critical |
| 3DS Scenarios | 5 | Critical |
| Webhook Integration | 8 | Critical |
| Edge Cases | 7 | Medium |
| External Integrations | 4 | Conditional |
| Security & Compliance | 6 | Critical |

**Total: 65 test cases**

## 1. Happy Path Tests [#1-happy-path-tests]

### 1.1 Standard CIT Payment with Internal 3DS [#11-standard-cit-payment-with-internal-3ds]

**Test Card:**`4000000000001091` (3DS required)

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create client | Returns client ID |
| 2 | Create purchase (amount: 10000, force_recurring: true) | Returns purchase ID and direct_post_url |
| 3 | Submit card data with browser fingerprint | Returns 3DS parameters or ready status |
| 4 | Complete 3DS challenge | Redirects to callback URL |
| 5 | POST to callback with MD and PaRes | Returns success |
| 6 | Verify purchase status | Status: "paid" |
| 7 | Check for token | payment_method_details.card.token present |
| 8 | Check for network_transaction_id | Value present for MIT use |

### 1.2 Standard CIT Payment without 3DS Challenge [#12-standard-cit-payment-without-3ds-challenge]

**Test Card:**`4000000000001000` (No 3DS)

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create client | Returns client ID |
| 2 | Create purchase | Returns purchase ID |
| 3 | Submit card data | No 3DS parameters returned |
| 4 | Charge purchase | Status: "paid" |

### 1.3 Preauthorisation (Card Validation) [#13-preauthorisation-card-validation]

**Test Card:**`4000000000001091`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create client | Returns client ID |
| 2 | Create purchase with amount: 0 | Returns purchase ID |
| 3 | Submit card data | 3DS flow initiated |
| 4 | Complete 3DS | Success |
| 5 | Verify no charge | Amount authorized: 0 |
| 6 | Verify token generated | Token present (if force_recurring: true) |

### 1.4 MIT Recurring Charge [#14-mit-recurring-charge]

**Prerequisite:** Completed CIT with token stored

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create MIT purchase with token reference | Returns purchase ID |
| 2 | Include previous_network_transaction_id | Accepted |
| 3 | Include original_amount_cents | Accepted |
| 4 | Submit with stored token (no CVV) | Ready for charge |
| 5 | Charge purchase | Status: "paid" |
| 6 | Verify no 3DS required | No 3DS challenge |

### 1.5 Mastercard Payment [#15-mastercard-payment]

**Test Card:**`5555555555554444`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete standard flow | Success |
| 2 | Verify card brand in response | brand: "mastercard" |

### 1.6 Multiple Products in Single Purchase [#16-multiple-products-in-single-purchase]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase with multiple products | Total calculated correctly |
| 2 | Complete payment | Full amount charged |

### 1.7 Payment with Metadata [#17-payment-with-metadata]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase with metadata | Accepted |
| 2 | Complete payment | Success |
| 3 | Retrieve purchase | Metadata preserved |
| 4 | Receive webhook | Metadata included |

### 1.8 Different Currency (if supported) [#18-different-currency-if-supported]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase with USD currency | Accepted |
| 2 | Complete payment | Charged in USD |

## 2. Pre-Authorization & Capture Tests [#2-pre-authorization--capture-tests]

### 2.1 Pre-Auth with Full Capture [#21-pre-auth-with-full-capture]

**Test Card:**`4000000000001091`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase (amount: 50000) | Returns purchase ID |
| 2 | Submit card and complete 3DS | Authorization successful |
| 3 | Verify status | Status: "authorized" |
| 4 | Capture full amount | Status: "paid" |
| 5 | Verify captured amount | amount: 50000 |

### 2.2 Pre-Auth with Partial Capture [#22-pre-auth-with-partial-capture]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create and authorize (amount: 50000) | Status: "authorized" |
| 2 | Capture partial amount (35000) | Status: "paid" |
| 3 | Verify captured amount | amount: 35000 |
| 4 | Verify remaining released | No hold for remaining 15000 |

### 2.3 Pre-Auth with Multiple Partial Captures [#23-pre-auth-with-multiple-partial-captures]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Authorize 100000 | Status: "authorized" |
| 2 | First capture: 30000 | Success, remaining: 70000 |
| 3 | Second capture: 40000 | Success, remaining: 30000 |
| 4 | Third capture: 30000 | Success, fully captured |
| 5 | Fourth capture attempt | Error: nothing remaining |

### 2.4 Pre-Auth without CVV (Token-based) [#24-pre-auth-without-cvv-token-based]

**Prerequisite:** Stored token from previous CIT

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase with is_recurring: true | Accepted |
| 2 | Submit with token, CVV: "000" | Accepted |
| 3 | Authorization completes | Status: "authorized" |
| 4 | Capture | Status: "paid" |

### 2.5 Capture Exceeding Authorization [#25-capture-exceeding-authorization]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Authorize 50000 | Status: "authorized" |
| 2 | Attempt capture of 60000 | Error: capture_amount_exceeds_authorization |

### 2.6 Authorization Expiry Handling [#26-authorization-expiry-handling]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Note: May require waiting or test mode | — |
| 2 | Attempt capture on expired auth | Error: authorization_expired |
| 3 | Verify appropriate error handling | User-friendly message |

## 3. Void/Cancel Tests [#3-voidcancel-tests]

### 3.1 Void Pre-Authorization [#31-void-pre-authorization]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create and authorize purchase | Status: "authorized" |
| 2 | Call cancel endpoint | Status: "cancelled" |
| 3 | Verify funds released | No hold on card |
| 4 | Attempt capture after void | Error: already_voided |

### 3.2 Void Capture (Same Day, Before Settlement) [#32-void-capture-same-day-before-settlement]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment | Status: "paid" |
| 2 | Void same day | Status: "cancelled" |
| 3 | Verify immediate reversal | Funds released |

### 3.3 Void After Settlement (Should Fail) [#33-void-after-settlement-should-fail]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Attempt void on settled transaction | Error: void_not_permitted |
| 2 | Verify error message | Suggests using refund |

### 3.4 Refund is irreversible [#34-refund-is-irreversible]

<Callout type="warning">
A refund cannot be voided. Confirm that your own interface prevents a second submission, since there is no idempotency key and a retried request is a second refund.
</Callout>

| Step | Action | Expected Result |
|---|---|---|
| 1 | Process a partial refund | Payment object returned; `refundable_amount` reduced |
| 2 | Attempt to reverse it | No such operation exists — confirm your code never offers one |
| 3 | Re-read the purchase | `refundable_amount` reflects the refund; original charge intact |
| 4 | Submit the same refund twice | Second request is a second refund — confirm your UI blocks it |

## 4. Refund Scenarios [#4-refund-scenarios]

### 4.1 Full Refund [#41-full-refund]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment (29900) | Status: "paid" |
| 2 | Request full refund | Status: "refunded" |
| 3 | Verify refund amount | amount: 29900 |
| 4 | Receive webhook | Event: purchase.refunded |

### 4.2 Partial Refund [#42-partial-refund]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment (50000) | Status: "paid" |
| 2 | Request partial refund (20000) | Success |
| 3 | Verify remaining | 30000 still charged |
| 4 | Verify refund details | Refund ID, amount: 20000 |

### 4.3 Multiple Partial Refunds [#43-multiple-partial-refunds]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment (100000) | Status: "paid" |
| 2 | First refund (25000) | Success, remaining: 75000 |
| 3 | Second refund (25000) | Success, remaining: 50000 |
| 4 | Third refund (50000) | Success, remaining: 0 |
| 5 | Fourth refund attempt | Error: nothing to refund |

### 4.4 Refund Exceeding Original Amount [#44-refund-exceeding-original-amount]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment (30000) | Status: "paid" |
| 2 | Request refund (40000) | Error: exceeds original |

### 4.5 Refund Exceeding Remaining Amount [#45-refund-exceeding-remaining-amount]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment (50000) | Status: "paid" |
| 2 | First refund (30000) | Success |
| 3 | Second refund (30000) | Error: exceeds remaining |

## 5. Error Handling Tests [#5-error-handling-tests]

### 5.1 Card Declined - Generic [#51-card-declined---generic]

**Test Card:**`4000000000000002`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit declined card | Error returned |
| 2 | Verify error code | do_not_honour |
| 3 | Verify user-friendly message | Appropriate message |

### 5.2 Expired Card [#52-expired-card]

**Test Card:**`4000000000000069`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit expired card | Error: expired_card |
| 2 | Verify message | "Card has expired" |

### 5.3 Insufficient Funds [#53-insufficient-funds]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit card with insufficient funds | Error: insufficient_funds |
| 2 | Verify soft decline | Can retry later |

### 5.4 Invalid CVC [#54-invalid-cvc]

**Test Card:**`4000000000000127`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit with wrong CVC | Error: cvc_check_failed |

### 5.5 Invalid Card Number [#55-invalid-card-number]

**Test Input:**`4111111111111112` (fails Luhn)

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit invalid card number | Error: invalid_card_number |
| 2 | Verify validation message | Clear error message |

### 5.6 Invalid Expiry Format [#56-invalid-expiry-format]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit wrong format | Error: invalid_expires |
| 2 | Test: "2028/12", "1228" | All fail |
| 3 | Correct: "12/28" | Success |

### 5.7 Processing Error [#57-processing-error]

**Test Card:**`4000000000000119`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Trigger processing error | Error returned |
| 2 | Verify retry logic | Exponential backoff |

### 5.8 Missing Required Fields [#58-missing-required-fields]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit without client_id | Validation error |
| 2 | Submit without brand_id | Validation error |
| 3 | Submit without currency | Validation error |
| 4 | Submit without products | Validation error |

### 5.9 Invalid API Key [#59-invalid-api-key]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Use invalid API key | HTTP 401 |
| 2 | Use wrong key type | Error returned |
| 3 | Use expired key | HTTP 401 |

### 5.10 Network Timeout Handling [#510-network-timeout-handling]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Simulate network timeout | Error caught |
| 2 | Verify retry logic | Retries with backoff |
| 3 | Verify idempotency | No duplicate charges |

### 5.11 Duplicate Charge Prevention [#511-duplicate-charge-prevention]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit charge request | Success |
| 2 | Resubmit same request | Idempotent response |
| 3 | Verify only one charge | Single transaction |

### 5.12 Expired Direct Post URL [#512-expired-direct-post-url]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase | Get direct_post_url |
| 2 | Use URL once | Success |
| 3 | Reuse URL | Error: expired |

## 6. 3DS Scenarios [#6-3ds-scenarios]

### 6.1 3DS Challenge Flow (Internal) [#61-3ds-challenge-flow-internal]

**Test Card:**`4000000000001091`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit card requiring 3DS | 3DS parameters returned |
| 2 | Verify 3DS fields | MD, PaReq, URL, callback_url |
| 3 | Redirect to 3DS URL | Bank page loads |
| 4 | Complete challenge | Redirects to callback |
| 5 | Submit callback | Payment completes |

### 6.2 3DS Authentication Failed [#62-3ds-authentication-failed]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Initiate 3DS | Challenge presented |
| 2 | Fail authentication | Error: 3ds_authentication_failed |
| 3 | Verify retry available | Can retry |

### 6.3 3DS Timeout [#63-3ds-timeout]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Initiate 3DS | Challenge presented |
| 2 | Allow timeout | Error: timeout |
| 3 | Verify graceful handling | User-friendly message |

### 6.4 Frictionless 3DS [#64-frictionless-3ds]

**Test Card:**`4000000000001000`

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit low-risk transaction | No challenge |
| 2 | Verify frictionless | Success without redirect |

### 6.5 3DS Data in Response [#65-3ds-data-in-response]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete 3DS transaction | Success |
| 2 | Verify ECI value | Present |
| 3 | Verify CAVV | Present |

## 7. Webhook Tests [#7-webhook-tests]

### 7.1 Receive purchase.paid Event [#71-receive-purchasepaid-event]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete payment | Webhook received |
| 2 | Verify event type | purchase.paid |
| 3 | Verify payload | All fields present |
| 4 | Verify purchase_id | Matches transaction |

### 7.2 Receive purchase.payment_failure Event [#72-receive-purchasepayment_failure-event]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit declined card | Payment fails |
| 2 | Receive webhook | purchase.payment_failure |
| 3 | Verify error details | Error code included |

### 7.3 Receive purchase.refunded Event [#73-receive-purchaserefunded-event]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Process refund | Completes |
| 2 | Receive webhook | purchase.refunded |
| 3 | Verify details | Amount, refund_id |

### 7.4 Receive purchase.preauthorized Event [#74-receive-purchasepreauthorized-event]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete pre-auth | Holds funds |
| 2 | Receive webhook | purchase.preauthorized |
| 3 | Verify details | Amount, expiry |

### 7.5 Signature Verification - Valid [#75-signature-verification---valid]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Receive webhook | Headers present |
| 2 | Verify signature | Matches computed |
| 3 | Verify timestamp | Within 5 minutes |
| 4 | Process webhook | Success |

### 7.6 Signature Verification - Invalid [#76-signature-verification---invalid]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Receive tampered webhook | — |
| 2 | Verify signature | Mismatch detected |
| 3 | Reject webhook | HTTP 401 |
| 4 | No processing | No action taken |

### 7.7 Duplicate Webhook Handling [#77-duplicate-webhook-handling]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Receive webhook | Process |
| 2 | Receive same again | Detect duplicate |
| 3 | Return HTTP 200 | Acknowledge |
| 4 | Do not reprocess | Idempotent |

### 7.8 Webhook Timeout Recovery [#78-webhook-timeout-recovery]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Simulate timeout | Precium retries |
| 2 | Fix endpoint | Next retry succeeds |
| 3 | Verify no data loss | Event processed |

## 8. Edge Cases [#8-edge-cases]

### 8.1 Very Small Amount [#81-very-small-amount]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create purchase (amount: 1) | Accepted |
| 2 | Complete payment | Success |

### 8.2 Very Large Amount [#82-very-large-amount]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create large purchase | Accepted or limit error |
| 2 | Verify handling | Appropriate response |

### 8.3 Special Characters in Fields [#83-special-characters-in-fields]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Name with accents | Handled |
| 2 | Special characters | Handled |
| 3 | Verify encoding | UTF-8 preserved |

### 8.4 Token Expiry [#84-token-expiry]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Use expired token | Error: token_expired |
| 2 | Verify handling | Prompts re-tokenization |

### 8.5 Concurrent Requests [#85-concurrent-requests]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Send multiple simultaneous | All handled |
| 2 | Verify no race conditions | No duplicates |
| 3 | Verify data integrity | All correct |

### 8.6 Client Reuse [#86-client-reuse]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Create client once | ID stored |
| 2 | Use for multiple purchases | All succeed |
| 3 | Verify consistency | Data unchanged |

### 8.7 Browser Fingerprint Variations [#87-browser-fingerprint-variations]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Minimal fingerprint | Accepted |
| 2 | Full fingerprint | Accepted |
| 3 | Missing optional fields | Handled |

## 9. External Integration Tests [#9-external-integration-tests]

*Complete if using external 3DS or network tokens*

### 9.1 External 3DS (MPI) Flow [#91-external-3ds-mpi-flow]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Complete 3DS with MPI | Auth data obtained |
| 2 | Create purchase (is_external_3DS: true) | Accepted |
| 3 | Include CAVV, ECI, transaction ID | Validated |
| 4 | Complete payment | Success |

### 9.2 External 3DS - Invalid Data [#92-external-3ds---invalid-data]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit invalid CAVV | Error |
| 2 | Submit missing fields | Error |
| 3 | Submit wrong ECI format | Error |

### 9.3 Network Token Provisioning [#93-network-token-provisioning]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit network token | Accepted |
| 2 | Include cryptogram | Validated |
| 3 | Complete payment | Success |

### 9.4 Network Token - Expired Cryptogram [#94-network-token---expired-cryptogram]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Submit expired cryptogram | Error |
| 2 | Verify handling | Prompts refresh |

## 10. Security & Compliance Tests [#10-security--compliance-tests]

### 10.1 API Key Security [#101-api-key-security]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Check client-side code | Keys not exposed |
| 2 | Check logs | Keys masked |
| 3 | Verify HTTPS only | No HTTP |

### 10.2 Card Data Handling [#102-card-data-handling]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Check logs | Card numbers masked |
| 2 | Check storage | CVV not stored |
| 3 | Check URLs | Card data in POST only |

### 10.3 Token Storage Security [#103-token-storage-security]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Verify encryption | Encrypted at rest |
| 2 | Verify access control | Auth required |
| 3 | Verify UI | Tokens masked |

### 10.4 Webhook Endpoint Security [#104-webhook-endpoint-security]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Verify HTTPS | HTTP rejected |
| 2 | Verify signature | Invalid rejected |
| 3 | Verify timestamp | Old rejected |

### 10.5 Error Message Security [#105-error-message-security]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Check errors | No sensitive data |
| 2 | Check responses | No internal details |
| 3 | Check customer messages | Generic/friendly |

### 10.6 Rate Limiting Handling [#106-rate-limiting-handling]

| Step | Action | Expected Result |
|---|---|---|
| 1 | Exceed rate limits | HTTP 429 |
| 2 | Verify backoff | Implements retry |
| 3 | Verify recovery | Resumes normally |

## Test Cards Reference [#test-cards-reference]

### Success Cards [#success-cards]

| Card Number | Brand | 3DS | Behavior |
|---|---|---|---|
| `4000000000001091` | Visa | Yes | Success with 3DS |
| `4000000000001000` | Visa | No | Success without 3DS |
| `5555555555554444` | Mastercard | Yes | Success |

### Decline Cards [#decline-cards]

| Card Number | Error Code | Description |
|---|---|---|
| `4000000000000002` | do_not_honour | Generic decline |
| `4000000000000069` | expired_card | Expired card |
| `4000000000000127` | cvc_check_failed | Invalid CVC |
| `4000000000000119` | processing_error | Processing error |

### Test CVCs [#test-cvcs]

| CVC | Behavior |
|---|---|
| `123` | Success |
| `000` | Bypass (recurring) |

### Test Expiry [#test-expiry]

Use any future date in MM/YY format. Recommended: `12/28`

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

Before going live, ensure:

- All critical tests passed
- All high-priority tests passed
- Known issues documented and accepted
- Production credentials obtained
- Production webhook URL configured
- Monitoring and alerting configured
- Support contact information documented
