Developers
Subscribe to
the events.
Pipe partner program events directly into your CRM, your audit trail, or your billing reconciliation. Every delivery is signed with HMAC SHA 256 and retried with backoff until you 200 us.
Event catalog
partner.approvedApplication moved to APPROVED. Referral link goes live.
partner.suspendedStatus changed to SUSPENDED with a reason.
tier.promotedAuto promotion fired on the nightly review.
commission.createdNew commission row, status PENDING, source amount and FX rate stamped.
commission.approvedHold elapsed, commission moved from PENDING to APPROVED.
commission.reversedSubscription cancelled inside the hold window. Pending commission reversed.
commission.paidCommission settled into a payout that was marked PAID.
payout.createdMonthly aggregator bundled approved commissions into a PENDING payout.
payout.paidWise transfer completed. Status PAID with reference.
payout.failedTransfer rejected by the rail. Reason on file.
Verify a delivery
Constant time HMAC compare.
Every payload arrives with an `x-rook-signature` header. Compare it against your secret in constant time. Fail closed on any mismatch.
// Express receiver
import express from 'express';
import crypto from 'node:crypto';
const SECRET = process.env.ROOK_FRIENDS_WEBHOOK_SECRET!;
app.post(
'/webhooks/rook-friends',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.headers['x-rook-signature'] as string;
const body = req.body.toString();
const expected = crypto
.createHmac('sha256', SECRET)
.update(body)
.digest('hex');
const ok = signature.length === expected.length &&
crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
if (!ok) {
return res.status(401).json({ error: 'bad signature' });
}
const { event, payload } = JSON.parse(body);
handle(event, payload);
res.json({ ok: true });
},
);// Subscribe via the API
await fetch('https://api.rookfriends.com/api/v1/partner/webhooks', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json',
'x-rook-csrf': csrfToken,
},
body: JSON.stringify({
workspaceId: '<your workspace>',
url: 'https://your.app/webhooks/rook-friends',
events: ['commission.created', 'payout.paid'],
}),
});
// Response includes a one-time secret you store
// for HMAC verification on the receiving side.Subscribe
One POST. One secret.
Pick the events, point a URL at it, store the secret we hand back exactly once. Failed deliveries retry on backoff: one minute, five minutes, thirty minutes, one hour. Ten consecutive failures pauses the subscription so we do not hammer a dead endpoint.
Idempotency keys
Send Idempotency-Key on POST writes. Same key, same response, never run twice.
Audit immutable
Every state change writes a partner_events row. The table is append only at the database level.
Replay safe
External event IDs prevent duplicate commissions even when upstream redelivers.
Want to see this wired up?
Apply for access