← Ahadi
Developers

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 dashboard

2. 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.

Supported events
  • escrow.funded — buyer paid, funds held
  • escrow.released — funds released to seller
  • escrow.refunded — order refunded
  • escrow.disputed — dispute opened
  • link.paid — payment link succeeded
Request headers
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>
Verify the signature (Node)
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.