# Introduction (/docs/server-to-server/introduction)

The Precium **Server-to-Server (S2S)** API gives you direct control of the full card payment flow. You handle card data on your own infrastructure and call Precium for authentication, authorisation, capture, refunds and reporting.

This is the most flexible of the Precium integrations and the only one that requires full PCI DSS scope. If you do not need card data on your servers, one of the lower-scope options below will get you live faster.

## Choosing an integration [#choosing-an-integration]

All four options run on the same API and the same credentials. They differ only in where card data is entered, and therefore in your PCI DSS obligation.

| Integration | PCI scope | Card data entered | Best for |
|---|---|---|---|
| **Hosted Checkout** | SAQ-A | On a Precium-hosted page | Fastest route live, minimal compliance burden |
| **Payment Links** | SAQ-A | On a Precium-hosted page | Invoicing, email and manual billing |
| **Direct Post** | SAQ A-EP | In your form, posted straight to Precium | Branded checkout without card data touching your servers |
| **Server-to-Server** | SAQ-D | On your server | PSPs and platforms needing full control of the flow |

Direct Post is worth a look before committing to S2S: you keep a fully branded checkout, but because card data posts from the customer's browser directly to Precium, your scope is raised only to SAQ A-EP rather than SAQ-D. See the **Payment Orchestration** documentation for both hosted and Direct Post flows.

## Who this is for [#who-this-is-for]

- **Payment service providers and payment facilitators** serving their own merchant networks
- **Enterprise merchants** with an existing PCI-compliant cardholder data environment
- **Platforms and marketplaces** embedding payments where the checkout must be fully owned

## Prerequisites [#prerequisites]

| Requirement | Detail |
|---|---|
| **PCI DSS** | Level 1 validation for your cardholder data environment, evidenced by a current Attestation of Compliance. Your Attestation must be on file with Precium before live keys are issued. |
| **Credentials** | A **bearer token** and a **Brand ID** from the Developers section of your dashboard, plus an **S2S token** issued separately by Precium to qualifying merchants. |
| **HTTPS endpoints** | TLS 1.2 or higher, for 3D Secure redirects and webhook delivery. |
| **Webhook handling** | An endpoint that verifies signatures and tolerates duplicate delivery. See *Webhooks* below. |

Your brand may need to be approved by [support@precium.com](mailto:support@precium.com) before it can be used for live transactions.

## Base URL and environments [#base-url-and-environments]

Every request goes to:

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

Endpoint paths in this documentation are relative to that base. For example, `/purchases/` means `https://gate.reviopay.com/api/v1/purchases/`.

<Callout type="warning">
**Test and production share this base URL.** The environment is determined entirely by which API key you send — there is no separate sandbox host. Two consequences worth designing around:

- A key mixed up in configuration will send **live** card traffic through what you believe is a test integration. There is no URL-level safeguard, so keep test and live keys in separate secret stores and never fall back from one to the other.
- Test and live data are fully separate. A test webhook never receives events caused by live purchases, and vice versa.
</Callout>

## Authentication [#authentication]

Precium uses bearer token authentication. Send your API key in the `Authorization` header of every request:

```text
Authorization: Bearer YOUR_API_KEY
```

| Key | Used for |
|---|---|
| **Standard API key** | All API operations: creating clients and purchases, capture, refund, cancel, webhooks and reporting |
| **S2S API key** | Submitting card data to the `direct_post_url` returned on a purchase |

Creating a purchase requires both your API key and your **Brand ID**. Never expose either in client-side code, mobile applications or logs.

## Core endpoints [#core-endpoints]

| Method | Path | Purpose |
|---|---|---|
| POST | `/clients/` | Create a customer record |
| POST | `/purchases/` | Create a transaction |
| GET | `/purchases/{id}/` | Retrieve a transaction and its attempt history |
| POST | `/purchases/{id}/charge/` | Charge a stored token |
| POST | `/purchases/{id}/capture/` | Capture funds held by an authorisation |
| POST | `/purchases/{id}/release/` | Release held funds without capturing |
| POST | `/purchases/{id}/refund/` | Refund in full or in part |
| POST | `/purchases/{id}/cancel/` | Cancel a purchase |
| POST | `/purchases/{id}/delete_recurring_token/` | Delete a stored card token |
| GET | `/clients/{id}/recurring_tokens/` | List a customer's stored tokens |
| GET | `/payment_methods/` | List methods enabled for a brand and currency |
| GET | `/public_key/` | Retrieve the key for verifying callback signatures |

