Table of contents

Integration quick start

Introduction

Precium's Server-to-Server (S2S) integration provides sophisticated merchants with direct control over the entire payment flow. This integration pattern is designed for organisations that require complete customisation of the payment experience while maintaining the highest security standards.

This documentation is intended for: Payment processors, enterprise merchants, and technical integrators who require direct API access to card data handling.

Who Should Use S2S Integration?

The S2S integration is ideal for:

  • Payment service providers (PSPs) and payment facilitators
  • Enterprise merchants with existing PCI-compliant infrastructure
  • Organisations requiring custom checkout experiences
  • Platforms integrating payments into native mobile applications
  • Businesses with specific regulatory or compliance requirements

PCI Compliance Requirements

Important: S2S integration requires your organisation to maintain PCI DSS Level 1 compliance. This includes:

|Requirement|Description| |---|---| |**SAQ-D**|Annual Self-Assessment Questionnaire Type D completion| |**AoC**|Attestation of Compliance submitted annually| |**RoC**|Report on Compliance from a Qualified Security Assessor (QSA)| |**Quarterly Scans**|ASV (Approved Scanning Vendor) vulnerability scans| |**Penetration Testing**|Annual penetration testing of cardholder data environment|

If your organisation does not currently hold SAQ-D certification, please contact our sales team to discuss our redirect-based integration options that reduce your PCI scope.

Quick Start Checklist

Before beginning your integration, ensure you have:

  • API Credentials: Obtain your Standard API Key and S2S API Key from the Developers section
  • Brand ID: Retrieve your unique Brand ID from your merchant dashboard
  • PCI Documentation: Confirm your SAQ-D AoC is current and on file with Precium
  • Test Environment: Access to sandbox environment credentials
  • Webhook Endpoint: Server endpoint configured to receive payment notifications
  • 3DS Implementation: Plan for 3D Secure challenge handling (required for CIT transactions)

API Base URL

All API requests are made to:

JSON

https://gate.reviopay.com/api/v1/

Authentication

Precium uses Bearer token authentication. Include your API key in the Authorization header of every request:

JSON

Authorization: Bearer <your_api_key>

Token Types:

  • Standard API Key: Used for creating clients and purchases
  • S2S API Key: Used for direct card data submission to the Direct Post URL

Integration Scenarios Overview

Precium S2S supports the following integration scenarios:

|Scenario|3DS|CVV Required|Token|Use Case| |---|---|---|---|---| |**Zero Authorisation (Card Validation)**|Yes|Yes|Optional|Validate card without charging| |**Pre-Authorisation**|Yes|Yes|Optional|Reserve funds for later capture| |**Pre-Authorisation without CVV**|External|No|Yes|Reserve with stored token| |**3DS Execution (Internal)**|Precium-managed|Yes|Optional|Standard CIT with Precium 3DS| |**External MPI**|Merchant-managed|Optional|Optional|Use your own 3DS provider| |**Frictionless (Clear PAN)**|None|Optional|No|Pre-approved non-3DS processing| |**MIT Recurring**|Not required|No|Yes|Subscription/recurring billing|

Scenario Selection Decision Tree

flowchart TD
    A[New Transaction] --> B{Customer Present?}
    B -->|Yes - CIT| C{Transaction Type?}
    B -->|No - MIT| D[Use MIT Recurring Flow]
    C -->|Card Validation| E[Zero Authorization]
    C -->|Reserve Funds| F{Have CVV?}
    C -->|Immediate Charge| G{Have own 3DS?}
    F -->|Yes| H[Pre-Authorization]
    F -->|No| I[Pre-Auth without CVV]
    G -->|No| J{Tokenize?}
    G -->|Yes| K[External MPI Flow]
    J -->|Yes| L[Internal 3DS + Token]
    J -->|No| M{Pre-approved?}
    M -->|Yes| N[Frictionless Flow]
    M -->|No| L

Zero Authorisation (Card Validation)

Zero authorisation validates a card without charging any amount. Use this to verify card details before storing them for future use.

