This comprehensive guide covers all payment scenarios, API endpoints, and integration patterns for the Precium Payment API.
All API requests require Bearer token authentication.
Request Format
BASH
curl -X GET "https://gate.reviopay.com/api/v1/endpoint/" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"
API Key Types
| Key Type | Usage |
|---|---|
| Standard API Key | All non-S2S operations |
| S2S API Key | Server-to-server card operations (requires SAQ-D) |
Clients represent your customers. Creating client records enables stored payment methods, pre-filled checkouts, and recurring billing.
Create Client
JSON
POST /api/v1/clients/
Request Body:
JSON
{
"email": "customer@example.com",
"phone": "+27821234567",
"full_name": "John Doe",
"street_address": "123 Main Street",
"city": "Cape Town",
"state": "Western Cape",
"zip_code": "8001",
"country": "ZA",
"shipping_street_address": "123 Main Street",
"shipping_city": "Cape Town",
"shipping_state": "Western Cape",
"shipping_zip_code": "8001",
"shipping_country": "ZA"
}
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
email | string | Yes | Customer email address |
phone | string | No | Phone number (E.164 format) |
full_name | string | No | Customer full name |
personal_code | string | No | ID number (for DebiCheck) |
street_address | string | No | Billing address |
city | string | No | Billing city |
state | string | No | Billing state/province |
zip_code | string | No | Billing postal code |
country | string | No | Billing country (ISO 3166-1 alpha-2) |
bank_account | string | No | Bank account number |
bank_code | string | No | Bank branch/SWIFT code |
cc | array | No | CC email addresses for receipts |
bcc | array | No | BCC email addresses |
Response:
JSON
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"type": "client",
"created_on": 1619740800,
"updated_on": 1619740800,
"email": "customer@example.com",
"phone": "+27821234567",
"full_name": "John Doe"
}
List Clients
JSON
GET /api/v1/clients/
Query Parameters:
| Parameter | Description |
|---|---|
q | Fuzzy search across email, phone, name, etc. |
email | Search by email |
phone | Search by phone |
Get Client
BASH
GET /api/v1/clients/{client_id}/
Update Client
BASH
PUT /api/v1/clients/{client_id}/
Partial Update Client
BASH
PATCH /api/v1/clients/{client_id}/
Delete Client
BASH
DELETE /api/v1/clients/{client_id}/
List Client Recurring Tokens
Retrieve stored payment methods for a client:
BASH
GET /api/v1/clients/{client_id}/recurring_tokens/
Response:
JSON
{
"results": [
{
"id": "tok_abc123...",
"type": "recurring_token",
"payment_method": "visa",
"description": "Visa ending in 1111",
"created_on": 1619740800
}
]
}
Delete Client Token
BASH
DELETE /api/v1/clients/{client_id}/recurring_tokens/{token_id}/
A Purchase represents a payment request. Create a purchase to generate a checkout URL or process a payment.
Create Purchase
BASH
POST /api/v1/purchases/
Full Request Body:
JSON
{
"client_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"purchase": {
"currency": "ZAR",
"language": "en",
"products": [
{
"name": "Product Name",
"price": 10000,
"quantity": "1",
"discount": 0,
"tax_percent": "15",
"category": "electronics"
}
],
"notes": "Special instructions",
"due_strict": false
},
"brand_id": "YOUR_BRAND_ID",
"reference": "INV-2026-0001",
"payment_method_whitelist": ["visa", "mastercard", "ozow"],
"success_redirect": "https://www.example.com/success",
"failure_redirect": "https://www.example.com/failure",
"cancel_redirect": "https://www.example.com/cancel",
"success_callback": "https://www.example.com/callback",
"send_receipt": true,
"force_recurring": false,
"skip_capture": false,
"due": 1735689600
}
Core Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
brand_id | uuid | Yes | Your brand identifier |
purchase.currency | string | Yes | ISO 4217 currency code |
purchase.products | array | Yes | Array of product objects |
purchase.products[].name | string | Yes | Product name |
purchase.products[].price | integer | Yes | Price in cents |
Client Parameters (use client_id OR client object):
| Parameter | Type | Description |
|---|---|---|
client_id | uuid | Existing client ID |
client.email | string | Create/find client by email |
client.phone | string | Client phone |
client.full_name | string | Client name |
Optional Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
reference | string | --- | Your order reference |
payment_method_whitelist | array | all | Allowed payment methods |
success_redirect | string | --- | Redirect URL on success |
failure_redirect | string | --- | Redirect URL on failure |
cancel_redirect | string | --- | Redirect URL on cancel |
success_callback | string | --- | Webhook URL for this purchase |
send_receipt | boolean | false | Email receipt on payment |
force_recurring | boolean | false | Force token storage |
skip_capture | boolean | false | Pre-authorization only |
due | integer | --- | Due date (Unix timestamp) |
purchase.due_strict | boolean | false | Block payment after due date |
purchase.language | string | en | Checkout language |
Response:
JSON
{
"id": "pur_abc123...",
"type": "purchase",
"status": "created",
"created_on": 1619740800,
"checkout_url": "https://gate.reviopay.com/p/abc123.../",
"direct_post_url": "https://gate.reviopay.com/p/abc123.../post/",
"purchase": {
"currency": "ZAR",
"total": 10000,
"products": [...]
},
"brand_id": "YOUR_BRAND_ID",
"reference": "INV-2026-0001"
}
Get Purchase
BASH
GET /api/v1/purchases/{purchase_id}/
List Purchases
BASH
GET /api/v1/purchases/
Charge Purchase
Charge a purchase using a recurring token:
BASH
POST /api/v1/purchases/{purchase_id}/charge/
Request Body:
JSON
{
"recurring_token": "tok_abc123..."
}
Capture Pre-Authorization
Capture funds from a pre-authorized purchase:
BASH
POST /api/v1/purchases/{purchase_id}/capture/
Request Body:
JSON
{
"amount": 10000
}
Release Pre-Authorization
Release held funds without capturing:
BASH
POST /api/v1/purchases/{purchase_id}/release/
Cancel Purchase
BASH
POST /api/v1/purchases/{purchase_id}/cancel/
Resend Invoice
BASH
POST /api/v1/purchases/{purchase_id}/resend_invoice/
Mark as Paid
Manually mark a purchase as paid (for offline payments):
BASH
POST /api/v1/purchases/{purchase_id}/mark_as_paid/
Generate a payment link to send via email or messaging:
BASH
POST /api/v1/purchases/
JSON
{
"client": {
"email": "customer@example.com"
},
"purchase": {
"currency": "ZAR",
"products": [
{
"name": "Invoice #12345",
"price": 150000
}
]
},
"brand_id": "YOUR_BRAND_ID"
}
Share the checkout_url from the response with your customer.
Standard e-commerce integration with redirect:
sequenceDiagram
participant C as Customer
participant M as Your Site
participant P as Precium
C->>M: Click "Pay Now"
M->>P: POST /purchases/
P-->>M: checkout_url
M->>C: Redirect to checkout_url
C->>P: Complete payment
P->>C: Redirect to success_redirect
P->>M: Webhook: purchase.paid
M->>C: Show confirmation
Create Purchase:
JSON
{
"client_id": "existing_client_id",
"purchase": {
"currency": "ZAR",
"products": [
{"name": "Widget", "price": 5000, "quantity": "2"},
{"name": "Shipping", "price": 5000}
]
},
"brand_id": "YOUR_BRAND_ID",
"reference": "ORD-12345",
"payment_method_whitelist": ["visa", "mastercard", "ozow"],
"success_redirect": "https://www.example.com/order/ORD-12345/success",
"failure_redirect": "https://www.example.com/order/ORD-12345/failure",
"cancel_redirect": "https://www.example.com/cart"
}
Reserve funds for later capture (hotels, car rentals):
Step 1: Create Pre-Auth Purchase
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://www.example.com/booking/success",
"failure_redirect": "https://www.example.com/booking/failure"
}
Step 2: Capture When Ready
BASH
POST /api/v1/purchases/{purchase_id}/capture/
JSON
{
"amount": 450000
}
Or Release if Not Needed:
BASH
POST /api/v1/purchases/{purchase_id}/release/
Only allow specific payment methods:
JSON
{
"payment_method_whitelist": ["visa", "mastercard"],
...
}
Available Payment Methods:
| Value | Description |
|---|---|
visa | Visa cards |
mastercard | Mastercard |
maestro | Maestro cards |
ozow | Ozow Instant EFT |
capitec_pay | Capitec Pay |
capitec_pay_recurring | Capitec Pay Recurring |
zapper | Zapper |
debicheck | DebiCheck |
eft | Traditional debit order / EFT collection |
debicheck | Authenticated debit order (DebiCheck) |
Create an invoice that's due by a specific date:
JSON
{
"client_id": "client_uuid",
"purchase": {
"currency": "ZAR",
"due_strict": true,
"products": [
{"name": "Consulting Services", "price": 2500000}
]
},
"brand_id": "YOUR_BRAND_ID",
"due": 1735689600,
"reference": "INV-2026-0042"
}
Setting due_strict: true prevents payment after the due date.
The hosted checkout page is a PCI-compliant payment form hosted by Precium.
After creating a purchase, redirect customers to the checkout_url:
https://gate.reviopay.com/p/{purchase_id}/
Checkout appearance is configured via your Brand settings in the dashboard:
flowchart TD
A[Customer arrives at checkout_url] --> B{Multiple payment methods?}
B -->|Yes| C[Select payment method]
B -->|No| D[Show payment form]
C --> D
D --> E[Enter payment details]
E --> F{3DS Required?}
F -->|Yes| G[Complete 3DS]
F -->|No| H[Process payment]
G --> H
H --> I{Success?}
I -->|Yes| J[Redirect to success_redirect]
I -->|No| K[Redirect to failure_redirect]
Direct Post allows you to create a custom checkout form while keeping card data out of your servers (SAQ A-EP compliance).
direct_post_urldirect_post_url
Important: Direct Post integration requires PCI DSS SAQ A-EP compliance. Contact your account manager before implementing.
HTML
<form method='POST' action='{direct_post_url}'>
<input type='hidden' name='pm' value='visa'>
<input type='text' name='cardholder_name'
maxlength='30' required>
<input type='text' name='card_number'
maxlength='19' required>
<input type='text' name='expires'
placeholder='MM/YY' maxlength='5' required>
<input type='text' name='cvc'
maxlength='4' required>
<input type='checkbox' name='remember_card' value='on'>
<label>Save card for future payments</label>
<button type='submit'>Pay Now</button>
</form>
| Field | Format | Validation |
|---|---|---|
pm | string | Payment method: visa, mastercard, etc. |
cardholder_name | string | Latin letters, space, apostrophe, dot, dash. Max 30 chars |
card_number | string | Digits only, no spaces. Max 19 chars |
expires | string | MM/YY format |
cvc | string | 3-4 digits |
remember_card | string | on to save card |
Capitec Pay:
HTML
<form method='POST' action='{direct_post_url}'>
<input type='hidden' name='pm' value='capitec_pay'>
<input type='hidden' name='capitec_radio' value='mobile_number'>
<input type='text' name='capitec_mobile_number' required>
<input type='hidden' name='accepted_terms' value='on'>
<button type='submit'>Pay with Capitec Pay</button>
</form>
DebiCheck:
HTML
<form method='POST' action='https://gate.reviopay.com/p/{purchase_id}/'>
<input type='hidden' name='pm' value='debicheck'>
<input type='text' name='PayerFirstName' required>
<input type='text' name='PayerLastName' required>
<input type='text' name='PayerPhoneNumber' required>
<input type='hidden' name='PayerIdType' value='idNumber'>
<input type='text' name='PayerdNumber' required>
<input type='text' name='PayerBranchCode' maxlength='6' required>
<input type='text' name='PayerAccountType' value='Current'>
<input type='text' name='PayerAccount' required>
<button type='submit'>Set Up DebiCheck</button>
</form>
Ozow
JSON
s2s:true
pm:ozow
phone:27123456789
To save a payment method for future charges, set force_recurring: true:
JSON
{
"client_id": "client_uuid",
"purchase": {
"currency": "ZAR",
"products": [
{"name": "Initial Payment", "price": 10000}
]
},
"brand_id": "YOUR_BRAND_ID",
"force_recurring": true,
"success_redirect": "https://www.example.com/success"
}
After successful payment, the purchase ID becomes a recurring token.
To tokenize a card without charging:
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://www.example.com/success"
}
Step 1: Create Purchase for Upcoming Charge
BASH
POST /api/v1/purchases/
JSON
{
"client_id": "client_uuid",
"purchase": {
"currency": "ZAR",
"products": [
{"name": "Monthly Subscription", "price": 29900}
]
},
"brand_id": "YOUR_BRAND_ID",
"reference": "SUB-2026-01"
}
Step 2: Charge Using Token
BASH
POST /api/v1/purchases/{new_purchase_id}/charge/
JSON
{
"recurring_token": "{original_purchase_id}"
}
BASH
GET /api/v1/clients/{client_id}/recurring_tokens/
No longer offered. Subscription billing via billing templates is not sold to new integrations. This section is retained for existing implementations only. For recurring charges, use tokenisation and merchant-initiated charges — see Recurring Payments above.
Billing templates automate recurring billing with configurable schedules.
BASH
POST /api/v1/billing_templates/
JSON
{
"title": "Premium Monthly Subscription",
"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",
"number_of_billing_cycles": 12,
"subscription_due_period": 3,
"subscription_due_period_units": "days",
"subscription_trial_periods": 0,
"force_recurring": true,
"success_redirect": "https://www.example.com/subscribe/success",
"failure_redirect": "https://www.example.com/subscribe/failure"
}
Subscription Parameters:
| Parameter | Type | Description |
|---|---|---|
is_subscription | boolean | Enable subscription mode |
subscription_active | boolean | Activate automatic billing |
subscription_period | integer | Billing frequency number |
subscription_period_units | string | days, weeks, months, years |
number_of_billing_cycles | integer | Total billing cycles (0 = infinite) |
subscription_due_period | integer | Days before due date to create invoice |
subscription_trial_periods | integer | Free trial periods |
subscription_charge_period_end | boolean | Charge at end of period |
BASH
POST /api/v1/billing_templates/{template_id}/add_subscriber/
JSON
{
"client_id": "client_uuid",
"invoice_reference": "SUB-CUST-001",
"subscription_confirm_each_order": false,
"send_invoice_on_add_subscriber": false,
"send_invoice_on_charge_failure": true,
"send_receipt": true
}
Response includes:
billing_template_client.id - Subscription IDpurchase.checkout_url - URL for initial tokenizationpurchase.direct_post_url - Direct post URL
Customise pricing for specific subscribers:
JSON
{
"client_id": "client_uuid",
"invoice_reference": "SUB-VIP-001",
"override": {
"products": [
{
"name": "VIP Plan (Discounted)",
"price": 19900
}
]
}
}
BASH
GET /api/v1/billing_templates/
BASH
GET /api/v1/billing_templates/{template_id}/
BASH
GET /api/v1/billing_templates/{template_id}/clients/
BASH
PUT /api/v1/billing_templates/{template_id}/clients/{subscription_id}/
BASH
DELETE /api/v1/billing_templates/{template_id}/clients/{subscription_id}/
BASH
POST /api/v1/purchases/{purchase_id}/refund/
JSON
{}
BASH
POST /api/v1/purchases/{purchase_id}/refund/
JSON
{
"amount": 5000
}
JSON
{
"id": "ref_abc123...",
"type": "refund",
"status": "pending",
"amount": 5000,
"purchase_id": "pur_abc123..."
}
Webhooks notify your application of payment events in real-time.
Subscribe only to the events you act on. Event names are exact — a name that does not appear below will silently never fire.
| Event | Fires when |
|---|---|
purchase.created | A purchase has been created |
purchase.viewed | The payer opened the checkout |
purchase.paid | Payment captured and complete |
purchase.payment_failure | Payment failed |
purchase.cancelled | Purchase cancelled |
purchase.hold | Funds reserved by an authorisation |
purchase.preauthorized | Zero-amount card verification succeeded |
purchase.captured | A hold was captured |
purchase.capture_failure | Capture failed |
purchase.released | A hold was released without capture |
purchase.release_failure | Release failed |
purchase.pending_charge | Authorisation in flight at the acquirer |
purchase.pending_capture | Capture accepted, still processing |
purchase.pending_release | Release accepted, still processing |
purchase.pending_refund | Refund accepted, still processing |
payment.refunded | A refund completed. Treat this as the completion signal |
purchase.refund_failure | Refund failed after acceptance |
payment.charged_back | A chargeback was raised |
payment.chargeback_reversed | A chargeback was reversed in your favour |
purchase.settled | The transaction settled |
purchase.recurring_token_deleted | A stored card token was deleted |
Note that purchase.pending, purchase.authorized, purchase.refunded, subscription.created and subscription.cancelled are not valid event names. Use purchase.pending_charge, purchase.preauthorized and payment.refunded instead.
BASH
POST /api/v1/webhooks/
JSON
{
"url": "https://www.example.com/webhooks/precium",
"events": ["purchase.paid", "purchase.payment_failure", "payment.refunded"]
}
JSON
{
"id": "evt_abc123...",
"event_type": "purchase.paid",
"created_on": 1619740800,
"data": {
"id": "pur_abc123...",
"status": "paid",
"purchase": {
"total": 10000,
"currency": "ZAR"
},
"reference": "ORD-12345",
"payment_method_details": {
"card": {
"brand": "visa",
"last4": "1111"
}
}
}
}
Verify webhook authenticity using the signature header:
PYTHON
import base64
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
# Callbacks are signed with ASYMMETRIC RSA. There is no shared secret.
# X-Signature = base64( RSA PKCS#1 v1.5 over the SHA-256 digest of the raw body )
# webhook subscriptions -> public_key on the webhook object
# per-purchase success_callback -> GET /public_key/
def verify_webhook(raw_body: bytes, signature_b64: str, public_key_pem: str) -> bool:
key = serialization.load_pem_public_key(public_key_pem.encode())
try:
key.verify(
base64.b64decode(signature_b64),
raw_body, # raw bytes; never a re-serialised dict
padding.PKCS1v15(),
hashes.SHA256(),
)
return True
except Exception:
return False
Not currently available. Payouts are not yet released. The endpoints are documented here for reference only — do not build against them, and speak to your account manager before planning a disbursement flow.
Send funds to recipients using stored payment methods.
BASH
POST /api/v1/payouts/
JSON
{
"client": {
"email": "recipient@example.com",
"phone": "+27821234567"
},
"payment": {
"amount": 50000,
"currency": "ZAR",
"description": "Commission Payment"
},
"brand_id": "YOUR_BRAND_ID"
}
BASH
POST {execution_url}
JSON
{
"cardholder_name": "John Doe",
"card_number": "4444333322221111",
"expiry_month": "12",
"expiry_year": "28"
}
BASH
GET /api/v1/payouts/{payout_id}/
| Code | Description |
|---|---|
200 | Success |
201 | Created |
204 | No content (successful deletion) |
400 | Bad request (validation error) |
401 | Unauthorized (invalid API key) |
404 | Not found |
409 | Conflict (duplicate request) |
429 | Rate limited |
500 | Server error |
API requests are rate-limited to ensure fair usage:
Rate limit headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1619740860
List endpoints use cursor-based pagination:
JSON
{
"results": [...],
"next": "https://gate.reviopay.com/api/v1/purchases/?cursor=abc123",
"previous": null
}
Follow the next URL to retrieve additional pages.