This document provides production-ready code examples in multiple programming languages for integrating with Precium's Server-to-Server API.
Installation
BASH
pip install requests
Complete Integration Class
PYTHON
"""
Precium S2S Integration - Python
Requires: requests
"""
import requests
from typing import Optional, Dict, Any
from dataclasses import dataclass
from enum import Enum
import json
class PreciumEnvironment(Enum):
SANDBOX = "https://gate.reviopay.com/api/v1"
PRODUCTION = "https://gate.reviopay.com/api/v1"
@dataclass
class CardData:
cardholder_name: str
card_number: str
expires: str # MM/YY format
cvc: str
remote_ip: str
@dataclass
class BrowserFingerprint:
user_agent: str
accept_header: str
language: str
java_enabled: bool
javascript_enabled: bool
color_depth: int
utc_offset: int
screen_width: int
screen_height: int
class PreciumS2SClient:
"""Precium Server-to-Server API Client"""
def __init__(
self,
standard_api_key: str,
s2s_api_key: str,
brand_id: str,
environment: PreciumEnvironment = PreciumEnvironment.SANDBOX
):
self.standard_api_key = standard_api_key
self.s2s_api_key = s2s_api_key
self.brand_id = brand_id
self.base_url = environment.value
def _headers(self, use_s2s: bool = False) -> Dict[str, str]:
"""Generate request headers with appropriate API key."""
api_key = self.s2s_api_key if use_s2s else self.standard_api_key
return {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"Accept": "application/json"
}
def _request(
self,
method: str,
endpoint: str,
data: Optional[Dict] = None,
use_s2s: bool = False
) -> Dict[str, Any]:
"""Make an API request."""
url = f"{self.base_url}{endpoint}"
response = requests.request(
method=method,
url=url,
headers=self._headers(use_s2s),
json=data
)
response.raise_for_status()
return response.json()
# =========================================================================
# Client Management
# =========================================================================
def create_client(self, email: str, phone: Optional[str] = None) -> Dict:
"""
Create a new client record.
Args:
email: Customer's email address
phone: Optional phone number in international format
Returns:
Client object with ID
"""
payload = {"email": email}
if phone:
payload["phone"] = phone
return self._request("POST", "/clients/", payload)
def get_client(self, client_id: str) -> Dict:
"""Retrieve a client by ID."""
return self._request("GET", f"/clients/{client_id}/")
# =========================================================================
# Purchase Management
# =========================================================================
def create_purchase(
self,
client_id: str,
amount_cents: int,
currency: str,
product_name: str,
success_redirect: str,
failure_redirect: str,
force_recurring: bool = False,
metadata: Optional[Dict] = None
) -> Dict:
"""
Create a new purchase.
Args:
client_id: The client's ID
amount_cents: Amount in cents (e.g., 29900 for R299.00)
currency: ISO 4217 currency code (e.g., "ZAR")
product_name: Description of the product/service
success_redirect: URL for successful payment redirect
failure_redirect: URL for failed payment redirect
force_recurring: Set True to generate token for future MIT
metadata: Optional custom key-value data
Returns:
Purchase object with direct_post_url
"""
payload = {
"client_id": client_id,
"brand_id": self.brand_id,
"currency": currency,
"products": [{"name": product_name, "price": amount_cents}],
"success_redirect": success_redirect,
"failure_redirect": failure_redirect,
}
if force_recurring:
payload["force_recurring"] = True
if metadata:
payload["metadata"] = metadata
return self._request("POST", "/purchases/", payload)
def create_mit_purchase(
self,
client_id: str,
amount_cents: int,
currency: str,
product_name: str,
card_token: str,
network_transaction_id: str,
original_amount_cents: int
) -> Dict:
"""
Create a purchase for Merchant-Initiated Transaction (recurring).
Args:
client_id: The client's ID
amount_cents: Amount in cents
currency: ISO 4217 currency code
product_name: Description of the charge
card_token: Token from original CIT transaction
network_transaction_id: Network transaction ID from original
original_amount_cents: Amount from original tokenization
Returns:
Purchase object ready for MIT charge
"""
payload = {
"client_id": client_id,
"brand_id": self.brand_id,
"currency": currency,
"products": [{"name": product_name, "price": amount_cents}],
"payment_method_details": {
"card_token": card_token,
"previous_network_transaction_id": network_transaction_id,
"original_amount_cents": original_amount_cents
},
"is_recurring": True
}
return self._request("POST", "/purchases/", payload)
def get_purchase(self, purchase_id: str) -> Dict:
"""Retrieve purchase details by ID."""
return self._request("GET", f"/purchases/{purchase_id}/")
# =========================================================================
# Card Data Submission (Direct Post)
# =========================================================================
def submit_card_data(
self,
direct_post_url: str,
card: CardData,
fingerprint: BrowserFingerprint,
remember_card: bool = False
) -> Dict:
"""
Submit card data to the direct post URL.
This method handles the S2S card submission for CIT with internal 3DS.
Args:
direct_post_url: The URL from purchase creation
card: Card details
fingerprint: Browser fingerprint data for 3DS
remember_card: Whether to tokenize the card
Returns:
Response containing 3DS parameters or ready status
"""
payload = {
"cardholder_name": card.cardholder_name,
"card_number": card.card_number,
"expires": card.expires,
"cvc": card.cvc,
"remember_card": str(remember_card).lower(),
"remote_ip": card.remote_ip,
"user_agent": fingerprint.user_agent,
"accept_header": fingerprint.accept_header,
"language": fingerprint.language,
"java_enabled": str(fingerprint.java_enabled).lower(),
"javascript_enabled": str(fingerprint.javascript_enabled).lower(),
"color_depth": str(fingerprint.color_depth),
"utc_offset": str(fingerprint.utc_offset),
"screen_width": str(fingerprint.screen_width),
"screen_height": str(fingerprint.screen_height),
}
headers = {
"Authorization": f"Bearer {self.s2s_api_key}",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(
direct_post_url,
headers=headers,
data=payload
)
response.raise_for_status()
return response.json()
def submit_token_for_mit(
self,
direct_post_url: str,
card_token: str,
server_ip: str
) -> Dict:
"""
Submit token for MIT transaction.
Args:
direct_post_url: The URL from MIT purchase creation
card_token: The stored card token
server_ip: Your server's IP address
Returns:
Response indicating ready for charge
"""
payload = {
"card_token": card_token,
"remote_ip": server_ip
}
headers = {
"Authorization": f"Bearer {self.s2s_api_key}",
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(
direct_post_url,
headers=headers,
data=payload
)
response.raise_for_status()
return response.json()
# =========================================================================
# Charge and Refund
# =========================================================================
def charge_purchase(self, purchase_id: str) -> Dict:
"""
Finalize the transaction and charge the card.
Call this after 3DS completion or for MIT transactions.
Args:
purchase_id: The purchase ID to charge
Returns:
Transaction result with payment details and token
"""
return self._request("POST", f"/purchases/{purchase_id}/charge/")
def refund_purchase(
self,
purchase_id: str,
amount_cents: Optional[int] = None
) -> Dict:
"""
Process a refund for a purchase.
Args:
purchase_id: The purchase ID to refund
amount_cents: Amount to refund in cents (None for full refund)
Returns:
Refund confirmation
"""
payload = {}
if amount_cents:
payload["amount"] = amount_cents
return self._request("POST", f"/purchases/{purchase_id}/refund/", payload)
# =========================================================================
# Pre-Authorization Operations
# =========================================================================
def capture_purchase(
self,
purchase_id: str,
amount_cents: Optional[int] = None
) -> Dict:
"""
Capture a pre-authorized transaction.
Args:
purchase_id: The purchase ID to capture
amount_cents: Amount to capture in cents (None for full capture)
Returns:
Capture confirmation
"""
payload = {}
if amount_cents:
payload["amount"] = amount_cents
return self._request("POST", f"/purchases/{purchase_id}/capture/", payload)
def void_purchase(self, purchase_id: str) -> Dict:
"""
Void/cancel a pre-authorized or captured transaction (before settlement).
Args:
purchase_id: The purchase ID to void
Returns:
Void confirmation
"""
return self._request("POST", f"/purchases/{purchase_id}/cancel/")
def void_refund(self, purchase_id: str, refund_id: str) -> Dict:
"""
Void a refund before settlement.
Args:
purchase_id: The original purchase ID
refund_id: The refund ID to void
Returns:
Void confirmation
"""
return self._request("POST", f"/purchases/{purchase_id}/refund/{refund_id}/cancel/")
# =========================================================================
# Zero Authorization (Card Validation)
# =========================================================================
def create_zero_auth_purchase(
self,
client_id: str,
currency: str,
success_redirect: str,
failure_redirect: str,
force_recurring: bool = True
) -> Dict:
"""
Create a zero-amount authorization for card validation.
Args:
client_id: The client's ID
currency: ISO 4217 currency code
success_redirect: URL for successful validation
failure_redirect: URL for failed validation
force_recurring: Set True to tokenize the card
Returns:
Purchase object for zero authorization
"""
payload = {
"client_id": client_id,
"brand_id": self.brand_id,
"currency": currency,
"products": [{"name": "Card Validation", "price": 0}],
"success_redirect": success_redirect,
"failure_redirect": failure_redirect,
}
if force_recurring:
payload["force_recurring"] = True
return self._request("POST", "/purchases/", payload)
# =========================================================================
# External 3DS (MPI)
# =========================================================================
def create_external_3ds_purchase(
self,
client_id: str,
amount_cents: int,
currency: str,
product_name: str,
success_redirect: str,
failure_redirect: str,
authentication_transaction_id: str,
cavv: str,
eci: str,
xid: Optional[str] = None,
ds_trans_id: Optional[str] = None
) -> Dict:
"""
Create a purchase with external 3DS authentication.
Args:
client_id: The client's ID
amount_cents: Amount in cents
currency: ISO 4217 currency code
product_name: Description of product/service
success_redirect: URL for successful payment
failure_redirect: URL for failed payment
authentication_transaction_id: Your MPI's transaction ID
cavv: Cardholder Authentication Verification Value
eci: Electronic Commerce Indicator
xid: Transaction ID (3DS1 only)
ds_trans_id: Directory Server Transaction ID (3DS2 only)
Returns:
Purchase object with direct_post_url
"""
payment_details = {
"card": {
"is_external_3DS": True,
"authentication_transaction_id": authentication_transaction_id,
"cavv": cavv,
"eci_raw": eci
}
}
if xid:
payment_details["card"]["xid"] = xid
if ds_trans_id:
payment_details["card"]["ds_trans_id"] = ds_trans_id
payload = {
"client_id": client_id,
"brand_id": self.brand_id,
"currency": currency,
"products": [{"name": product_name, "price": amount_cents}],
"payment_method_details": payment_details,
"success_redirect": success_redirect,
"failure_redirect": failure_redirect,
}
return self._request("POST", "/purchases/", payload)
# =============================================================================
# Usage Examples
# =============================================================================
def example_cit_with_internal_3ds():
"""Example: Customer-Initiated Transaction with Internal 3DS"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id"
)
# Step 1: Create client
customer = client.create_client(email="customer@example.com")
print(f"Created client: {customer['id']}")
# Step 2: Create purchase
purchase = client.create_purchase(
client_id=customer['id'],
amount_cents=29900,
currency="ZAR",
product_name="Premium Subscription",
success_redirect="https://yoursite.com/success",
failure_redirect="https://yoursite.com/failure",
force_recurring=True # Generate token for future recurring
)
print(f"Created purchase: {purchase['id']}")
print(f"Direct post URL: {purchase['direct_post_url']}")
# Step 3: Submit card data
card = CardData(
cardholder_name="John Smith",
card_number="4000000000001091",
expires="12/28",
cvc="123",
remote_ip="196.21.45.123"
)
fingerprint = BrowserFingerprint(
user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
accept_header="text/html,application/xhtml+xml",
language="en-ZA",
java_enabled=False,
javascript_enabled=True,
color_depth=24,
utc_offset=-120,
screen_width=1920,
screen_height=1080
)
result = client.submit_card_data(
direct_post_url=purchase['direct_post_url'],
card=card,
fingerprint=fingerprint,
remember_card=True
)
# Step 4: Handle 3DS (in production, redirect customer)
if '3ds' in result:
print("3DS authentication required")
print(f"3DS URL: {result['3ds']['3ds_url']}")
print(f"MD: {result['3ds']['MD']}")
# Redirect customer to 3DS URL...
# Step 5: After 3DS completion, charge
charge_result = client.charge_purchase(purchase['id'])
print(f"Charge result: {charge_result['status']}")
if charge_result['status'] == 'paid':
# Store token for future MIT
token = charge_result['payment_method_details']['card']['token']
network_txn_id = charge_result['payment_method_details']['card']['network_transaction_id']
print(f"Token for recurring: {token}")
print(f"Network Transaction ID: {network_txn_id}")
def example_mit_recurring():
"""Example: Merchant-Initiated Recurring Transaction"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id"
)
# Stored from original CIT transaction
stored_token = "tok_abc123def456..."
stored_network_txn_id = "MCC123456789012345"
original_amount = 29900
# Create MIT purchase
purchase = client.create_mit_purchase(
client_id="existing_client_id",
amount_cents=29900,
currency="ZAR",
product_name="Monthly Subscription - February 2026",
card_token=stored_token,
network_transaction_id=stored_network_txn_id,
original_amount_cents=original_amount
)
# Submit token
client.submit_token_for_mit(
direct_post_url=purchase['direct_post_url'],
card_token=stored_token,
server_ip="10.0.0.1" # Your server IP
)
# Charge
result = client.charge_purchase(purchase['id'])
print(f"MIT charge result: {result['status']}")
def example_zero_authorization():
"""Example: Zero Authorization for Card Validation"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id"
)
# Create client
customer = client.create_client(email="customer@example.com")
# Create zero-amount purchase for card validation
purchase = client.create_zero_auth_purchase(
client_id=customer['id'],
currency="ZAR",
success_redirect="https://yoursite.com/validation/success",
failure_redirect="https://yoursite.com/validation/failure",
force_recurring=True # Tokenize for future use
)
print(f"Zero auth purchase: {purchase['id']}")
# Submit card data (same as standard flow)
card = CardData(
cardholder_name="John Smith",
card_number="4000000000001091",
expires="12/28",
cvc="123",
remote_ip="196.21.45.123"
)
fingerprint = BrowserFingerprint(
user_agent="Mozilla/5.0",
accept_header="text/html",
language="en-ZA",
java_enabled=False,
javascript_enabled=True,
color_depth=24,
utc_offset=-120,
screen_width=1920,
screen_height=1080
)
result = client.submit_card_data(
direct_post_url=purchase['direct_post_url'],
card=card,
fingerprint=fingerprint,
remember_card=True
)
# Handle 3DS if required, then charge to validate
# Card is validated without any charge
def example_pre_authorization():
"""Example: Pre-Authorization with Later Capture"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id"
)
# Create client
customer = client.create_client(email="guest@hotel.com")
# Pre-authorize for hotel stay (estimated amount)
purchase = client.create_purchase(
client_id=customer['id'],
amount_cents=500000, # R5,000 estimated
currency="ZAR",
product_name="Hotel Stay - 3 nights (estimated)",
success_redirect="https://hotel.com/booking/confirmed",
failure_redirect="https://hotel.com/booking/failed",
force_recurring=False
)
# Submit card data and complete 3DS (same as standard flow)
# ... card submission code ...
# Later: Guest checks out, actual bill is R4,500
# Partial capture
capture_result = client.capture_purchase(
purchase_id=purchase['id'],
amount_cents=450000 # Capture only R4,500
)
print(f"Captured: {capture_result['status']}")
# Alternative: Guest cancels before checkout
# Void the pre-authorization
# void_result = client.void_purchase(purchase['id'])
# print(f"Voided: {void_result['status']}")
def example_partial_refund():
"""Example: Partial Refund Flow"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id"
)
# Assume we have a completed purchase
purchase_id = "existing_paid_purchase_id"
# Customer returns one item worth R100
refund_result = client.refund_purchase(
purchase_id=purchase_id,
amount_cents=10000 # R100 partial refund
)
print(f"Partial refund: {refund_result['status']}")
print(f"Refund ID: {refund_result.get('refund_id')}")
# Can issue multiple partial refunds up to original amount
def example_external_3ds():
"""Example: External 3DS (MPI) Flow"""
client = PreciumS2SClient(
standard_api_key="your_standard_api_key",
s2s_api_key="your_s2s_api_key",
brand_id="your_brand_id" # Must be Non-3DS brand
)
# Create client
customer = client.create_client(email="customer@example.com")
# After completing 3DS with your MPI, create purchase with auth data
purchase = client.create_external_3ds_purchase(
client_id=customer['id'],
amount_cents=50000,
currency="ZAR",
product_name="External 3DS Purchase",
success_redirect="https://yoursite.com/success",
failure_redirect="https://yoursite.com/failure",
authentication_transaction_id="GAux5DosxbhI35RL8nc0",
cavv="AAABBBCCCdddEEEfff111222333=",
eci="05",
ds_trans_id="a1b2c3d4-e5f6-7890-abcd-ef1234567890" # 3DS2
)
# Submit card data (no browser fingerprint needed)
card = CardData(
cardholder_name="John Smith",
card_number="4000000000001091",
expires="12/28",
cvc="000", # Can use placeholder for external 3DS
remote_ip="8.8.8.8"
)
# ... submit card and charge ...
if __name__ == "__main__":
example_cit_with_internal_3ds()
Installation
BASH
npm install axios
Complete Integration Module
JSX
/**
* Precium S2S Integration - Node.js
* Requires: axios
*/
const axios = require('axios');
const ENVIRONMENTS = {
SANDBOX: 'https://gate.reviopay.com/api/v1',
PRODUCTION: 'https://gate.reviopay.com/api/v1'
};
class PreciumS2SClient {
/**
* Initialize the Precium S2S client
* @param {Object} config Configuration object
* @param {string} config.standardApiKey Standard API key for general requests
* @param {string} config.s2sApiKey S2S API key for card data submission
* @param {string} config.brandId Your brand ID
* @param {string} [config.environment='SANDBOX'] Environment to use
*/
constructor({ standardApiKey, s2sApiKey, brandId, environment = 'SANDBOX' }) {
this.standardApiKey = standardApiKey;
this.s2sApiKey = s2sApiKey;
this.brandId = brandId;
this.baseUrl = ENVIRONMENTS[environment];
}
/**
* Get headers for API requests
* @private
*/
_getHeaders(useS2S = false) {
const apiKey = useS2S ? this.s2sApiKey : this.standardApiKey;
return {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
};
}
/**
* Make an API request
* @private
*/
async _request(method, endpoint, data = null, useS2S = false) {
const url = `${this.baseUrl}${endpoint}`;
const response = await axios({
method,
url,
headers: this._getHeaders(useS2S),
data
});
return response.data;
}
// ===========================================================================
// Client Management
// ===========================================================================
/**
* Create a new client record
* @param {string} email Customer's email address
* @param {string} [phone] Optional phone number
* @returns {Promise<Object>} Client object with ID
*/
async createClient(email, phone = null) {
const payload = { email };
if (phone) payload.phone = phone;
return this._request('POST', '/clients/', payload);
}
/**
* Get client by ID
* @param {string} clientId Client ID
* @returns {Promise<Object>} Client object
*/
async getClient(clientId) {
return this._request('GET', `/clients/${clientId}/`);
}
// ===========================================================================
// Purchase Management
// ===========================================================================
/**
* Create a new purchase
* @param {Object} options Purchase options
* @returns {Promise<Object>} Purchase object with direct_post_url
*/
async createPurchase({
clientId,
amountCents,
currency,
productName,
successRedirect,
failureRedirect,
forceRecurring = false,
metadata = null
}) {
const payload = {
client_id: clientId,
brand_id: this.brandId,
currency,
products: [{ name: productName, price: amountCents }],
success_redirect: successRedirect,
failure_redirect: failureRedirect
};
if (forceRecurring) payload.force_recurring = true;
if (metadata) payload.metadata = metadata;
return this._request('POST', '/purchases/', payload);
}
/**
* Create MIT (recurring) purchase
* @param {Object} options MIT purchase options
* @returns {Promise<Object>} Purchase object
*/
async createMITPurchase({
clientId,
amountCents,
currency,
productName,
cardToken,
networkTransactionId,
originalAmountCents
}) {
const payload = {
client_id: clientId,
brand_id: this.brandId,
currency,
products: [{ name: productName, price: amountCents }],
payment_method_details: {
card_token: cardToken,
previous_network_transaction_id: networkTransactionId,
original_amount_cents: originalAmountCents
},
is_recurring: true
};
return this._request('POST', '/purchases/', payload);
}
/**
* Get purchase by ID
* @param {string} purchaseId Purchase ID
* @returns {Promise<Object>} Purchase object
*/
async getPurchase(purchaseId) {
return this._request('GET', `/purchases/${purchaseId}/`);
}
// ===========================================================================
// Card Data Submission
// ===========================================================================
/**
* Submit card data to direct post URL
* @param {string} directPostUrl URL from purchase creation
* @param {Object} cardData Card details
* @param {Object} fingerprint Browser fingerprint
* @param {boolean} [rememberCard=false] Whether to tokenize
* @returns {Promise<Object>} 3DS parameters or ready status
*/
async submitCardData(directPostUrl, cardData, fingerprint, rememberCard = false) {
const formData = new URLSearchParams({
cardholder_name: cardData.cardholderName,
card_number: cardData.cardNumber,
expires: cardData.expires,
cvc: cardData.cvc,
remember_card: rememberCard.toString(),
remote_ip: cardData.remoteIp,
user_agent: fingerprint.userAgent,
accept_header: fingerprint.acceptHeader,
language: fingerprint.language,
java_enabled: fingerprint.javaEnabled.toString(),
javascript_enabled: fingerprint.javascriptEnabled.toString(),
color_depth: fingerprint.colorDepth.toString(),
utc_offset: fingerprint.utcOffset.toString(),
screen_width: fingerprint.screenWidth.toString(),
screen_height: fingerprint.screenHeight.toString()
});
const response = await axios.post(directPostUrl, formData.toString(), {
headers: {
'Authorization': `Bearer ${this.s2sApiKey}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
});
return response.data;
}
/**
* Submit token for MIT transaction
* @param {string} directPostUrl URL from MIT purchase
* @param {string} cardToken Stored card token
* @param {string} serverIp Your server's IP
* @returns {Promise<Object>} Ready status
*/
async submitTokenForMIT(directPostUrl, cardToken, serverIp) {
const formData = new URLSearchParams({
card_token: cardToken,
remote_ip: serverIp
});
const response = await axios.post(directPostUrl, formData.toString(), {
headers: {
'Authorization': `Bearer ${this.s2sApiKey}`,
'Content-Type': 'application/x-www-form-urlencoded'
}
});
return response.data;
}
// ===========================================================================
// Charge and Refund
// ===========================================================================
/**
* Charge a purchase
* @param {string} purchaseId Purchase ID to charge
* @returns {Promise<Object>} Transaction result
*/
async chargePurchase(purchaseId) {
return this._request('POST', `/purchases/${purchaseId}/charge/`);
}
/**
* Refund a purchase
* @param {string} purchaseId Purchase ID to refund
* @param {number} [amountCents] Amount in cents (null for full refund)
* @returns {Promise<Object>} Refund confirmation
*/
async refundPurchase(purchaseId, amountCents = null) {
const payload = amountCents ? { amount: amountCents } : {};
return this._request('POST', `/purchases/${purchaseId}/refund/`, payload);
}
}
// =============================================================================
// Usage Examples
// =============================================================================
async function exampleCITWithInternal3DS() {
const client = new PreciumS2SClient({
standardApiKey: 'your_standard_api_key',
s2sApiKey: 'your_s2s_api_key',
brandId: 'your_brand_id'
});
try {
// Step 1: Create client
const customer = await client.createClient('customer@example.com');
console.log('Created client:', customer.id);
// Step 2: Create purchase
const purchase = await client.createPurchase({
clientId: customer.id,
amountCents: 29900,
currency: 'ZAR',
productName: 'Premium Subscription',
successRedirect: 'https://yoursite.com/success',
failureRedirect: 'https://yoursite.com/failure',
forceRecurring: true
});
console.log('Created purchase:', purchase.id);
// Step 3: Submit card data
const cardData = {
cardholderName: 'John Smith',
cardNumber: '4000000000001091',
expires: '12/28',
cvc: '123',
remoteIp: '196.21.45.123'
};
const fingerprint = {
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
acceptHeader: 'text/html,application/xhtml+xml',
language: 'en-ZA',
javaEnabled: false,
javascriptEnabled: true,
colorDepth: 24,
utcOffset: -120,
screenWidth: 1920,
screenHeight: 1080
};
const submitResult = await client.submitCardData(
purchase.direct_post_url,
cardData,
fingerprint,
true
);
// Step 4: Handle 3DS if required
if (submitResult['3ds']) {
console.log('3DS required - redirect customer to:', submitResult['3ds']['3ds_url']);
// In production: redirect customer to 3DS URL
}
// Step 5: Charge after 3DS
const chargeResult = await client.chargePurchase(purchase.id);
console.log('Charge status:', chargeResult.status);
if (chargeResult.status === 'paid') {
console.log('Token:', chargeResult.payment_method_details.card.token);
}
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
module.exports = { PreciumS2SClient, ENVIRONMENTS };
Complete Integration Class
PHP
<?php
/**
* Precium S2S Integration - PHP
* Requires: PHP 7.4+ with cURL
*/
declare(strict_types=1);
class PreciumS2SClient
{
private const ENVIRONMENTS = [
'SANDBOX' => 'https://gate.reviopay.com/api/v1',
'PRODUCTION' => 'https://gate.reviopay.com/api/v1'
];
private string $standardApiKey;
private string $s2sApiKey;
private string $brandId;
private string $baseUrl;
public function __construct(
string $standardApiKey,
string $s2sApiKey,
string $brandId,
string $environment = 'SANDBOX'
) {
$this->standardApiKey = $standardApiKey;
$this->s2sApiKey = $s2sApiKey;
$this->brandId = $brandId;
$this->baseUrl = self::ENVIRONMENTS[$environment];
}
/**
* Make an API request
*/
private function request(
string $method,
string $endpoint,
?array $data = null,
bool $useS2S = false
): array {
$apiKey = $useS2S ? $this->s2sApiKey : $this->standardApiKey;
$url = $this->baseUrl . $endpoint;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$apiKey}",
'Content-Type: application/json',
'Accept: application/json'
]
]);
if ($data !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode >= 400) {
throw new Exception("API Error: HTTP {$httpCode} - {$response}");
}
return json_decode($response, true);
}
// =========================================================================
// Client Management
// =========================================================================
/**
* Create a new client
*/
public function createClient(string $email, ?string $phone = null): array
{
$payload = ['email' => $email];
if ($phone !== null) {
$payload['phone'] = $phone;
}
return $this->request('POST', '/clients/', $payload);
}
/**
* Get client by ID
*/
public function getClient(string $clientId): array
{
return $this->request('GET', "/clients/{$clientId}/");
}
// =========================================================================
// Purchase Management
// =========================================================================
/**
* Create a new purchase
*/
public function createPurchase(
string $clientId,
int $amountCents,
string $currency,
string $productName,
string $successRedirect,
string $failureRedirect,
bool $forceRecurring = false,
?array $metadata = null
): array {
$payload = [
'client_id' => $clientId,
'brand_id' => $this->brandId,
'currency' => $currency,
'products' => [['name' => $productName, 'price' => $amountCents]],
'success_redirect' => $successRedirect,
'failure_redirect' => $failureRedirect
];
if ($forceRecurring) {
$payload['force_recurring'] = true;
}
if ($metadata !== null) {
$payload['metadata'] = $metadata;
}
return $this->request('POST', '/purchases/', $payload);
}
/**
* Create MIT (recurring) purchase
*/
public function createMITPurchase(
string $clientId,
int $amountCents,
string $currency,
string $productName,
string $cardToken,
string $networkTransactionId,
int $originalAmountCents
): array {
$payload = [
'client_id' => $clientId,
'brand_id' => $this->brandId,
'currency' => $currency,
'products' => [['name' => $productName, 'price' => $amountCents]],
'payment_method_details' => [
'card_token' => $cardToken,
'previous_network_transaction_id' => $networkTransactionId,
'original_amount_cents' => $originalAmountCents
],
'is_recurring' => true
];
return $this->request('POST', '/purchases/', $payload);
}
// =========================================================================
// Card Data Submission
// =========================================================================
/**
* Submit card data to direct post URL
*/
public function submitCardData(
string $directPostUrl,
array $cardData,
array $fingerprint,
bool $rememberCard = false
): array {
$postData = http_build_query([
'cardholder_name' => $cardData['cardholder_name'],
'card_number' => $cardData['card_number'],
'expires' => $cardData['expires'],
'cvc' => $cardData['cvc'],
'remember_card' => $rememberCard ? 'true' : 'false',
'remote_ip' => $cardData['remote_ip'],
'user_agent' => $fingerprint['user_agent'],
'accept_header' => $fingerprint['accept_header'],
'language' => $fingerprint['language'],
'java_enabled' => $fingerprint['java_enabled'] ? 'true' : 'false',
'javascript_enabled' => $fingerprint['javascript_enabled'] ? 'true' : 'false',
'color_depth' => (string)$fingerprint['color_depth'],
'utc_offset' => (string)$fingerprint['utc_offset'],
'screen_width' => (string)$fingerprint['screen_width'],
'screen_height' => (string)$fingerprint['screen_height']
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $directPostUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$this->s2sApiKey}",
'Content-Type: application/x-www-form-urlencoded'
]
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
/**
* Submit token for MIT
*/
public function submitTokenForMIT(
string $directPostUrl,
string $cardToken,
string $serverIp
): array {
$postData = http_build_query([
'card_token' => $cardToken,
'remote_ip' => $serverIp
]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $directPostUrl,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postData,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$this->s2sApiKey}",
'Content-Type: application/x-www-form-urlencoded'
]
]);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// =========================================================================
// Charge and Refund
// =========================================================================
/**
* Charge a purchase
*/
public function chargePurchase(string $purchaseId): array
{
return $this->request('POST', "/purchases/{$purchaseId}/charge/");
}
/**
* Refund a purchase
*/
public function refundPurchase(string $purchaseId, ?int $amountCents = null): array
{
$payload = $amountCents !== null ? ['amount' => $amountCents] : [];
return $this->request('POST', "/purchases/{$purchaseId}/refund/", $payload);
}
}
// =============================================================================
// Usage Example
// =============================================================================
/*
$client = new PreciumS2SClient(
'your_standard_api_key',
'your_s2s_api_key',
'your_brand_id'
);
// Create client
$customer = $client->createClient('customer@example.com');
// Create purchase
$purchase = $client->createPurchase(
$customer['id'],
29900,
'ZAR',
'Premium Subscription',
'https://yoursite.com/success',
'https://yoursite.com/failure',
true
);
// Submit card data
$cardData = [
'cardholder_name' => 'John Smith',
'card_number' => '4000000000001091',
'expires' => '12/28',
'cvc' => '123',
'remote_ip' => '196.21.45.123'
];
$fingerprint = [
'user_agent' => 'Mozilla/5.0',
'accept_header' => 'text/html',
'language' => 'en-ZA',
'java_enabled' => false,
'javascript_enabled' => true,
'color_depth' => 24,
'utc_offset' => -120,
'screen_width' => 1920,
'screen_height' => 1080
];
$result = $client->submitCardData(
$purchase['direct_post_url'],
$cardData,
$fingerprint,
true
);
// Charge
$chargeResult = $client->chargePurchase($purchase['id']);
*/
RUBY
# Precium S2S Integration - Ruby
# Requires: httparty gem
require 'httparty'
require 'json'
class PreciumS2SClient
ENVIRONMENTS = {
sandbox: 'https://gate.reviopay.com/api/v1',
production: 'https://gate.reviopay.com/api/v1'
}.freeze
def initialize(standard_api_key:, s2s_api_key:, brand_id:, environment: :sandbox)
@standard_api_key = standard_api_key
@s2s_api_key = s2s_api_key
@brand_id = brand_id
@base_url = ENVIRONMENTS[environment]
end
# Client Management
def create_client(email:, phone: nil)
payload = { email: email }
payload[:phone] = phone if phone
request(:post, '/clients/', payload)
end
def get_client(client_id)
request(:get, "/clients/#{client_id}/")
end
# Purchase Management
def create_purchase(client_id:, amount_cents:, currency:, product_name:,
success_redirect:, failure_redirect:, force_recurring: false)
payload = {
client_id: client_id,
brand_id: @brand_id,
currency: currency,
products: [{ name: product_name, price: amount_cents }],
success_redirect: success_redirect,
failure_redirect: failure_redirect
}
payload[:force_recurring] = true if force_recurring
request(:post, '/purchases/', payload)
end
def create_mit_purchase(client_id:, amount_cents:, currency:, product_name:,
card_token:, network_transaction_id:, original_amount_cents:)
payload = {
client_id: client_id,
brand_id: @brand_id,
currency: currency,
products: [{ name: product_name, price: amount_cents }],
payment_method_details: {
card_token: card_token,
previous_network_transaction_id: network_transaction_id,
original_amount_cents: original_amount_cents
},
is_recurring: true
}
request(:post, '/purchases/', payload)
end
# Card Data Submission
def submit_card_data(direct_post_url:, card_data:, fingerprint:, remember_card: false)
form_data = {
cardholder_name: card_data[:cardholder_name],
card_number: card_data[:card_number],
expires: card_data[:expires],
cvc: card_data[:cvc],
remember_card: remember_card.to_s,
remote_ip: card_data[:remote_ip],
user_agent: fingerprint[:user_agent],
accept_header: fingerprint[:accept_header],
language: fingerprint[:language],
java_enabled: fingerprint[:java_enabled].to_s,
javascript_enabled: fingerprint[:javascript_enabled].to_s,
color_depth: fingerprint[:color_depth].to_s,
utc_offset: fingerprint[:utc_offset].to_s,
screen_width: fingerprint[:screen_width].to_s,
screen_height: fingerprint[:screen_height].to_s
}
response = HTTParty.post(
direct_post_url,
headers: {
'Authorization' => "Bearer #{@s2s_api_key}",
'Content-Type' => 'application/x-www-form-urlencoded'
},
body: URI.encode_www_form(form_data)
)
JSON.parse(response.body)
end
# Charge and Refund
def charge_purchase(purchase_id)
request(:post, "/purchases/#{purchase_id}/charge/")
end
def refund_purchase(purchase_id, amount_cents: nil)
payload = amount_cents ? { amount: amount_cents } : {}
request(:post, "/purchases/#{purchase_id}/refund/", payload)
end
private
def request(method, endpoint, payload = nil, use_s2s: false)
api_key = use_s2s ? @s2s_api_key : @standard_api_key
url = "#{@base_url}#{endpoint}"
options = {
headers: {
'Authorization' => "Bearer #{api_key}",
'Content-Type' => 'application/json',
'Accept' => 'application/json'
}
}
options[:body] = payload.to_json if payload
response = HTTParty.send(method, url, options)
JSON.parse(response.body)
end
end
JAVA
/**
* Precium S2S Integration - Java
* Requires: java.net.http (Java 11+), org.json
*/
package com.precium.s2s;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.HashMap;
import org.json.JSONObject;
public class PreciumS2SClient {
private static final String BASE_URL = "https://gate.reviopay.com/api/v1";
private final String standardApiKey;
private final String s2sApiKey;
private final String brandId;
private final HttpClient httpClient;
public PreciumS2SClient(String standardApiKey, String s2sApiKey, String brandId) {
this.standardApiKey = standardApiKey;
this.s2sApiKey = s2sApiKey;
this.brandId = brandId;
this.httpClient = HttpClient.newHttpClient();
}
// =========================================================================
// Client Management
// =========================================================================
public JSONObject createClient(String email) throws Exception {
JSONObject payload = new JSONObject();
payload.put("email", email);
return request("POST", "/clients/", payload, false);
}
// =========================================================================
// Purchase Management
// =========================================================================
public JSONObject createPurchase(
String clientId,
int amountCents,
String currency,
String productName,
String successRedirect,
String failureRedirect,
boolean forceRecurring
) throws Exception {
JSONObject product = new JSONObject();
product.put("name", productName);
product.put("price", amountCents);
JSONObject payload = new JSONObject();
payload.put("client_id", clientId);
payload.put("brand_id", brandId);
payload.put("currency", currency);
payload.put("products", new org.json.JSONArray().put(product));
payload.put("success_redirect", successRedirect);
payload.put("failure_redirect", failureRedirect);
if (forceRecurring) {
payload.put("force_recurring", true);
}
return request("POST", "/purchases/", payload, false);
}
// =========================================================================
// Card Data Submission
// =========================================================================
public JSONObject submitCardData(
String directPostUrl,
Map<String, String> cardData,
Map<String, Object> fingerprint,
boolean rememberCard
) throws Exception {
Map<String, String> formData = new HashMap<>();
formData.put("cardholder_name", cardData.get("cardholderName"));
formData.put("card_number", cardData.get("cardNumber"));
formData.put("expires", cardData.get("expires"));
formData.put("cvc", cardData.get("cvc"));
formData.put("remember_card", String.valueOf(rememberCard));
formData.put("remote_ip", cardData.get("remoteIp"));
formData.put("user_agent", (String) fingerprint.get("userAgent"));
formData.put("accept_header", (String) fingerprint.get("acceptHeader"));
formData.put("language", (String) fingerprint.get("language"));
formData.put("java_enabled", String.valueOf(fingerprint.get("javaEnabled")));
formData.put("javascript_enabled", String.valueOf(fingerprint.get("javascriptEnabled")));
formData.put("color_depth", String.valueOf(fingerprint.get("colorDepth")));
formData.put("utc_offset", String.valueOf(fingerprint.get("utcOffset")));
formData.put("screen_width", String.valueOf(fingerprint.get("screenWidth")));
formData.put("screen_height", String.valueOf(fingerprint.get("screenHeight")));
String formBody = buildFormData(formData);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(directPostUrl))
.header("Authorization", "Bearer " + s2sApiKey)
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(formBody))
.build();
HttpResponse<String> response = httpClient.send(request,
HttpResponse.BodyHandlers.ofString());
return new JSONObject(response.body());
}
// =========================================================================
// Charge and Refund
// =========================================================================
public JSONObject chargePurchase(String purchaseId) throws Exception {
return request("POST", "/purchases/" + purchaseId + "/charge/", null, false);
}
public JSONObject refundPurchase(String purchaseId, Integer amountCents) throws Exception {
JSONObject payload = new JSONObject();
if (amountCents != null) {
payload.put("amount", amountCents);
}
return request("POST", "/purchases/" + purchaseId + "/refund/", payload, false);
}
// =========================================================================
// Private Helpers
// =========================================================================
private JSONObject request(String method, String endpoint, JSONObject payload, boolean useS2S)
throws Exception {
String apiKey = useS2S ? s2sApiKey : standardApiKey;
String url = BASE_URL + endpoint;
HttpRequest.Builder builder = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer " + apiKey)
.header("Content-Type", "application/json")
.header("Accept", "application/json");
if (method.equals("POST")) {
String body = payload != null ? payload.toString() : "";
builder.POST(HttpRequest.BodyPublishers.ofString(body));
} else {
builder.GET();
}
HttpResponse<String> response = httpClient.send(builder.build(),
HttpResponse.BodyHandlers.ofString());
return new JSONObject(response.body());
}
private String buildFormData(Map<String, String> data) {
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : data.entrySet()) {
if (sb.length() > 0) sb.append("&");
sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
sb.append("=");
sb.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return sb.toString();
}
}
CSHARP
/**
* Precium S2S Integration - C#
* Requires: .NET 6+
*/
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace Precium.S2S
{
public class PreciumS2SClient
{
private const string BaseUrl = "https://gate.reviopay.com/api/v1";
private readonly string _standardApiKey;
private readonly string _s2sApiKey;
private readonly string _brandId;
private readonly HttpClient _httpClient;
public PreciumS2SClient(string standardApiKey, string s2sApiKey, string brandId)
{
_standardApiKey = standardApiKey;
_s2sApiKey = s2sApiKey;
_brandId = brandId;
_httpClient = new HttpClient();
}
// Client Management
public async Task<JsonDocument> CreateClientAsync(string email, string? phone = null)
{
var payload = new Dictionary<string, object> { { "email", email } };
if (phone != null) payload["phone"] = phone;
return await RequestAsync("POST", "/clients/", payload);
}
// Purchase Management
public async Task<JsonDocument> CreatePurchaseAsync(
string clientId,
int amountCents,
string currency,
string productName,
string successRedirect,
string failureRedirect,
bool forceRecurring = false)
{
var payload = new Dictionary<string, object>
{
{ "client_id", clientId },
{ "brand_id", _brandId },
{ "currency", currency },
{ "products", new[] { new { name = productName, price = amountCents } } },
{ "success_redirect", successRedirect },
{ "failure_redirect", failureRedirect }
};
if (forceRecurring) payload["force_recurring"] = true;
return await RequestAsync("POST", "/purchases/", payload);
}
// Card Data Submission
public async Task<JsonDocument> SubmitCardDataAsync(
string directPostUrl,
CardData card,
BrowserFingerprint fingerprint,
bool rememberCard = false)
{
var formData = new Dictionary<string, string>
{
{ "cardholder_name", card.CardholderName },
{ "card_number", card.CardNumber },
{ "expires", card.Expires },
{ "cvc", card.Cvc },
{ "remember_card", rememberCard.ToString().ToLower() },
{ "remote_ip", card.RemoteIp },
{ "user_agent", fingerprint.UserAgent },
{ "accept_header", fingerprint.AcceptHeader },
{ "language", fingerprint.Language },
{ "java_enabled", fingerprint.JavaEnabled.ToString().ToLower() },
{ "javascript_enabled", fingerprint.JavascriptEnabled.ToString().ToLower() },
{ "color_depth", fingerprint.ColorDepth.ToString() },
{ "utc_offset", fingerprint.UtcOffset.ToString() },
{ "screen_width", fingerprint.ScreenWidth.ToString() },
{ "screen_height", fingerprint.ScreenHeight.ToString() }
};
var request = new HttpRequestMessage(HttpMethod.Post, directPostUrl)
{
Content = new FormUrlEncodedContent(formData)
};
request.Headers.Add("Authorization", $"Bearer {_s2sApiKey}");
var response = await _httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(content);
}
// Charge and Refund
public async Task<JsonDocument> ChargePurchaseAsync(string purchaseId)
{
return await RequestAsync("POST", $"/purchases/{purchaseId}/charge/", null);
}
public async Task<JsonDocument> RefundPurchaseAsync(string purchaseId, int? amountCents = null)
{
var payload = amountCents.HasValue
? new Dictionary<string, object> { { "amount", amountCents.Value } }
: null;
return await RequestAsync("POST", $"/purchases/{purchaseId}/refund/", payload);
}
private async Task<JsonDocument> RequestAsync(
string method,
string endpoint,
Dictionary<string, object>? payload,
bool useS2S = false)
{
var apiKey = useS2S ? _s2sApiKey : _standardApiKey;
var url = $"{BaseUrl}{endpoint}";
var request = new HttpRequestMessage(
method == "POST" ? HttpMethod.Post : HttpMethod.Get,
url);
request.Headers.Add("Authorization", $"Bearer {apiKey}");
request.Headers.Add("Accept", "application/json");
if (payload != null)
{
var json = JsonSerializer.Serialize(payload);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
}
var response = await _httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(content);
}
}
public record CardData(
string CardholderName,
string CardNumber,
string Expires,
string Cvc,
string RemoteIp);
public record BrowserFingerprint(
string UserAgent,
string AcceptHeader,
string Language,
bool JavaEnabled,
bool JavascriptEnabled,
int ColorDepth,
int UtcOffset,
int ScreenWidth,
int ScreenHeight);
}
GO
// Precium S2S Integration - Go
// Requires: Go 1.18+
package precium
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"strings"
)
const baseURL = "https://gate.reviopay.com/api/v1"
type Client struct {
StandardAPIKey string
S2SAPIKey string
BrandID string
HTTPClient *http.Client
}
type CardData struct {
CardholderName string
CardNumber string
Expires string
CVC string
RemoteIP string
}
type BrowserFingerprint struct {
UserAgent string
AcceptHeader string
Language string
JavaEnabled bool
JavascriptEnabled bool
ColorDepth int
UTCOffset int
ScreenWidth int
ScreenHeight int
}
func NewClient(standardAPIKey, s2sAPIKey, brandID string) *Client {
return &Client{
StandardAPIKey: standardAPIKey,
S2SAPIKey: s2sAPIKey,
BrandID: brandID,
HTTPClient: &http.Client{},
}
}
// CreateClient creates a new client record
func (c *Client) CreateClient(email string, phone *string) (map[string]interface{}, error) {
payload := map[string]interface{}{"email": email}
if phone != nil {
payload["phone"] = *phone
}
return c.request("POST", "/clients/", payload, false)
}
// CreatePurchase creates a new purchase
func (c *Client) CreatePurchase(
clientID string,
amountCents int,
currency string,
productName string,
successRedirect string,
failureRedirect string,
forceRecurring bool,
) (map[string]interface{}, error) {
payload := map[string]interface{}{
"client_id": clientID,
"brand_id": c.BrandID,
"currency": currency,
"products": []map[string]interface{}{{"name": productName, "price": amountCents}},
"success_redirect": successRedirect,
"failure_redirect": failureRedirect,
}
if forceRecurring {
payload["force_recurring"] = true
}
return c.request("POST", "/purchases/", payload, false)
}
// SubmitCardData submits card data to the direct post URL
func (c *Client) SubmitCardData(
directPostURL string,
card CardData,
fingerprint BrowserFingerprint,
rememberCard bool,
) (map[string]interface{}, error) {
form := url.Values{}
form.Set("cardholder_name", card.CardholderName)
form.Set("card_number", card.CardNumber)
form.Set("expires", card.Expires)
form.Set("cvc", card.CVC)
form.Set("remember_card", strconv.FormatBool(rememberCard))
form.Set("remote_ip", card.RemoteIP)
form.Set("user_agent", fingerprint.UserAgent)
form.Set("accept_header", fingerprint.AcceptHeader)
form.Set("language", fingerprint.Language)
form.Set("java_enabled", strconv.FormatBool(fingerprint.JavaEnabled))
form.Set("javascript_enabled", strconv.FormatBool(fingerprint.JavascriptEnabled))
form.Set("color_depth", strconv.Itoa(fingerprint.ColorDepth))
form.Set("utc_offset", strconv.Itoa(fingerprint.UTCOffset))
form.Set("screen_width", strconv.Itoa(fingerprint.ScreenWidth))
form.Set("screen_height", strconv.Itoa(fingerprint.ScreenHeight))
req, err := http.NewRequest("POST", directPostURL, strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+c.S2SAPIKey)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
return result, nil
}
// ChargePurchase charges a purchase
func (c *Client) ChargePurchase(purchaseID string) (map[string]interface{}, error) {
return c.request("POST", fmt.Sprintf("/purchases/%s/charge/", purchaseID), nil, false)
}
// RefundPurchase refunds a purchase
func (c *Client) RefundPurchase(purchaseID string, amountCents *int) (map[string]interface{}, error) {
var payload map[string]interface{}
if amountCents != nil {
payload = map[string]interface{}{"amount": *amountCents}
}
return c.request("POST", fmt.Sprintf("/purchases/%s/refund/", purchaseID), payload, false)
}
func (c *Client) request(method, endpoint string, payload map[string]interface{}, useS2S bool) (map[string]interface{}, error) {
apiKey := c.StandardAPIKey
if useS2S {
apiKey = c.S2SAPIKey
}
url := baseURL + endpoint
var body io.Reader
if payload != nil {
jsonBytes, err := json.Marshal(payload)
if err != nil {
return nil, err
}
body = bytes.NewReader(jsonBytes)
}
req, err := http.NewRequest(method, url, body)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Accept", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result map[string]interface{}
if err := json.Unmarshal(respBody, &result); err != nil {
return nil, err
}
return result, nil
}
Use this code on your frontend to collect browser fingerprint data:
JSX
function collectBrowserFingerprint() {
return {
userAgent: navigator.userAgent,
acceptHeader: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
language: navigator.language || navigator.userLanguage,
javaEnabled: navigator.javaEnabled ? navigator.javaEnabled() : false,
javascriptEnabled: true,
colorDepth: screen.colorDepth,
utcOffset: new Date().getTimezoneOffset(),
screenWidth: screen.width,
screenHeight: screen.height
};
}
// Usage
const fingerprint = collectBrowserFingerprint();
// Send fingerprint to your backend with the payment request
HTML
<!DOCTYPE html>
<html>
<head>
<title>Bank Verification</title>
</head>
<body>
<div id="loading">Redirecting to your bank for verification...</div>
<form id="3ds-form" method="POST" style="display: none;">
<input type="hidden" name="MD" id="md" />
<input type="hidden" name="PaReq" id="pareq" />
<noscript>
<p>JavaScript is required for bank verification.</p>
<button type="submit">Continue to Bank</button>
</noscript>
</form>
<script>
// These values come from your backend after card submission
function initiate3DS(threeDSData) {
const form = document.getElementById('3ds-form');
form.action = threeDSData['3ds_url'];
document.getElementById('md').value = threeDSData['MD'];
document.getElementById('pareq').value = threeDSData['PaReq'];
// Add TermUrl for the callback
const termUrl = document.createElement('input');
termUrl.type = 'hidden';
termUrl.name = 'TermUrl';
termUrl.value = threeDSData['callback_url'];
form.appendChild(termUrl);
form.submit();
}
// Call with data from your backend
// initiate3DS(threeDSResponseFromBackend);
</script>
</body>
</html>