Getting started
- 1Register an HTTPS endpoint in your dashboard.
- 2Verify the signature header on each incoming request.
- 3Respond with 2xx quickly; we retry failures with backoff.
Event types
| Event | Description |
|---|---|
transfer.created | A transfer was initiated. |
transfer.completed | A transfer settled successfully to the recipient. |
transfer.failed | A transfer failed and funds were reversed. |
payout.completed | A payout to a beneficiary settled. |
payment.succeeded | A collection / checkout payment succeeded. |
payment.refunded | A payment was refunded. |
wallet.credited | A wallet received funds. |
wallet.debited | A wallet was debited. |
kyc.updated | A customer KYC status changed. |
Example payload
{
"id": "evt_1a2b3c",
"type": "transfer.completed",
"created": 1730000000,
"data": {
"transferId": "trf_9x8y7z",
"amount": 1500.00,
"currency": "ETB",
"status": "completed"
}
}Signature verification
Every delivery includes an Amnen-Signature header containing a timestamp and an HMAC-SHA256 signature of `${timestamp}.${rawBody}`, computed with your endpoint's signing secret. Verify it before trusting a payload.
import crypto from 'crypto';
function verify(rawBody, header, secret) {
const [tsPart, sigPart] = header.split(',');
const timestamp = tsPart.replace('t=', '');
const signature = sigPart.replace('v1=', '');
// 1. Replay protection: reject anything older than 5 minutes.
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
throw new Error('Timestamp outside tolerance — possible replay');
}
// 2. Recompute the HMAC and compare in constant time.
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
throw new Error('Invalid signature');
}
}Timestamp & replay protection
The signed timestamp lets you reject stale or replayed requests — discard any event more than 5 minutes old. Events also carry a unique id; store processed ids and ignore duplicates so a redelivery is never processed twice (idempotent consumption).
Retries & delivery
- Return a 2xx quickly (within 5s). Any non-2xx or timeout is treated as a failure.
- Failed deliveries are retried with exponential backoff over ~24 hours.
- Because each event has a stable id, retries are safe — dedupe on your side.
- Endpoints that keep failing are automatically disabled and surfaced in your dashboard.