When to Use This Scenario

  • Validating card details during customer registration
  • Verifying card before adding to wallet/stored payment methods
  • Account verification without a financial transaction

Implementation

Set the purchase amount to 0 (zero cents):

Request:

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "d9f8a7b6-c5e4-3d2a-1b0c-9e8d7f6a5b4c",
 "brand_id": "409eb80e-3782-4b1d-afa8-b779759266a5",
 "currency": "ZAR",
 "products": [
   {
     "name": "Card Validation",
     "price": 0
   }
 ],
 "success_redirect": "https://yoursite.com/validation/success",
 "failure_redirect": "https://yoursite.com/validation/failure",
 "force_recurring": true
}

Notes:

  • 3DS is still required for zero-amount authorisations
  • Set force_recurring: true If you want to tokenize the card for future use
  • The card network will validate the card details without any hold on funds

Response

The response follows the same pattern as a standard authorisation. A successful zero-auth confirms:

  • Card number is valid
  • The card is not expired
  • Card passes basic fraud checks

Pre-Authorisation (Auth Only)

Pre-authorisation reserves funds on a cardholder's account without immediate capture. Use this for delayed fulfilment scenarios.

When to Use This Scenario

  • Hotel reservations (charge at checkout)
  • Car rentals (final amount determined at return)
  • E-commerce with delayed shipping
  • Service deposits

Step 1: Create Client

JSON

POST /api/v1/clients/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "email": "customer@example.com",
 "phone": "+27123456789",
 "full_name": "Customer Name",
 "street_address": "1 Long Street",
 "city": "Cape Town",
 "state": "Western Cape",
 "zip_code": "8001",
 "country": "South Africa"
}

Step 2: Create Purchase (Auth-Only)

Create a purchase with the estimated amount. The authorisation will place a hold on the customer's funds.

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Hotel Reservation - 3 Nights",
       "price": 450000
     }
   ]
 },
 "brand_id": "{{brand_id}}",
 "reference": "BOOKING-12345",
 "send_receipt": false,
 "force_recurring": true,
 "success_redirect": "https://yoursite.com/booking/success",
 "failure_redirect": "https://yoursite.com/booking/failure"
}

Step 3: Submit Card Data (Authorisation)

Submit card details to the direct_post_url with browser fingerprint for 3DS:

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "123",
 "remember_card": "on",
 "remote_ip": "196.21.45.123",
 "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)...",
 "accept_header": "text/html",
 "language": "en-US",
 "java_enabled": false,
 "javascript_enabled": true,
 "color_depth": 24,
 "utc_offset": 0,
 "screen_width": 1920,
 "screen_height": 1080
}

Step 4: Handle 3DS (if required)

If the response contains 3ds parameters, redirect the customer to complete authentication.

Step 5: Capture (Full or Partial)

When ready to complete the transaction, capture the authorised amount:

Full Capture:

JSON

POST /api/v1/purchases/{{purchase_id}}/capture/
Authorization: Bearer <standard_api_key>

Partial Capture:

JSON

POST /api/v1/purchases/{{purchase_id}}/capture/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "amount": 400000
}

The amount field specifies the capture amount in cents. You can capture less than or equal to the authorised amount.

Pre-Authorization Void

To release the hold without capturing (e.g., customer cancels):

JSON

POST /api/v1/purchases/{{purchase_id}}/cancel/
Authorization: Bearer <standard_api_key>

Important: Pre-authorisations typically expire after 7-30 days, depending on the card network. Capture before expiration to avoid declined transactions.

Pre-Authorisation without CVV

Use this scenario when you have a stored token and need to pre-authorise without the CVV.

When to Use This Scenario

  • Subsequent authorisations using the stored card token
  • Customer not present, but has previously authorised card storage
  • Recurring pre-authorisations (e.g., monthly car rental reservations)

Implementation

