Server to server payments
Capture payment details on your own checkout, submit them to Ozow from your backend, and drive the rest of the transaction over a WebSocket. Not yet available for merchant integrations.
On this page14 sections
- What is server to server payments?
- Requirements
- PCI DSS certification: mandatory
- Additional requirements
- How server to server payments will work
- Driving the transaction over a WebSocket
- How the exchange works
- Connect
- Ozow asks for the next input
- Send the completed input
- Ozow reports the transaction complete
- When a step fails
- The full contract
- Register your interest
Not yet available
Server to server payments is not yet available for merchant integrations. This page explains what server to server payments is and what you will need to prepare, including the WebSocket exchange that drives a transaction to completion. Contact support@ozow.com to register your interest.
What is server to server payments?
Server to server payments is an advanced integration path where your platform captures payment details directly and submits them to Ozow via API in the background. Your customer never leaves your site or sees an Ozow-hosted interface, the entire payment experience is built and controlled by you.
This is the highest level of control available in an Ozow integration and is suited to merchants who need the payment to happen entirely within their own interface with no Ozow UI involved.
Requirements
PCI DSS certification: mandatory
PCI DSSPCI DSS The security standard that applies to anyone who stores, processes or transmits card data. Its reach is the reason most integrations avoid touching card numbers at all.PCI Security Standards Council certification is mandatory for server to server payments. There are no exceptions.
Because your platform captures and transmits sensitive payment details, you are responsible for ensuring that data is handled securely. That covers both halves of this integration:
- Card details, including card numbers and CVV codes, where you submit them in
paymentDetail - The payer's internet banking credentials, which the screen-scraping flow collects through the WebSocket exchange below
Ozow will require proof of PCI DSS certification before enabling server to server payments on your merchant profile.
Merchants who are not PCI DSS certified must use one of the following integration paths instead:
- Redirect to Ozow, Ozow handles all sensitive payment data on its own hosted page
- Embedded iframe, full payment page embedded inside your site via the Ozow SDK
- Embedded wallet, card data is captured inside the Ozow iframe, keeping your checkout page out of PCI scope
Additional requirements
- An active Ozow merchant account with Direct integration enabled
- PCI DSS certification, proof required before enablement
- A server-side integration, server to server payments calls must be made server-side only. Never submit payment details from browser code.
- A client that can send and receive text frames over a WebSocket and can set a request header on the opening handshake, for the exchange described below
How server to server payments will work
When available, server to server payments will use One API. Instead of calling /payments to
generate a redirectRedirect Sending the payer to the Ozow payment page to complete the payment, and returning them to your site afterwards. The alternative is embedding the checkout in your own page, where the payer never leaves it. URL, you will call /transactions directly and supply the payment details in a
paymentDetail object:
{
"paymentRequest": {
"siteCode": "YOUR_SITE_CODE",
"amount": {
"currency": "ZAR",
"value": 100.00
},
"merchantReference": "ORDER-001",
"expireAt": "2026-12-31T23:59:59Z"
},
"paymentDetail": {
"paymentType": "card",
"details": {
"cardNumber": "XXXX XXXX XXXX XXXX",
"fullName": "CUSTOMER NAME",
"expiryMonth": "12",
"expiryYear": "30",
"cvv": "XXX",
"userAgent": "CUSTOMER_BROWSER_USER_AGENT",
"callbackUrl": "https://yourstore.com/card-callback"
}
}
}
The response carries a requiredActionOptions array saying what has to happen next. Your
integration must handle these programmatically, and the entry whose action is websocket is the
one described below.
Driving the transaction over a WebSocket
Ozow tells you what the payer must supply next, you render it in your own interface and send the answer back, and that repeats until the transaction completes.
This is a conversation Ozow drives. You do not decide the steps: the bank does, and they differ between banks and between payers. Your job is to render whatever arrives and return what the payer entered.
There is no fixed URL to connect to.
The address is issued per transaction and comes back in the response that created it, so you cannot configure it ahead of time.
How the exchange works
Four messages travel on the channel. Ozow sends three of them and you send one.
| Message | Direction | What it means |
|---|---|---|
Input |
Ozow sends | The payer must supply something. This arrives first and again after each step |
Input |
You send | The values the payer entered |
Completion |
Ozow sends | Every step is done, with the final status |
Error |
Ozow sends | A step failed, with a flag saying whether the transaction survives it |
Connect
The requiredActionOptions entry whose action is websocket carries the uri to connect to:
{
"requiredActionOptions": [
{
"action": "websocket",
"uri": "WEBSOCKET_URI_RETURNED_FOR_THIS_TRANSACTION"
}
]
}
Connect to the uri exactly as it was returned. It is issued for that one transaction, so build
nothing from its shape and store nothing from it between transactions.
Send your access token as an Authorization header on the opening handshake:
Authorization: Bearer YOUR_ACCESS_TOKEN
If authentication or authorisation fails, the connection closes with 403 Forbidden.
Ozow asks for the next input
As soon as the connection is established, Ozow sends an InputResponse. It arrives again after each
step you complete.
{
"transactionId": "5ecaafc2-354f-47d9-822d-d0bd8b77eab3",
"paymentStep": "Login",
"pageTitle": "Login Details",
"pageInstructions": "Log in using your internet banking profile.",
"pageActionText": "Login",
"displayType": "form",
"inputFields": [
{
"name": "MobileNumber",
"label": "Enter Mobile Number",
"fieldType": "text",
"properties": {
"maxLength": 10,
"isOptional": false,
"isSensitive": false
}
}
]
}
pageTitle, pageInstructions and pageActionText are written for the payer, so you can show them
as they arrive rather than writing your own copy for a step you have never seen.
These fields are where the payer types their banking credentials.
A field carrying
isSensitive is one of them, and the step above asks for an internet banking login. Everything
your interface does with these values is inside your
PCI DSS scope: do not log them, do not persist them, and send
them to Ozow and nowhere else.
displayType is the branch your loop turns on:
display |
What to render |
|---|---|
form |
Collect the fields in input |
prompt |
Tell the payer to perform an action, such as accepting a push message |
busy |
Ask the payer to wait |
Only a form carries inputFields.
Send the completed input
Send an InputRequest back with the values the payer entered:
{
"paymentStep": "Login",
"inputFields": [
{
"name": "MobileNumber",
"value": "0821234567"
}
]
}
paymentStep and every field name must match the message Ozow sent, exactly
, including the case. A message whose values differ is not read. Echo the strings you received rather than retyping them, and the case cannot drift.
Then wait for the next message. It is another InputResponse if the bank has more to ask, a
CompletionResponse if it does not, or an ErrorResponse if the step failed.
Ozow reports the transaction complete
{
"transactionId": "5ecaafc2-354f-47d9-822d-d0bd8b77eab3",
"status": "Successful"
}
A completion message is not the same as a successful payment. It means every step has been
processed, and status says how it ended. Read status rather than treating the arrival of the
message as the outcome.
When a step fails
{
"title": "Invalid credentials",
"detail": "The username or password was not accepted by the bank.",
"canContinue": true
}
canContinue decides what happens next:
can |
What to do |
|---|---|
true |
The transaction survives. Send the last message again with the problem corrected |
false |
The transaction is over |
title and detail describe what went wrong.
The full contract
Every message, field and enumerated value is in the One API WebSocket reference. This page covers the order they arrive in; that page covers what each one contains.
Register your interest
If you are planning server to server payments and want to be notified when it becomes available, or if you want to discuss your PCI DSS certification requirements with Ozow, contact support@ozow.com or reach out to your account manager.
In the API reference
1 entry
Last updated