Webhook
We can notify a registered pay widget merchant about the statuses of orders associated with him.
We will make a POST request to a provided webhook URL with the next application/json contents:
Webhook V1:
type WebhookRequest = {
"data": {
"status":
| "swap_initiated" // user has created an order
| "swap_expired" // an order has expired
| "swap_buyer_rejected" // user has rejected an order
| "swap_buyer_confirmed" // user has confirmed an order
| "swap_seller_rejected" // agent has rejected an order, happens when agent don't receive a payment
| "swap_seller_confirmed" // agent has confirmed an order
| "pending" // USDC/cUSD transaction is pending
| "complete" // USDC/cUSD transaction is complete
| "failed", // USDC/cUSD transaction has failed
"date": string, // date when event has happened
"orderId": string, // order id in our system
"phoneNumber": string, // customer phone number
"localCurrencyAmount": number, // amount of local currency user paid
"localCurrencyIsoCode": string, // ISO code of local currency user paid, e.g. KES, NGN etc.
"countryIsoCode": string, // ISO code of country user paid from, e.g. KE, NG etc.
"provider": // payment provider user paid with
| "carrier"
| "mpesa"
| "mobile_money"
| "bank_transfer"
"amount": number, // amount of USD user received
"amountCrypto": number, // amount of crypto user received
"network": // network user received USDC/cUSD on
| "POLYGON"
| "ETHEREUM"
| "STELLAR"
| "AVALANCHE"
| "SOLANA"
| "ALGORAND"
| "TRON"
| "CELO"
| "LISK",
"asset": "USDC" | "CUSD" | "USDT" | "USDC_E", // asset user received
"address": string, // address user received USDC/cUSD on
"orderParams"?: string // Content of a orderParams query parameter provided to a pay widget URL. It might be useful for matching a merchant system user to an order user.
"hash"?: string, // transaction hash
"resumeUrl": string, // URL where user can resume his order, it point either to the transfer instructions page or to the status page
},
"hash": string, // SHA256 encrypted request.data string to validate a webhook request
};
Webhook V2:
Instead of sending hash inside - WebhookRequest, we will send it as a request x-signature header
Request headers:
x-signature: hash (string)
Webhook verification:
We send a hash field in our webhook to protect merchants from fraudulent requests. Each request should be verified by a secret provided in the dashboard.
Here is how it should be checked in pseudocode:
request.body.hash === SHA256(stringify(request.body.data), secret)
Here is how it should be checked in Node.js:
For Webhook V1 version:
import { createHash } from 'crypto';
request.body.hash === createHash('sha256')
.update(JSON.stringify(request.body.data))
.update(createHash('sha256').update(__SECRET__, 'utf8').digest('hex'))
.digest('hex');
For Webhook V2 version:
import { createHash } from 'crypto';
request 'x-signature' header === createHash('sha256')
.update(JSON.stringify(request.body))
.update(createHash('sha256').update(__SECRET__, 'utf8').digest('hex'))
.digest('hex');