Skip to main content

Payout S2S callback

Once a fund transfer reaches a terminal state (SUCCESS, FAILED, RETURNED_FROM_BENEFICIARY), Omniware POSTs the result to the S2S URL configured against your merchant account.

Sample payload

{
"transaction_reference_number": "3a7bd60e92344ecb45a0a0047330000",
"status": "SUCCESS",
"error_message": null,
"bank_reference_number": 207517810965,
"merchant_reference_number": "C8V8o5knTyW2439y6nuiDDBWby",
"transaction_date": "2022-03-08 15:11:12",
"transaction_amount": "1.00",
"api_key": "YOUR_API_KEY",
"hash": "27FFA306D43ABC7553E4D55897012469E67C67CF0EC32B5F5A1480C297AD249E3EA00A4E65F4C7D4692857496CD0BDBBB92B2DB95AC1E8B894F9D9541218A7B9"
}

error_message is null on success and carries the bank's failure reason otherwise.

Status values

See Disbursement statuses for the full table.

Verifying the hash

hash = SHA512(salt + json_of_body_without_hash) uppercased — same convention as the Payments webhook.

import hashlib, hmac, json
from flask import Flask, request, abort

app = Flask(__name__)

@app.post("/webhooks/omniware/payouts")
def handle_payout():
body = request.get_json()
sent = body.get("hash")
if not sent:
abort(400)
rest = {k: v for k, v in body.items() if k != "hash"}
computed = hashlib.sha512(
(SALT + json.dumps(rest)).encode()
).hexdigest().upper()
if not hmac.compare_digest(sent, computed):
abort(400)
# idempotent processing keyed on merchant_reference_number
return "", 200

Idempotency

Use merchant_reference_number (your reference) as the idempotency key. If the same event is replayed or delivered again, the second arrival should be a no-op after you've processed the first.

Acknowledgement

Return 2xx only after the callback is hash-verified and safely recorded. The Fund Transfer PDF does not specify retry timing for failed webhook delivery; confirm the replay policy with Omniware before depending on automatic retries.