RebbeHub
עב · EN
RebbeHub

התיעוד למפתחים כתוב באנגלית.

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: null means 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 seq you 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.