Ozow Hub
On this page11 sections
Build with AI 2 packages

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.

  • Refund a paymentEverything needed to refund a completed payment through One API, in full or in part, and to handle the statuses a refund moves through.
    View package
  • Migrate refunds from the Payments API to One APIEverything needed to move an existing refunds integration onto One API, with the legacy guide and its One API counterpart side by side.
    View package

This guide walks you through issuing refunds to your customers using One API. Refunds are merchant-initiated backend operations, there is no customer-facing step. The entire flow happens in your backend.

This guide uses the One API: Ozow's recommended API for all new integrations.

Already integrated? If your integration posts to api.ozow.com and builds a SHA512SHA-512 A hashing algorithm. Ozow uses it to sign the values in a request or a notification so you can tell that they arrived unaltered and came from us. Hashing is one-way: the hash cannot be turned back into what produced it.Wikipedia hash, you're on the Payments API: see Refund a payment under Legacy integrations, or Migrating to One API.

FloatFloat The balance held with Ozow that payouts and refunds are paid out of. Both draw on it, and neither will process while it is empty. Payins do not need one, so if you only take payments you never meet it. required

Ozow uses your float balance to fund refunds. Make sure your float has sufficient funds before issuing refunds. See the Float top-up guide to load funds into your float.

Before you start

  • You have a valid One API access token: see Step 1: Obtain an access token for the token flow
  • Your One API client must have the refunds scope, and your token must request it. A token issued for payments alone is refused by every endpoint on this page
  • Your float balance is sufficient to cover the refund amount
  • You have the transaction ID of the original payment you want to refund

Environments

Environment Base URL Dashboard
Production https://one.ozow.com/v1 dash.ozow.com
Staging https://stagingone.ozow.com/v1 stagingdash.ozow.com

How refunds work

You can request a refund two ways: against a specific transaction, or as a batch of one or more refunds in a single call. Both create the same kind of refund resource and follow the same lifecycle.


Refund a single transaction

Use this to refund a specific payment. You can issue a full refund or a partial refund by specifying the amount.

POST Request Refund Reference
POST https://one.ozow.com/v1/transactions/{id}/refunds
Authorization: Bearer YOUR_ACCESS_TOKEN
Idempotency-Key: YOUR_UNIQUE_KEY
Content-Type: application/json

Replace {id} with the transaction ID of the original payment.

Idempotency keyIdempotency A request is idempotent when sending it twice has the same effect as sending it once. It matters most where a retry after a timeout could otherwise take a payment twice.IETF draft

Include a unique Idempotency-Key header with every refund request. If a request fails and you retry, using the same idempotency key prevents the refund from being processed twice.

curl -X POST "https://one.ozow.com/v1/transactions/497f6eca-6276-4993-bfeb-53cbbbba6f08/refunds" \
  -H "Authorization: Bearer <YOUR_ACCESS_TOKEN>" \
  -H "Idempotency-Key: YOUR_UNIQUE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": {
      "currency": "ZAR",
      "value": 50.00
    },
    "reason": "Order cancellation",
    "realTimePayment": false
  }'

Key request fields

Field Type Required Description
amount.currency string Yes Must be ZAR
amount.value number Yes Amount to refund. Must not exceed the original transaction amount
reason string Yes Reason for the refund
realTimePayment boolean Yes Whether the refund pays out in real time. See Ozow Pricing for the cost of real-time refunds. Defaults to false
notifyUrl string No URL to notify of the refund status. Use webhooks instead: see Handling the refund outcome

For the full list of request fields see Request Refund.

Successful response

{
  "links": {
    "self": "https://one.ozow.com/v1/refunds/6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "cancel": "https://one.ozow.com/v1/refunds/6ba7b810-9dad-11d1-80b4-00c04fd430c8/cancel"
  },
  "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
  "transactionId": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
  "amount": {
    "currency": "ZAR",
    "value": 50.00
  },
  "requested": "2026-01-01T00:00:00Z",
  "status": "Pending",
  "reason": "Order cancellation",
  "realTimePayment": false
}

Store the refund id, you can use it to check the status of the refund.

To see the refunds already requested against a transaction, GET the same endpoint:

GET Get Refunds Reference
GET https://one.ozow.com/v1/transactions/{id}/refunds
Authorization: Bearer YOUR_ACCESS_TOKEN

