Webhooks
Adeva Pro POSTs JSON events to a URL you control, signed with a Stripe-compatible Adeva-Signature header.
Configuring a receiver
curl -X PUT https://api.adevapro.com.au/v1/webhooks \
-H "Authorization: Bearer ak_live_…" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your.app/adeva/webhook" }'
On first configure (or whenever you rotate) the response includes a one-time newSecret starting with whsec_. Store it in your secret manager.
Event envelope
{
"id": "evt_abc123…",
"type": "debt.created",
"createdAt": "2026-05-27T11:42:31.123+00:00",
"data": { /* event-specific payload */ }
}
Events
debt.created,debt.updated,debt.accepted,debt.disputedpayment.received,plan.activated,plan.defaultedtest.ping— sent fromPOST /v1/webhooks/test
Signature verification
Adeva-Signature: t=<unix>,v1=<hex hmac-sha256>
Where v1 = HMAC_SHA256(secret, "<t>.<rawBody>"). Compare with constant-time equality. Reject if |now − t| > 300s.
Node.js
const crypto = require("crypto");
function verify(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(",").map(p => p.split("=")));
const t = parseInt(parts.t, 10);
if (Math.abs(Date.now()/1000 - t) > 300) throw new Error("stale");
const expected = crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1))) throw new Error("bad signature");
}
Python
import hmac, hashlib, time
def verify(raw_body, header, secret):
parts = dict(p.split("=", 1) for p in header.split(","))
t = int(parts["t"])
if abs(time.time() - t) > 300: raise ValueError("stale")
mac = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256)
if not hmac.compare_digest(mac.hexdigest(), parts["v1"]): raise ValueError("bad signature")
Retries
Non-2xx → retries at 1m / 5m / 30m / 2h / 12h / 24h. After 6 attempts the delivery is marked Failed and surfaced in your dashboard.
Treat events as at-least-once. Dedupe on the envelope id or the Adeva-Delivery-Id header.