DevelopersUsing the API
Webhooks
Every approved change posted to you, signed.
Every change approved into the catalog can be posted to an address of yours, signed, within a few minutes.
Adding one#
On your account page (For developers: webhooks), or with a token that may write:
curl
curl -X POST https://api.rebbehub.org/v1/webhooks -H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' -d '{ "url": "https://example.org/rebbehub-hook" }'JSON
{ "id": 3, "url": "https://example.org/rebbehub-hook", "secret": "…" }The secret is shown this once: keep it to check signatures. Up to five addresses per person; GET /v1/webhooks lists yours, DELETE /v1/webhooks/<id> removes one.
What arrives#
Every merge from then on, in order and at least once, every few minutes:
HTTP
POST <your address>
Content-Type: application/json
X-RebbeHub-Signature: sha256=<HMAC-SHA256 of the body, keyed with the hook's secret>
{ "commits": [ { "seq": 9, "at": "…", "message": "…", "author": "…", "mergedBy": "…",
"changes": [ { "id": "rh-…", "type": "event", "path": "/events/…", "rev": 22993, "data": { … } } ] } ] }data: nullmeans the item was deleted.- Words withheld for rights are left out, as in
/v1/commits. - Answer with a 2xx status. Anything else is tried again; after 20 failures in a row the hook is switched off (the account page says so).
- Keep the last
seqyou handled: a commit may come twice.
Checking the signature#
TypeScript
import { createHmac, timingSafeEqual } from 'node:crypto';
function signed(body: string, header: string | null, secret: string): boolean {
const expected = `sha256=${createHmac('sha256', secret).update(body).digest('hex')}`;
return header !== null && header.length === expected.length && timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}Check it against the raw body, before parsing it.
Without a server#
GET /v1/commits?since=<seq> answers the same commits, a page at a time (pages): poll it instead when you cannot receive posts.