GitHub Marketplace integration

Marketplace webhook

A signed, idempotent HTTPS POST endpoint that accepts the GitHub Marketplace marketplace_purchase topic. Post the URL below into the publisher UI; set the secret once; duplicate deliveries are accepted idempotently.

Webhook URL — paste into the publisher

https://getbivouac.com/api/marketplace-webhook

Signature scheme

Every delivery must arrive with an HMAC over the raw body bytes using GITHUB_MARKETPLACE_WEBHOOK_SECRET as the key.

Header
X-Hub-Signature-256: sha256=<lowercase hex>
Algorithm
HMAC-SHA256
Input
Raw request body (literal bytes)
Content-Type
application/json

The endpoint also accepts the legacy X-Hub-Signature: sha1=<hex> fallback until the publisher UI migrates. Both are recomputed locally over the same raw bytes; sha512 (or any non-sha256 / non-sha1 prefix) is rejected with a 401.

Implemented events

Bivouac processes exactly five actions on the marketplace_purchase topic — the documented plan-lifecycle signals for the dependency-remediation listing. Any other topic or any other action is rejected with 400so a delivery is never silently 200'd on something Bivouac doesn't implement.

Idempotency

Every delivery carries an X-GitHub-Delivery UUID. We key the persistence layer on this UUID with a unique index, so a replayed delivery matches a row that already exists on the second arrival and acknowledges with 200 { accepted: true, duplicate: true } — no side effects rerun.

Publisher configuration

  1. In the GitHub Marketplace publisher UI, open Listings and paste the webhook URL above into Webhook URL.
  2. Set Webhook secretto a fresh random string; paste the same value into the operator's GITHUB_MARKETPLACE_WEBHOOK_SECRET deploy env. The endpoint never echoes the secret.
  3. Select only the marketplace_purchase topic — other Marketplace topics and GitHub App webhook events are not part of this endpoint.
  4. Submit the listing. The first delivery will arrive with X-GitHub-Delivery populated; verify the deferred JSON page in the operator console to confirm the row landed.