Reconcile settlements
Pull settlement data from One API and tie it back to the deposits in your bank account and the records in your own system, line item by line item.
On this page13 sections
- Where settlements fit
- What you'll build
- Before you start
- Step 1: List your settlements
- What comes back
- Step 2: Fetch the line items
- Understanding line item types
- Fees and rounding
- Paging
- Step 3: Match settlements to your bank account
- Step 4: Match line items to your records
- Step 5: Flag what doesn't match
- Next steps
Build with AI 1 package
A build package is every page for one task, with the API operations they use. Copy the prompt into a coding assistant, or hand it the package itself: slim links to each page, full inlines all of them in one document.
- Reconcile a settlementEverything needed to match the money Ozow pays into your bank account against the payments you collected, line item by line item, including the fees that make the two differ.
This guide shows you how to pull settlementSettlement Ozow paying the money you have collected into your bank account. Payins arrive at Ozow first and are settled to you on a schedule, so what a customer paid you today and what has been settled to you today are different amounts. data out of the One API and tie it back to the deposits in your bank account and the records in your own system.
Where settlements fit
When a customer pays you through Ozow, the money lands with Ozow first. Ozow then transfers what you're owed to your bank account. That transfer is a settlement.
How payments are grouped into settlements depends on your settlement model and the payment method. By default Ozow groups transactions together into settlements, but there are several settlement models, and yours may include a custom arrangement. Your specific setup is agreed during onboarding; if you're not sure what applies to you, speak to your account manager.
For reconciliation, the practical consequence is: don't hard-code assumptions about how many records a settlement contains, or how often settlements arrive. Read what the API returns.
There are two separate things to reconcile:
- Did the customer pay? Answered by transaction status.
- Did Ozow pay me? Answered by settlement data, this guide.
A transaction reaching Complete doesn't mean the money has reached you. Settlement happens later,
on a cycle that depends on the payment method. See
Settlements for how that works.
If you reconcile occasionally, the Ozow Dashboard shows all of this with no development work. Build this when you're reconciling regularly or at volume.
What you'll build
Three endpoints, all under https://one.ozow.com/v1:
| Endpoint | Gives you |
|---|---|
GET / |
Settlements for a date range, with totals |
GET / |
A single settlement |
GET / |
Every record that makes up that settlement |
A typical daily job:
- List settlements for the period.
- Fetch the line items for each one.
- Match each settlement to a deposit on your bank statement.
- Match each line item to a record in your system.
- Flag whatever doesn't match.
For complete field lists, all parameters and error responses, see the One API reference.
Before you start
You'll need your One API credentials from the Ozow Dashboard and an OAuth 2.0OAuth 2.0 The authorisation framework behind the token endpoint. Ozow uses the client credentials flow: your server exchanges a client ID and secret for a short-lived access token, and sends that token rather than the secret on every subsequent call.RFC 6749 access token. See Redirect to Ozow for how to obtain one.
Your One API client must have the settlements scope, and your token must request it. A token
issued for payments alone is refused by both endpoints on this page.
Every request takes a bearer tokenBearer token An access token sent in the Authorization header as Authorization: Bearer <token>. Anyone holding the token can use it, which is why it belongs on your server and never in a browser or a mobile app.RFC 6750:
Authorization: Bearer YOUR_ACCESS_TOKEN
Send an X-Correlation-ID header with each request, any UUIDUUID A 128-bit identifier written as 36 characters, such as 497f6eca-6276-4993-bfeb-53cbbbba6f08. Generated rather than assigned in sequence, so two systems can create identifiers without coordinating.Wikipedia you generate. It's returned in
the response and passed through Ozow's internal systems, which makes it the fastest way for Ozow
Support to trace a specific call. If you don't send one, Ozow generates it for you. Log whichever
you end up with.
Step 1: List your settlements
GET https://one.ozow.com/v1/settlements?fromDate=2026-09-01&toDate=2026-09-30
fromDate and toDate are required. You can also filter by siteCode or by a specific settlement
reference, and page with limit (max 50) and offset.
curl -X GET "https://one.ozow.com/v1/settlements?fromDate=2026-09-01&toDate=2026-09-30&limit=50" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
-H "Accept: application/json" \
-H "X-Correlation-ID: 8f14e45f-ceea-467a-9575-9f0e5a3f1b2c"
using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
client.DefaultRequestHeaders.Add("X-Correlation-ID", Guid.NewGuid().ToString());
var url = "https://one.ozow.com/v1/settlements" + "?fromDate=2026-09-01&toDate=2026-09-30&limit=50";
var response = await client.GetAsync(url);
var body = await response.Content.ReadAsStringAsync();
$url = 'https://one.ozow.com/v1/settlements'
. '?fromDate=2026-09-01&toDate=2026-09-30&limit=50';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $accessToken,
'Accept: application/json',
'X-Correlation-ID: ' . $correlationId,
],
]);
$response = curl_exec($ch);
curl_close($ch);
const params = new URLSearchParams({
fromDate: "2026-09-01",
toDate: "2026-09-30",
limit: "50",
});
const response = await fetch(`https://one.ozow.com/v1/settlements?${params}`, {
headers: {
"Authorization": `Bearer ${accessToken}`,
"Accept": "application/json",
"X-Correlation-ID": crypto.randomUUID(),
},
});
const data = await response.json();
import requests, uuid
response = requests.get(
"https://one.ozow.com/v1/settlements",
params={"fromDate": "2026-09-01", "toDate": "2026-09-30", "limit": 50},
headers={
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
"X-Correlation-ID": str(uuid.uuid4()),
},
)
data = response.json()
What comes back
{
"links": { "self": "...", "next": "..." },
"results": [
{
"links": {
"self": "https://one.ozow.com/v1/settlements/497f6eca-...",
"lineItems": "https://one.ozow.com/v1/settlements/497f6eca-.../lineitems"
},
"id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
"totalSettlement": { "currency": "ZAR", "value": 12450.00 },
"totalFees": { "currency": "ZAR", "value": 187.25 },
"lineItemCounts": {
"total": 63,
"transaction": 60,
"refund": 2,
"adjustment": 1,
"payout": 0
},
"reference": "OZOW20260901ACME",
"date": "2026-09-01",
"bank": {
"institutionId": "7c02f304-...",
"institutionName": "Example Bank",
"accountNumber": "1234567890",
"branchCode": "5040"
}
}
],
"meta": { "totalPages": 1, "totalItems": 1 }
}
The fields you'll use:
| Field | Use it for |
|---|---|
id |
Your primary key, and the path parameter for line items |
reference |
Matching to your bank statement: this is the reference that appears there |
total |
The amount transferred to you |
total |
Ozow fees across the settlement |
line |
A quick check that you've retrieved everything |
links. |
The URL for step 2, follow it rather than building it yourself |
bank |
Which of your accounts the settlement went to |
Amounts are objects, not numbers: { "currency": "ZAR", "value": 12450.00 }. Read value, and
check currency if you take payments in more than one.
There's no status on a settlement in the One API. If you need to know whether the money has
actually landed, your bank statement is the answer.
Step 2: Fetch the line items
Follow the links.lineItems URL from step 1, or build it:
GET https://one.ozow.com/v1/settlements/{id}/lineitems?limit=50&offset=0
curl -X GET "https://one.ozow.com/v1/settlements/497f6eca-6276-4993-bfeb-53cbbbba6f08/lineitems?limit=50" \
-H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
-H "Accept: application/json"
var url = $"https://one.ozow.com/v1/settlements/{settlementId}/lineitems" + "?limit=50&offset=0";
var response = await client.GetAsync(url);
var body = await response.Content.ReadAsStringAsync();
$url = "https://one.ozow.com/v1/settlements/{$settlementId}/lineitems"
. '?limit=50&offset=0';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $accessToken,
'Accept: application/json',
],
]);
$response = curl_exec($ch);
curl_close($ch);
const response = await fetch(
`https://one.ozow.com/v1/settlements/${settlementId}/lineitems?limit=50&offset=0`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
Accept: "application/json",
},
},
);
const data = await response.json();
response = requests.get(
f"https://one.ozow.com/v1/settlements/{settlement_id}/lineitems",
params={"limit": 50, "offset": 0},
headers={
"Authorization": f"Bearer {access_token}",
"Accept": "application/json",
},
)
data = response.json()
Each line item looks like this:
{
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"siteCode": "ACM-ACM-001",
"reference": "ORDER-10432",
"description": null,
"amount": { "currency": "ZAR", "value": 250.00 },
"fee": { "currency": "ZAR", "value": 3.75 },
"settlementAmount": { "currency": "ZAR", "value": 246.25 },
"date": "2026-08-29",
"type": "transaction"
}
| Field | Use it for |
|---|---|
reference |
Matching to your own records: this is your reference for the transaction, refund or payoutPayout Money sent from a merchant to a bank account. Unlike a refund, a payout is not tied to a payment anyone made you, so you can pay anyone with a bank account. Payouts draw on your float rather than on your incoming payments, and they are not self-service: they need approval from Ozow and testing in staging first. |
type |
What kind of record this is. See below, this matters more than you'd expect |
amount |
The original amount of the record |
fee |
The Ozow fee for it |
settlement |
amount − fee. What this record contributed to the settlement |
site |
Which of your sites it belongs to |
date |
The date the record applies to |
description |
Mostly populated on adjustments: read it when you see one |
Understanding line item types
A settlement is not just customer payments. The type field tells you what each record is, and your
reconciliation needs to handle all of them:
| Type | What it is |
|---|---|
transaction |
A customer payment |
refund |
A refund you issued |
payout |
A payout you sent |
returnedrefund |
A refund that came back |
returnedpayout |
A payout that came back |
fee |
A fee charged as its own line |
adjustment |
A manual correction. Read description |
chargeback |
A disputedDispute A customer challenging a completed card payment through their own bank. A successful dispute becomes a chargeback and reverses the funds. Distinct from a refund, which you initiate and control. card payment reversed |
withheldreserve |
Funds held back as reserve |
releasedreserve |
Reserve funds released back to you |
withheldchargeback |
Funds held against a chargebackChargeback A completed card payment reversed by the customer's bank after a successful dispute. The funds come back out, and the process runs between the banks rather than through Ozow, so it is not something you can approve or refuse. Your transaction records and delivery confirmations are what it is decided on. |
releasedchargeback |
Chargeback funds released back to you |
Two consequences worth designing for.
Don't assume every line item is a sale. Code that treats all line items as customer payments
will double-count refunds and misreport your revenue. Branch on type.
Handle unknown types gracefully. New types get added. Log anything you don't recognise and surface it for review rather than dropping it or crashing.
Fees and rounding
Fees are applied per record and the settlement total is calculated from them, so settlementAmount
on each line is amount − fee.
The line item fees will not always add up to totalFees.
Fees on individual records are
rounded, while totalFees is calculated off total amounts or counts. Small differences are
expected and are not an error. If your reconciliation asserts that the two match exactly, it will
fail on real data.
Reconcile using totalSettlement against your bank deposit, and use settlementAmount per line for
allocating to your own records.
Paging
Both list endpoints page: limit (max 50) and offset, with meta.totalPages and
meta.totalItems telling you how much is there, and links.next giving you the next page.
Follow links.next until it's absent rather than incrementing offset yourself, it's less to get
wrong. Use lineItemCounts.total from step 1 to confirm you've retrieved every line item for a
settlement.
Step 3: Match settlements to your bank account
Match on reference. It's the settlement reference that appears on your bank statement, which
makes it a reliable join. Confirm totalSettlement.value agrees with the deposit.
Don't match on amount and date alone, two settlements of the same value in the same week is entirely possible.
Step 4: Match line items to your records
Match on the line item reference, which is your own reference for the transaction, refund or
payout. That's the most reliable join because it's your identifier; so set a meaningful one when you
create payments and payouts.
Adjustments are the exception: Ozow generates the reference, and description is what tells you
what happened.
If you run multiple sites, key on siteCode and reference together rather than reference alone.
Step 5: Flag what doesn't match
Check both directions:
- Line items you can't place: a settled record with no matching entry in your system
- Records you expected to see settled but didn't: a completed payment that hasn't appeared in any settlement
Give the second a tolerance window: a transaction that completed just before this run and hasn't settled yet is normal; one well past its expected cycle isn't.
Also flag any adjustment, chargeback or reserve line item. These are not routine and they
originate outside your system, so review each one.
Next steps
- Full field lists, parameters and error responses; One API reference
- How settlements work, Settlements
- Statuses across transactions and settlements, Transaction and settlement statuses
- On the legacy API?, Reconcile settlements
In the API reference
3 entries
Last updated