Webhooks allow you to subscribe to certain events happening at W3C. When one of these events is triggered, we'll send a HTTP POST payload to the webhook's configured URL.
You can configure your webhooks from your profile.
When configuring a webhook, you can choose which events you would like to receive payloads for. You can change the subscribed events through the UI anytime.
Each event corresponds to a certain set of actions that can happen. For example, if you subscribe to the publication event you'll receive detailed payloads every time a technical report is published.
The available events are:
Name | Description |
---|---|
Publication (tr.published, tr.updated) | Any time a technical report is published or its metadata are updated |
Group Participation (group.participant_joined, group.participant_left) | Any time someone joins or leaves a group |
Connected Accounts (connected_account.created, connected_account.deleted) | Any time someone connects their W3C account to an external service such as GitHub, or removes such a connection |
This list of events will be progressively augmented.
HTTP requests made to your webhook's configured URL endpoint will contain several special headers:
Header | Description |
---|---|
X-W3C-Webhook | Link to the webhook that triggered the delivery |
X-W3C-Webhook-Id | ID of the webhook that triggered the delivery |
X-W3C-Webhook-Signature-256 | Signature of the payload, if a secret token was set. See below for more information |
X-W3C-Webhook-Signature-256-Base64 | Signature of the payload encoded in base64, if a secret token was set. See below for more information |
Payload of HTTP requests consists in a JSON fragment including the event that triggered the webhook, the exact time when the request was made, and one or several objects serialized in the same way as the API.
URL: http://example.org/my-webhook
Host: example.org
X-W3C-Webhook: https://www.w3.org/users/12345/webhooks/1
X-W3C-Webhook-Id: 1
{
"event": "tr.published",
"microtime": 1661495980.622211,
"specVersion": {
"status": "Working Draft",
"uri": "http://www.w3.org/TR/2016/WD-preload-20160120/",
"date": "2016-01-20",
"informative": false,
"title": "Preload",
"shortlink": "http://www.w3.org/TR/preload/",
"editor_draft": "http://w3c.github.io/preload/",
"process_rules": "http://www.w3.org/2015/Process-20150901/",
"_links": {
"self": {
"href": "https://api.w3.org/specifications/preload/versions/20160120"
},
"editors": {
"href": "https://api.w3.org/specifications/preload/versions/20160120/editors"
},
"deliverers": {
"href": "https://api.w3.org/specifications/preload/versions/20160120/deliverers"
},
"specification": {
"href": "https://api.w3.org/specifications/preload"
},
"predecessor-version": {
"href": "https://api.w3.org/specifications/preload/versions/20160120/predecessors"
}
}
}
}
For security reasons, you probably want to limit requests to those coming from W3C. To do so you can set up a secret token and validate the information received.
When creating or editing a webhook, you can fill out the Secret textbox. You should use a random key with high
entropy, for example by taking the output of LC_ALL=C tr -dc '[:alnum:]' < /dev/urandom | head -c20
from the terminal (on a GNU/Linux system).
Beware that once set, you won't be able to see this secret anymore. If you forget it, you will have to change it, which can be done when editing a webhook.
When your secret token is set, W3C uses it to create a hash signature with each payload. This hexadecimal
hash signature is included with the headers of each request as X-W3C-Webhook-Signature-256
.
We also send a Base 64 version of the signature as X-W3C-Webhook-Signature-256-Base64
.
To verify that this signature is correct, and thus that it indeed came from W3C, you need to compute hash using an HMAC hex digest, with the SHA-256 algorithm, and then compare this hash with the signature.
Here is a sample PHP code exhibiting how to verify the signature:
<?php
$body = file_get_contents('php://input');
$secret = $_ENV['SECRET_TOKEN'];
$signature = hash_hmac('sha256', $body, $secret);
if (hash_equals($signature, $_SERVER['HTTP_X_W3C_WEBHOOK_SIGNATURE_256'])) {
echo 'ok';
} else {
http_response_code(403);
}
Your language and server implementations may differ from this example code. However, there are a few important things to point out:
==
to compare the signature with the computed hash. Instead, use a method like
hash_equals
to perform a timing attack safe string comparison.