Refund multiple transactions in one request

POST /refunds submits a batch of refund requests, each against its own transaction. Use this when you need to issue several refunds at once; for a single refund it is simpler to use the transaction endpoint above.

POST Request Refunds Reference
POST https://one.ozow.com/v1/refunds
Authorization: Bearer YOUR_ACCESS_TOKEN
Idempotency-Key: YOUR_UNIQUE_KEY
Content-Type: application/json

Request example

[
  {
    "transactionId": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
    "amount": {
      "currency": "ZAR",
      "value": 50.00
    },
    "reason": "Order cancellation",
    "realTimePayment": false
  },
  {
    "transactionId": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
    "amount": {
      "currency": "ZAR",
      "value": 100.00
    },
    "reason": "Duplicate charge",
    "realTimePayment": false
  }
]

Key request fields

Field Type Required Description
transactionId string Yes The transaction ID of the payment being refunded
amount.currency string Yes Must be ZAR
amount.value number Yes Amount to refund. Must not exceed the original transaction amount
reason string Yes Reason for the refund
realTimePayment boolean Yes Whether the refund pays out in real time. Defaults to false
notifyUrl string No URL to notify of the refund status. Use webhooks instead

For the full list of request fields see Request Refunds.

Successful response

Ozow returns a Refund resource per item submitted, in the same shape shown above.


Check a refund's status

GET Get Refund Reference
GET https://one.ozow.com/v1/refunds/{id}
Authorization: Bearer YOUR_ACCESS_TOKEN

Replace {id} with the refund ID returned when you created the refund.

Cancel a refund

Cancels the refund if it can still be cancelled.

POST Cancel Refund Reference
POST https://one.ozow.com/v1/refunds/{id}/cancel
Authorization: Bearer YOUR_ACCESS_TOKEN
Idempotency-Key: YOUR_UNIQUE_KEY
Content-Type: application/json

Request body

{
  "reason": "Requested in error"
}

reason is required. A successful cancellation returns 200 OK with no response body.

List refunds

Retrieve a paginated list of refunds filtered by date range.

GET List Refunds Reference
GET https://one.ozow.com/v1/refunds?fromDate=2026-01-01T00:00:00Z&toDate=2026-01-31T23:59:59Z
Authorization: Bearer YOUR_ACCESS_TOKEN

Query parameters

Parameter Type Required Description
fromDate string Yes Start of date range, ISO 8601ISO 8601 The international standard for writing dates and times, such as 2026-03-14T09:30:00Z. Unambiguous about ordering and time zone, which local formats are not.Wikipedia date-time
toDate string Yes End of date range, ISO 8601 date-time
limit integer No Maximum items to return. 1 to 50, defaults to 50
offset integer No Number of items to skip, defaults to 0
siteCode string No Filter to a single site codeSite code The unique code for a site registered under a merchant. A site is a place to transact: a website, or a branch of a store. A merchant can have several, and each transaction names the one it belongs to, so sending the wrong code files the payment against the wrong place.

Successful response

{
  "links": {
    "self": "https://one.ozow.com/v1/refunds?fromDate=2026-01-01T00:00:00Z&toDate=2026-01-31T23:59:59Z&offset=0"
  },
  "results": [
    {
      "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "transactionId": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
      "status": "Complete"
    }
  ],
  "meta": {
    "totalPages": 1,
    "totalItems": 1
  }
}

Refund statuses

Status Description
pending The refund request has been submitted and accepted
submitted The refund has been assigned to a batch and is being processed
complete The refund has been paid successfully
failed The refund payment has failed
cancelled The refund was cancelled before it was submitted
returned The refund payment was returned because the destination account no longer exists

Handling the refund outcome

Ozow sends a refund.complete webhookWebhook A URL of yours that Ozow calls when something happens, rather than you polling to find out. The call carries no credential of yours and arrives at a public URL, so authenticate it before acting on it: a hash field on the Payments API, a Svix signature on One API. when a refund completes. Handle it the same way as a payment webhook, verify the Svix signature before acting on it.

See Step 4: Handle the webhook notification in the One API 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. guide for the full webhook verification process.

Note

Handle duplicate refund notifications idempotently. Receiving the same notification twice must not result in issuing a double refund.


Next steps

In the API reference

8 entries

Last updated