## How transactions are classified [#how-transactions-are-classified]

Precium classifies every transaction by who initiated it. This determines whether 3D Secure is required, whether a CVC is needed, and where chargeback liability sits — so it is the first thing to establish when choosing a flow.

| Class | Meaning | 3D Secure | CVC |
|---|---|---|---|
| **CIT** | Customer-initiated. The cardholder is present and acting. | Required | Required |
| **CIT → MIT** | A customer-initiated payment that stores a token for later merchant-initiated use. | Required on the first payment | Required on the first payment |
| **MIT** | Merchant-initiated against a stored token. The cardholder is not present. | Not presented | Not used — may be stubbed |

In South Africa the first charge on a card must always be authenticated with 3D Secure. Subsequent merchant-initiated charges against the resulting token do not present a challenge.

### Supported flows [#supported-flows]

- **Regular redirect** — create a purchase, send the customer to the returned `checkout_url`
- **Direct Post** — your form, card data posted straight to Precium (SAQ A-EP)
- **Preauthorisation** — verify a card and store it without moving money
- **Delayed capture** — hold funds now, capture or release later
- **Tokenised instant capture** — charge a stored token immediately
- **Tokenised delayed capture** — hold against a stored token, capture later
- **External MPI** — bring your own 3D Secure provider
- **External network tokens** — present your own VTS or MDES token and cryptogram
- **Non-3DS** — for approved merchants only; see below

## Preauthorisation and delayed capture [#preauthorisation-and-delayed-capture]

These are distinct operations and the difference matters. Both use `skip_capture`, and the amount decides which one you get.

| Operation | Request | Resulting status | Effect |
|---|---|---|---|
| **Preauthorisation** | `skip_capture: true` with a purchase total of **0** | `preauthorized` | Cardholder verification only. No financial transaction. The card is stored. |
| **Delayed capture** | `skip_capture: true` with a **non-zero** total | `hold` | Funds are reserved. Complete with `/capture/` or release with `/release/`. |

A purchase in `hold` must be resolved. Capture takes an optional `amount` to capture less than was authorised; anything not captured is released. Both operations are asynchronous: if the acquirer is slow you receive HTTP 200 with a status of `pending_capture` or `pending_release`, and the outcome arrives by webhook.

## Refunds [#refunds]

Refund a settled purchase in full, or in part by sending an `amount`. Partial refunds may be issued repeatedly until the original total is exhausted — check `refund_availability` and `refundable_amount` on the purchase before refunding, since not every payment method supports partial refunds.

<Callout type="important">
**A refund cannot be voided.** Once submitted it runs to completion; there is no reversal operation.
</Callout>

## Non-3DS processing [#non-3ds-processing]

Processing without a 3D Secure challenge is available to approved merchants. It is not prohibited, but it changes your risk and cost position:

- Transactions attract a **higher interchange fee** and are treated as higher risk
- You do not receive the liability shift that authentication provides, so chargeback exposure sits with you
- Issuer decline rates are typically higher

Approval is per brand. Contact your account manager before building against this flow.

## Your first request [#your-first-request]

Create a purchase. `client` or `client_id`, `purchase` and `brand_id` are all required. All amounts are integers in **cents**.

```bash
curl -X POST https://gate.reviopay.com/api/v1/purchases/ \
  -H "Authorization: Bearer $PRECIUM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "00000000-0000-4000-8000-000000000001",
    "brand_id":  "00000000-0000-4000-8000-000000000002",
    "purchase": {
      "currency": "ZAR",
      "products": [
        { "name": "Order 1042", "price": 149900 }
      ]
    },
    "reference": "ORDER-1042",
    "success_redirect": "https://www.example.com/success",
    "failure_redirect": "https://www.example.com/failure"
  }'
```

