From 2b7c93c3a7888f99064b66fee1ee24be5f0dff21 Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Mon, 9 Nov 2026 23:28:32 +0000 Subject: [PATCH 1/2] doc: document webhook delivery formats --- open-catalog-api.oas.yaml | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/open-catalog-api.oas.yaml b/open-catalog-api.oas.yaml index c402527..4163c8a 100644 --- a/open-catalog-api.oas.yaml +++ b/open-catalog-api.oas.yaml @@ -32,6 +32,30 @@ info: 4. Webhook subscribers receive a `POST` on every change to software and publishers, so they do not need to poll. + ## Webhook delivery formats + + The webhook `format` determines the JSON body and authentication headers + sent to the webhook URL. Every delivery has `Content-Type: application/json` + and the `open-catalog-api-webhook/1.0` user agent. + + - **default**: the body is `{"event":"create","subject":"/software/{id}"}`. + When a secret is configured, `X-Webhook-Signature` contains the lowercase + hexadecimal HMAC-SHA256 of the raw request body, using the secret as the key. + - **github**: the URL is a GitHub + [`repository_dispatch`](https://docs.github.com/en/rest/repos/repos#create-a-repository-dispatch-event) + endpoint. The body is `{"event_type":"software.create","client_payload":{"event":"create","subject":"/software/{id}"}}`. + Requests include `Accept: application/vnd.github+json` and + `X-GitHub-Api-Version: 2022-11-28`. When configured, the secret is a + GitHub token sent as `Authorization: Bearer {secret}`. + - **standard-webhooks**: the body is + `{"type":"software.create","timestamp":"2026-01-02T15:04:05Z","data":{"event":"create","subject":"/software/{id}"}}`. + It includes `webhook-id`, `webhook-timestamp` (Unix seconds) and, when a + secret is configured, `webhook-signature`. The signature is + `v1,{base64(HMAC-SHA256(secret, "{id}.{timestamp}.{body}"))}`. + + The callback schemas below describe the default format. Consumers of the + other formats should use the delivery contract above. + ## Resources - **Software**: a piece of software and its `publiccode.yml`. @@ -2462,7 +2486,7 @@ components: ResourceCreate: '{$request.body#/url}': post: - description: The webhook called when a new resource is created + description: The webhook called in the default format when a new resource is created requestBody: required: true content: @@ -2490,7 +2514,7 @@ components: ResourceUpdate: '{$request.body#/url}': post: - description: The webhook called when a resource is updated + description: The webhook called in the default format when a resource is updated requestBody: required: true content: @@ -2518,7 +2542,7 @@ components: ResourceDelete: '{$request.body#/url}': post: - description: The webhook called when a resource is deleted + description: The webhook called in the default format when a resource is deleted requestBody: required: true content: From 13a15de6a3c52e8bb5bf1ea2e578e1418b6127fe Mon Sep 17 00:00:00 2001 From: Fabio Bonelli Date: Tue, 10 Nov 2026 01:23:40 +0000 Subject: [PATCH 2/2] doc: clarify Standard Webhooks signing --- open-catalog-api.oas.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/open-catalog-api.oas.yaml b/open-catalog-api.oas.yaml index 4163c8a..9920ee8 100644 --- a/open-catalog-api.oas.yaml +++ b/open-catalog-api.oas.yaml @@ -50,8 +50,10 @@ info: - **standard-webhooks**: the body is `{"type":"software.create","timestamp":"2026-01-02T15:04:05Z","data":{"event":"create","subject":"/software/{id}"}}`. It includes `webhook-id`, `webhook-timestamp` (Unix seconds) and, when a - secret is configured, `webhook-signature`. The signature is - `v1,{base64(HMAC-SHA256(secret, "{id}.{timestamp}.{body}"))}`. + secret is configured, `webhook-signature`. The secret is used as raw + UTF-8 bytes, not as a Base64 key with the `whsec_` prefix. The + signature is + `v1,{base64(HMAC-SHA256(secret, "{webhook-id}.{webhook-timestamp}.{body}"))}`. The callback schemas below describe the default format. Consumers of the other formats should use the delivery contract above.