Build escrow into your product
REST endpoints, HMAC-signed webhooks and a merchant dashboard. Get started in minutes with an API key from your merchant workspace.
1. Get an API key
Sign in and open the merchant dashboard → API keys tab. Click Create key, name it, pick read-only or read+write, and copy the key that appears — it's shown exactly once and stored hashed.
Open merchant dashboard2. Make your first request
All endpoints live under /api/v1. Send your key as a Bearer token.
curl https://ahadi.app/api/v1/escrow_orders \
-H "Authorization: Bearer ahadi_..."Response shape:
{
"data": [
{
"id": "uuid",
"public_id": "AH-12345",
"title": "Order title",
"status": "funded" | "shipped" | "released" | "refunded" | "disputed",
"amount_minor": 250000,
"currency": "KES",
"buyer_email": "buyer@example.com",
"seller_email": "you@example.com",
"created_at": "2026-07-04T...",
"released_at": null,
"auto_release_at": "2026-07-11T..."
}
]
}3. Receive webhooks
Add an endpoint in the Webhooks tab. Ahadi POSTs a JSON payload to your URL every time a selected event fires, with headers you can use to verify authenticity.
escrow.funded— buyer paid, funds heldescrow.released— funds released to sellerescrow.refunded— order refundedescrow.disputed— dispute openedlink.paid— payment link succeeded
Content-Type: application/json
X-Ahadi-Event: escrow.funded
X-Ahadi-Delivery: <delivery UUID>
X-Ahadi-Timestamp: <unix seconds>
X-Ahadi-Signature: t=<ts>,v1=<hex sha256>import { createHmac, timingSafeEqual } from "crypto";
app.post("/webhooks/ahadi", express.raw({ type: "application/json" }), (req, res) => {
const header = req.header("X-Ahadi-Signature") ?? "";
const [tsPart, sigPart] = header.split(",");
const ts = tsPart.replace("t=", "");
const sig = sigPart.replace("v1=", "");
const expected = createHmac("sha256", process.env.AHADI_WEBHOOK_SECRET)
.update(`${ts}.${req.body.toString("utf8")}`)
.digest("hex");
const a = Buffer.from(sig, "hex");
const b = Buffer.from(expected, "hex");
if (a.length !== b.length || !timingSafeEqual(a, b)) {
return res.status(401).send("bad signature");
}
const event = JSON.parse(req.body.toString("utf8"));
// handle event.event and event.data ...
res.status(200).send("ok");
});We retry non-2xx responses with exponential backoff up to 8 attempts (roughly 1min → 2h). Respond within 10 seconds — otherwise the request times out and we retry.
Roadmap
Coming soon: POST /api/v1/escrow_orders, /api/v1/payment_links CRUD, subscription links, embedded checkout script, and per-key scope enforcement. Have a request? Emaildevelopers@ahadi.app.