The response contains the purchase `id`, a `checkout_url` for hosted checkout, and a `direct_post_url` for submitting card data yourself. Note that `direct_post_url` is returned only when both `success_redirect` and `failure_redirect` are supplied.

## Integration flow [#integration-flow]

```mermaid
sequenceDiagram
    participant M as Your server
    participant P as Precium
    participant I as Issuer
    M->>P: POST /purchases/
    P-->>M: purchase id + direct_post_url
    M->>P: POST direct_post_url?s2s=true (card data)
    P-->>M: 3D Secure parameters
    M->>I: Redirect cardholder to authenticate
    I-->>P: Authentication result
    P-->>M: Webhook: purchase.paid
```

## 3D Secure [#3d-secure]

<Callout type="info">
**3D Secure 2 is fully supported.** The S2S flow exchanges `MD`, `PaReq` and `PaRes`, which are 3DS1 parameter names, but these operate as a proxy ACS wrapper: Precium performs full 3DS2 verification and challenge on your behalf while presenting the simpler redirect contract to your integration. You do not need to implement 3DS2 device fingerprinting or the challenge flow yourself.
</Callout>

If you already run your own Merchant Plug-In, use the External MPI flow and pass your own authentication results instead.

## Webhooks [#webhooks]

Webhooks are the authoritative source of transaction outcomes. Do not rely on browser redirects — a customer who closes the tab still completes a payment.

### Verifying a callback [#verifying-a-callback]

Payloads are signed with **asymmetric public-key cryptography**. Every delivery carries an `X-Signature` header containing a base64-encoded **RSA PKCS#1 v1.5** signature of the **SHA-256 digest of the raw request body**.

| Callback type | Where to get the public key |
|---|---|
| Webhook subscription | `public_key` on the corresponding webhook object |
| Per-purchase success callback | `GET /public_key/` |

<Callout type="warning">
Verify against the **raw body bytes**, before any JSON parsing or re-serialisation — reformatting the payload invalidates the signature. Precium is not responsible for losses arising from unverified payloads.
</Callout>

### Delivery behaviour [#delivery-behaviour]

- A delivery is successful only on a 2xx response. Failures are retried up to **8 further times** at exponentially increasing intervals.
- No delivery is attempted more than **36 hours** after the triggering event.
- **Duplicates are possible even after you return 200**, if the confirmation is lost in transit. Handlers must be idempotent.
- Deliveries are sequential per object: no `purchase.paid` callback is sent for a purchase until every `purchase.created` callback for it has been delivered.

Twenty-nine event types are available, covering the purchase lifecycle, payments, refunds, chargebacks, payouts and settlement. Subscribe only to what you act on. See *Integration guide* for the full list.

## Duplicate protection [#duplicate-protection]

There is no idempotency key. Precium prevents duplicates through transaction state instead:

- Every purchase has a unique identifier and **may be paid only once**
- Repeat attempts against an already-paid purchase are rejected, typically with `409 Conflict`
- You may create any number of purchases for a client, but each is independently payable once

Practically: create one purchase per order attempt and retry against *that same purchase id* rather than creating another. Confirm state with `GET /purchases/{id}/` before retrying anything.

## Rate limits and pagination [#rate-limits-and-pagination]

Requests are limited to **100 per minute**, with short bursts to 200. Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`; back off when you see `429`.

List endpoints are cursor-paginated, returning `results` with `next` and `previous` URLs. Follow `next` rather than constructing offsets.

## Settlement [#settlement]

Transactions are authorised and settled the **next day**. Settlement of funds to your account may be scheduled differently depending on your commercial model, so confirm your settlement cycle with your account manager rather than inferring it from transaction timing.

## Going live [#going-live]

1. Complete your integration against test credentials
2. Work through the scenarios in *Test scenarios*, including declines, expiries and 3D Secure failures
3. Confirm your webhook endpoint verifies signatures and handles duplicate delivery
4. Place your PCI Attestation of Compliance on file with Precium
5. Request live credentials and brand approval from your account manager

## Support [#support]

Technical questions, credential requests and brand approvals: [support@precium.com](mailto:support@precium.com).

For the full endpoint reference, including every request field and response code, see *Technical reference documentation*.