Create a purchase with a token reference and recurring flags:

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Recurring Pre-Authorization",
       "price": 500000
     }
   ],
   "payment_method_details": {
     "card": {
       "is_recurring": true,
       "previous_network_transaction_id": "546464487987132",
       "original_amount_cents": "10000"
     }
   }
 },
 "brand_id": "{{brand_id}}",
 "reference": "PREAUTH-TOKEN-001",
 "send_receipt": false,
 "force_recurring": false
}

Submit to direct_post_url with token (no CVV required):

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "000",
 "remember_card": "off",
 "remote_ip": "8.8.8.8"
}

Note: When using stored credentials, CVV can be set to "000" or any placeholder value.

3DS Execution (Internal - Precium Managed)

This is the standard flow for customer-initiated transactions where Precium handles 3D Secure authentication.

Sequence Diagram

sequenceDiagram
    participant Customer
    participant Merchant
    participant Precium
    participant CardNetwork as Card Network/Issuer

    Note over Merchant,Precium: Step 1: Create Client
    Merchant->>Precium: POST /clients/
    Precium-->>Merchant: Client ID

    Note over Merchant,Precium: Step 2: Create Purchase
    Merchant->>Precium: POST /purchases/
    Precium-->>Merchant: Purchase Object with direct_post_url

    Note over Merchant,Precium: Step 3: Submit Card Data
    Merchant->>Precium: POST to direct_post_url (card details + browser fingerprint)
    Precium-->>Merchant: 3DS Parameters (MD, PaReq, 3DS URL)

    Note over Customer,CardNetwork: Step 4: 3DS Challenge
    Merchant->>Customer: Redirect to 3DS URL
    Customer->>CardNetwork: Complete Authentication
    CardNetwork->>Precium: 3DS Result (callback_url)

    Note over Merchant,Precium: Step 5: Capture Transaction
    Merchant->>Precium: POST /purchases/{id}/capture/ (via callback)
    Precium->>CardNetwork: Capture Request
    CardNetwork-->>Precium: Capture Response
    Precium-->>Merchant: Transaction Result + Token

Step-by-Step Implementation

Step 1: Create Client

JSON

POST /api/v1/clients/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "email": "customer@example.com",
 "phone": "+27123456789",
 "full_name": "Customer Name",
 "street_address": "1 Long Street",
 "city": "Cape Town",
 "state": "Western Cape",
 "zip_code": "8001",
 "country": "South Africa"
}

Step 2: Create Purchase

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Premium Subscription",
       "price": 29900
     }
   ]
 },
 "brand_id": "{{brand_id}}",
 "reference": "ORDER-12345",
 "send_receipt": false,
 "force_recurring": true,
 "success_redirect": "https://yoursite.com/payment/success",
 "failure_redirect": "https://yoursite.com/payment/failure",
 "cancel_redirect": "https://yoursite.com/payment/cancel"
}

Step 3: Submit Card Data (Authorisation)

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "123",
 "remember_card": "on",
 "remote_ip": "196.21.45.123",
 "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
 "accept_header": "text/html",
 "language": "en-US",
 "java_enabled": false,
 "javascript_enabled": true,
 "color_depth": 24,
 "utc_offset": 0,
 "screen_width": 1920,
 "screen_height": 1080
}

Response (3DS Required):

JSON

{
 "md": "abc123xyz789...",
 "PaReq": "eJxVUt1ugjAUvvcpSO...",
 "URL": "https://acs.cardnetwork.com/3ds/challenge",
 "callback_url": "https://gate.reviopay.com/3ds/callback/a1b2c3d4..."
}

Step 4: Handle 3DS Challenge

Create an HTML form that auto-submits to the 3DS URL:

HTML

<form id="3ds-form" action="{{URL}}" method="POST">
 <input type="hidden" name="MD" value="{{md}}" />
 <input type="hidden" name="PaReq" value="{{PaReq}}" />
 <input type="hidden" name="TermUrl" value="{{callback_url}}" />
 <noscript>
   <button type="submit">Continue to Bank Verification</button>
 </noscript>
</form>
<script>document.getElementById('3ds-form').submit();</script>

Step 5: Capture (After 3DS Completion)

After the customer completes 3DS, submit the callback to capture:

