Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.winampay.de/llms.txt

Use this file to discover all available pages before exploring further.

Overview

When a transaction reaches a terminal state (succeeded or failed), winam-payments sends a POST JSON request to your callback_url.
Webhooks are the recommended way to receive payment outcomes — faster and more reliable than polling. Always provide a callback_url in your deposit and withdrawal requests.

Webhook payload

{
  "winam_tx_id":    "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "reference":      "platform-bet-slip-98765",
  "event":          "payment.succeeded",
  "direction":      "deposit",
  "amount_xaf":     5000,
  "operator":       "mtn",
  "provider_tx_id": "MTN2025010112345",
  "ts":             "2025-01-01T12:07:43.123456+00:00"
}
FieldPossible values
eventpayment.succeeded or payment.failed
directiondeposit or withdrawal
provider_tx_idProvider-side reference (null if not available)
tsISO 8601 UTC timestamp of the event

Signature verification

Each webhook includes an X-Winam-Signature header containing a JWT RS256 token signed with Winam’s private key. Always verify this signature before processing the webhook.
1

Fetch the public key (once)

curl https://payments.winam.cm/api/v1/security/callback-public-key
Cache this response — the key rotates rarely.
2

Verify the signature

import jwt
import httpx

# 1. Fetch the public key (cache this)
r = httpx.get("https://payments.winam.cm/api/v1/security/callback-public-key")
public_key = r.json()["public_key_pem"]

# 2. Verify the received webhook
def verify_webhook(request_headers: dict, request_body: dict) -> bool:
    signature = request_headers.get("X-Winam-Signature")
    if not signature:
        return False
    try:
        decoded = jwt.decode(
            signature,
            public_key,
            algorithms=["RS256"],
        )
        return decoded["winam_tx_id"] == request_body["winam_tx_id"]
    except jwt.InvalidTokenError:
        return False

Retry policy

winam-payments retries 3 times with exponential backoff (1 s → 2 s → 4 s) if your endpoint responds with a status ≥ 400 or does not respond within 5 seconds. Your endpoint must:
  • Respond 2XX within 5 seconds
  • Be idempotent — the same winam_tx_id may be delivered more than once
  • Return 200 even if the event was already processed
If all retries fail, no further delivery attempts are made. Use Replay Callback for manual recovery.
For the public key endpoint reference, see Callback Public Key.