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:
PCI Compliance Requirements
Important: S2S integration requires your organisation to maintain PCI DSS Level 1 compliance. This includes:
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.
Before beginning your integration, ensure you have:
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:
Precium S2S supports the following integration scenarios:
Scenario Selection Decision Tree
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
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:
force_recurring: true If you want to tokenize the card for future use
Response
The response follows the same pattern as a standard authorisation. A successful zero-auth confirms:
Pre-authorisation reserves funds on a cardholder's account without immediate capture. Use this for delayed fulfilment scenarios.
When to Use This Scenario
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.
Use this scenario when you have a stored token and need to pre-authorise without the CVV.
When to Use This Scenario
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.
This is the standard flow for customer-initiated transactions where Precium handles 3D Secure authentication.
Sequence Diagram
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"
}
}
}
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
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:
ECI Values Reference:
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.
Use external network tokens (MDES/VTS) for enhanced security and improved authorisation rates.
When to Use This Scenario
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:
This flow bypasses 3D Secure authentication entirely. Pre-approval from Precium is required.
When to Use This Scenario
Risk and Liability Warning
Transactions processed without 3DS authentication:
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 transactions are used for recurring charges where the cardholder is not present.
When to Use This Scenario
Prerequisites
To process MIT transactions, you must have:
force_recurring: truenetwork_transaction_id from the original transactionoriginal_amount_cents from the tokenization transaction
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}}"
}
Capture less than the authorised amount when the final charge is lower than the pre-authorisation.
When to Use
Implementation
JSON
POST /api/v1/purchases/{{purchase_id}}/capture/
Authorization: Bearer <standard_api_key>
Content-Type: application/json
{
"amount": 35000
}
Notes:
amount must be less than or equal to the authorised amount
Cancel a capture before settlement to avoid processing fees and to release funds immediately.
When to Use
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:
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)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"
}
Cancel a refund before settlement.
When to Use
Implementation
JSON
POST /api/v1/purchases/{{purchase_id}}/refund/{{refund_id}}/cancel/
Authorization: Bearer <standard_api_key>
Notes:
Settlement typically occurs:
Configure webhooks to receive real-time notifications of transaction events.
Webhook Events
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
Test Card Numbers
Test CVCs
Next Steps