JSON

POST {{callback_url}}
Content-Type: application/x-www-form-urlencoded

MD={{MD}}&PaRes={{PaRes}}

Success Response:

JSON

{
 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
 "status": "paid",
 "transaction_id": "txn_9876543210",
 "payment_method_details": {
   "card": {
     "brand": "visa",
     "last_4": "1091",
     "exp_month": 12,
     "exp_year": 2028,
     "token": "tok_abc123def456...",
     "network_transaction_id": "MCC123456789012345"
   }
 }
}

External MPI (External 3DS Provider)

Use this flow when you have your own 3D Secure Merchant Plug-In (MPI) from providers like Cardinal Commerce, Netcetera, or similar.

When to Use This Scenario

  • You have an existing 3DS solution certified for your card networks
  • You require a specific 3DS configuration or branding
  • You need to consolidate 3DS authentication across multiple acquirers

Implementation

Include 3DS authentication results in the purchase creation:

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Once off charge",
       "price": 50000
     }
   ],
   "payment_method_details": {
     "card": {
       "is_external_3DS": true,
       "authentication_transaction_id": "GAux5DosxbhI35RL8nc0",
       "cavv": "AAABBBCCCdddEEEfff111222333=",
       "xid": "xidTestValue",
       "eci_raw": "05"
     }
   }
 },
 "brand_id": "{{brand_id}}",
 "reference": "EXT3DS-ORDER-001",
 "send_receipt": false,
 "force_recurring": false,
 "success_redirect": "https://yoursite.com/success",
 "failure_redirect": "https://yoursite.com/failure"
}

External 3DS Fields:

|Field|Type|Required|Description| |---|---|---|---| |`is_external_3DS`|boolean|Yes|Must be `true` for external MPI| |`authentication_transaction_id`|string|Yes|Your MPI's transaction ID| |`cavv`|string|Yes|Cardholder Authentication Verification Value| |`xid`|string|3DS1|Transaction identifier (3DS1 only)| |`eci_raw`|string|Yes|Electronic Commerce Indicator|

ECI Values Reference:

|ECI|Meaning|Liability Shift| |---|---|---| |05|Fully authenticated (Visa)|Yes| |02|Fully authenticated (Mastercard)|Yes| |06|Attempted authentication (Visa)|Conditional| |01|Attempted authentication (Mastercard)|Conditional| |07|Non-3DS or failed (Visa)|No| |00|Non-3DS or failed (Mastercard)|No|

Submit Card Data

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "000",
 "remember_card": "off",
 "remote_ip": "8.8.8.8",
 "user_agent": "Mozilla/5.0...",
 "accept_header": "text/html",
 "language": "en-US",
 "java_enabled": false,
 "javascript_enabled": true,
 "color_depth": 24,
 "utc_offset": 0,
 "screen_width": 1920,
 "screen_height": 1080
}

Note: This must be performed on a Non-3DS brand - contact your account manager to configure.

External Network Token Provisioning

Use external network tokens (MDES/VTS) for enhanced security and improved authorisation rates.

When to Use This Scenario

  • You provision tokens directly from Visa Token Service (VTS) or Mastercard Digital Enablement Service (MDES)
  • You want to leverage network-level tokenization benefits
  • You need to maintain the token lifecycle independently

Implementation

Include the network token and cryptogram in your purchase:

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Network Token Purchase",
       "price": 25000
     }
   ],
   "payment_method_details": {
     "card": {
       "network_token": "4895370012341234",
       "network_token_cryptogram": "AgAAAAAABk4DWZ4C28yUQAAAAAA=",
       "token_requestor_id": "50110030273",
       "is_recurring": true
     }
   }
 },
 "brand_id": "{{brand_id}}",
 "reference": "NETWORK-TOKEN-001"
}

Network Token Fields:

|Field|Type|Required|Description| |---|---|---|---| |`network_token`|string|Yes|The network token (DPAN)| |`network_token_cryptogram`|string|Yes|Dynamic cryptogram from token service| |`token_requestor_id`|string|Yes|Your registered Token Requestor ID|

