Open Collections
Payload & Signatures
What we POST to your endpoint.
Event
Exactly one event: transaction.forwarded. Fires for every incoming MoMo payment that didn’t match an HPN code.
Payload
JSON
{
"event": "transaction.forwarded",
"webhook_id": "ocl_a1b2c3d4e5f6g7h8i9j0k1l2",
"timestamp": "2026-04-29T12:05:32Z",
"data": {
"transaction_id": "550e8400-e29b-41d4-a716-446655440000",
"telco_transaction_id": "73012849466",
"provider": "mtn",
"amount": "150.00",
"currency": "GHS",
"reference": "ACCT-44821",
"payer_phone": "0244123456",
"payer_name": "JOHN DOE",
"transaction_timestamp": "2026-04-29T12:05:30Z"
}
}| Field | Type | Description |
|---|---|---|
event | string | Always transaction.forwarded |
webhook_id | string | Stable ID for this delivery, prefix ocl_. Use it as your idempotency key. |
timestamp | string | ISO 8601, UTC |
data.transaction_id | string | Harpoon’s ID for the payment |
data.telco_transaction_id | string | null | Provider transaction ID |
data.provider | string | mtn, telecel, or at |
data.amount | string | Fixed-decimal string |
data.currency | string | Always GHS |
data.reference | string | null | The reference field from the payment — match against your scheme |
data.payer_phone | string | null | Display format 0XXXXXXXXX |
data.payer_name | string | null | As reported by the provider |
data.transaction_timestamp | string | ISO 8601, UTC |
Headers
| Header | Value |
|---|---|
X-Harpoon-Signature | sha256=<hex> |
X-Harpoon-Timestamp | Unix timestamp |
X-Harpoon-Webhook-ID | Same as webhook_id in body |
Content-Type | application/json |
User-Agent | Harpoon-Webhook/1.0 |
Verify the signature
Same HMAC-SHA256 scheme as Harpoon webhooks, using the secret returned at endpoint creation.
Idempotency
Use webhook_id as your idempotency key. Retried deliveries reuse the same webhook_id, and a re-ingest of the same underlying payment is deduplicated server-side — your handler should never need to re-process the same transaction_id.