Frictionless (Clear PAN Processing - No 3DS)

This flow bypasses 3D Secure authentication entirely. Pre-approval from Precium is required.

When to Use This Scenario

  • Low-value transactions within approved thresholds
  • Markets where 3DS adoption is limited
  • Specific merchant categories with pre-negotiated exemptions
  • Testing and development environments

Risk and Liability Warning

Transactions processed without 3DS authentication:

  • Do not receive liability shift protection
  • Have higher chargeback exposure
  • May have higher decline rates from issuers
  • Are subject to monitoring and may be disabled if fraud rates exceed thresholds

Note: This flow is technically not permitted in South Africa due to 3DS requirements. The first charge must always be performed with 3DS; subsequent recurring charges can be processed without 3DS.

Implementation

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Frictionless charge",
       "price": 5000
     }
   ]
 },
 "brand_id": "{{brand_id}}",
 "reference": "FRICTIONLESS-001",
 "send_receipt": false,
 "force_recurring": false,
 "success_redirect": "https://yoursite.com/success",
 "failure_redirect": "https://yoursite.com/failure"
}

Submit card data without browser fingerprint:

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "000",
 "remember_card": "off",
 "remote_ip": "8.8.8.8"
}

The response will indicate ready for charge without 3DS parameters.

MIT Recurring (Merchant-Initiated Transactions)

MIT transactions are used for recurring charges where the cardholder is not present.

When to Use This Scenario

  • Subscription billing cycles
  • Recurring membership fees
  • Instalment payment plans
  • Variable-amount recurring charges (utilities, usage-based billing)

Prerequisites

To process MIT transactions, you must have:

  1. Stored Token: Card token from an initial CIT transaction with force_recurring: true
  2. Network Transaction ID: The network_transaction_id from the original transaction
  3. Original Amount: The original_amount_cents from the tokenization transaction
  4. Customer Consent: Documented authorisation for recurring charges

Implementation

JSON

POST /api/v1/purchases/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "client_id": "{{client_id}}",
 "payment_method_whitelist": ["visa", "mastercard", "maestro"],
 "purchase": {
   "currency": "ZAR",
   "language": "en",
   "products": [
     {
       "name": "Monthly Subscription - February 2026",
       "price": 29900
     }
   ],
   "payment_method_details": {
     "card": {
       "is_recurring": true,
       "previous_network_transaction_id": "546464487987132",
       "original_amount_cents": "10000"
     }
   }
 },
 "brand_id": "{{brand_id}}",
 "reference": "SUB-FEB-2026",
 "send_receipt": false,
 "force_recurring": false,
 "success_redirect": "https://yoursite.com/success",
 "failure_redirect": "https://yoursite.com/failure"
}

Submit with token:

JSON

POST {{direct_post_url}}?s2s=true
Authorization: Bearer <s2s_api_key>
Content-Type: application/json

{
 "cardholder_name": "John Smith",
 "card_number": "4000000000001091",
 "expires": "12/28",
 "cvc": "000",
 "remember_card": "off",
 "remote_ip": "8.8.8.8"
}

Charge using the recurring token:

JSON

POST /api/v1/purchases/{{purchase_id}}/charge/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "recurring_token": "{{original_purchase_id}}"
}

Partial Captures

Capture less than the authorised amount when the final charge is lower than the pre-authorisation.

When to Use

  • Customer modifies order after authorisation
  • Partial fulfilment scenarios
  • Final charge is less than estimated

Implementation

JSON

POST /api/v1/purchases/{{purchase_id}}/capture/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "amount": 35000
}

Notes:

  • The amount must be less than or equal to the authorised amount
  • Once captured, you cannot capture additional amounts
  • The remaining authorisation is automatically released

Capture Void (Before Settlement)

Cancel a capture before settlement to avoid processing fees and to release funds immediately.

When to Use

  • Customer cancels order after capture but before settlement
  • Capture made in error
  • Immediate reversal needed

Implementation

JSON

POST /api/v1/purchases/{{purchase_id}}/cancel/
Authorization: Bearer <standard_api_key>

Response:

JSON

{
 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
 "status": "cancelled",
 "cancelled_on": "2026-01-13T14:30:00Z"
}

Notes:

  • Only available before settlement (typically same day)
  • After the settlement, use the refund method instead
  • Void releases the hold immediately on most issuing banks

Partial Refunds

Refund a portion of a settled transaction.

Implementation

JSON

POST /api/v1/purchases/{{purchase_id}}/refund/
Authorization: Bearer <standard_api_key>
Content-Type: application/json

{
 "amount": 15000
}

Notes:

  • amount is in cents (15000 = R150.00)
  • Multiple partial refunds can be processed until the original total is reached
  • Each refund generates a separate refund_id

Response

JSON

{
 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
 "status": "refunded",
 "refund_amount": 15000,
 "refunded_on": "2026-01-14T15:30:00Z",
 "refund_id": "ref_xyz789abc123"
}

Refund Void (Before Settlement)

Cancel a refund before settlement.

When to Use

  • Refund issued in error
  • Customer changes mind before refund settles
  • Immediate reversal of refund needed

Implementation

JSON

POST /api/v1/purchases/{{purchase_id}}/refund/{{refund_id}}/cancel/
Authorization: Bearer <standard_api_key>

Notes:

  • Only available before refund settlement
  • After settlement, you would need to process a new charge (with customer consent)

Settlement Timing Reference

|Action|Before Settlement|After Settlement| |---|---|---| |Cancel Authorization|✅ Void|❌ Not possible| |Cancel Capture|✅ Void|❌ Use refund| |Cancel Refund|✅ Void|❌ Requires new charge| |Partial Capture|✅ Supported|❌ Already settled| |Partial Refund|N/A|✅ Supported|

Settlement typically occurs:

  • Same-day for most transactions
  • Next business day for late transactions
  • Check with your account manager for specific settlement windows

Webhooks

Configure webhooks to receive real-time notifications of transaction events.

Webhook Events

|Event|Description| |---|---| |`purchase.paid`|Transaction successfully completed| |`purchase.payment_failure`|Transaction failed| |`purchase.refunded`|Refund processed| |`purchase.pending`|Transaction pending 3DS or manual review| |`purchase.cancelled`|Transaction cancelled/voided| |`purchase.authorized`|Pre-authorization completed| |`purchase.captured`|Capture completed|

Webhook Payload Structure

JSON

{
 "event": "purchase.paid",
 "timestamp": "2026-01-13T10:35:12Z",
 "data": {
   "purchase_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
   "status": "paid",
   "amount": 29900,
   "currency": "ZAR",
   "client_id": "d9f8a7b6-c5e4-3d2a-1b0c-9e8d7f6a5b4c",
   "payment_method": {
     "type": "card",
     "brand": "visa",
     "last_4": "1091"
   }
 }
}

Webhook Best Practices

  1. Respond quickly: Return HTTP 200 within 5 seconds
  2. Process asynchronously: Queue webhook data for processing
  3. Implement idempotency: Handle duplicate deliveries gracefully
  4. Verify signatures: Validate webhook authenticity (if signature header provided)
  5. Retry handling: Webhooks retry on failure with exponential backoff

Testing

Test Card Numbers

|Card Number|Behavior| |---|---| |`4000000000001091`|Successful payment with 3DS| |`4000000000001000`|Successful payment, no 3DS| |`5555555555554444`|Mastercard success| |`4000000000000002`|Card declined| |`4000000000000069`|Expired card| |`4000000000000127`|Incorrect CVC| |`4000000000000119`|Processing error|

Test CVCs

|CVC|Behavior| |---|---| |`123`|Successful verification| |`000`|Bypass CVC (for recurring/tokenized)|

Next Steps

  • Error Codes Reference - Complete error code documentation
  • Code Examples - Implementation examples in multiple languages
  • Glossary - Payment terminology definitions
  • Troubleshooting - Common issues and solutions