webhook API reference
Sign and verify HMAC-signed webhooks - the GitHub-style X-Hub-Signature-256 convention. A sender computes sha256=<hex>, the hex HMAC-SHA256 of the exact request body keyed by a shared secret, and sends it in a header; a receiver recomputes it and compares, confirming the delivery is authentic and untampered. sign / verify are pure and run on both binaries; send POSTs a payload with the signature header and needs the default binary (net via http).
Import with import "webhook.j" as webhook;. See the webhook guide for prose and examples.
Functions
webhook.send(url as string, payload as string, secret as string)
POST a payload to a webhook URL with the X-Hub-Signature-256 header set, returning the receiver's HTTP response. The body is sent as application/json (the common webhook content type). Inspecting the result needs import "http.j" for the http.Response type.
Parameters
url{string}- the receiver URLpayload{string}- the request bodysecret{string}- the shared secret
Returns {http.Response} - the receiver's response (status / headers / body)
Throws
{Error}- on a network failure (a positionedhttp/neterror)
webhook.sign(payload as string, secret as string)
Sign a payload: sha256= followed by the hex HMAC-SHA256 of the payload keyed by the shared secret - the value a receiver checks in X-Hub-Signature-256.
Parameters
payload{string}- the exact request bodysecret{string}- the shared secret
Returns {string} - the signature, e.g. "sha256=757107ea..."
webhook.slackSign(secret as string, body as string, timestamp as int)
Sign a payload the Slack way: the signed base string is "v0:" + <timestamp> + ":" + <body>, HMAC-SHA256, hex-encoded, and the returned value is v0=<hexsig> (the X-Slack-Signature shape). The timestamp travels separately in X-Slack-Request-Timestamp.
Parameters
secret{string}- the Slack signing secretbody{string}- the exact request bodytimestamp{int}- the unix timestamp (seconds), the request timestamp
Returns {string} - the signature, e.g. "v0=a2114d57..."
webhook.slackVerify(secret as string, body as string, timestamp as int, signature as string, toleranceSeconds as int, now as int)
Verify a Slack v0=... signature against a body, secret, and the request timestamp (from X-Slack-Request-Timestamp). Recomputes the HMAC-SHA256 over "v0:" + <timestamp> + ":" + <body> and constant-time compares. Returns true only if the signature matches AND the timestamp is within toleranceSeconds of now (replay protection, e.g. 300s).
Parameters
secret{string}- the Slack signing secretbody{string}- the exact request body receivedtimestamp{int}- the request timestamp (seconds) from the headersignature{string}- the receivedv0=...header valuetoleranceSeconds{int}- the freshness window in seconds (e.g. 300)now{int}- the current unix time (seconds)
Returns {bool} - true if the signature is valid and the timestamp is fresh
webhook.stripeSign(secret as string, body as string, timestamp as int)
Sign a payload the Stripe way: the signed base string is <timestamp> + "." + <body>, HMAC-SHA256, hex-encoded, and the returned header value is t=<timestamp>,v1=<hexsig> (the Stripe-Signature shape).
Parameters
secret{string}- the endpoint signing secretbody{string}- the exact request bodytimestamp{int}- the unix timestamp (seconds) to stamp and sign
Returns {string} - the header value, e.g. "t=1492774800,v1=5257a8..."
webhook.stripeVerify(secret as string, body as string, header as string, toleranceSeconds as int, now as int)
Verify a Stripe t=...,v1=... signature header against a body and secret. Parses the timestamp and the (possibly several) v1= signatures, recomputes the HMAC-SHA256 over <t>.<body>, and constant-time compares. Returns true only if a signature matches AND the timestamp is within toleranceSeconds of now (replay protection).
Parameters
secret{string}- the endpoint signing secretbody{string}- the exact request body receivedheader{string}- the receivedt=...,v1=...header valuetoleranceSeconds{int}- the freshness window in seconds (e.g. 300)now{int}- the current unix time (seconds)
Returns {bool} - true if a signature is valid and the timestamp is fresh
webhook.timestampedSign(secret as string, body as string, timestamp as int, algo as string, encoding as string)
Generic timestamped HMAC signature: sign <timestamp> + "." + <body> with a caller-chosen digest and text encoding. Covers GitHub-style sha1/sha256 and hex/base64 schemes from one composable primitive.
Parameters
secret{string}- the shared secretbody{string}- the exact request bodytimestamp{int}- the unix timestamp (seconds) to stamp and signalgo{string}- the HMAC digest: "sha1" or "sha256"encoding{string}- the text encoding: "hex" or "base64"
Returns {string} - the encoded signature (no scheme prefix)
webhook.timestampedVerify(secret as string, body as string, timestamp as int, signature as string, algo as string, encoding as string, toleranceSeconds as int, now as int)
Verify a generic timestamped HMAC signature (see timestampedSign) with a constant-time compare and a replay-protecting freshness check. Returns true only if the signature matches AND the timestamp is within toleranceSeconds of now.
Parameters
secret{string}- the shared secretbody{string}- the exact request body receivedtimestamp{int}- the request timestamp (seconds)signature{string}- the received signature (encoded, no prefix)algo{string}- the HMAC digest: "sha1" or "sha256"encoding{string}- the text encoding: "hex" or "base64"toleranceSeconds{int}- the freshness window in secondsnow{int}- the current unix time (seconds)
Returns {bool} - true if the signature is valid and the timestamp is fresh
webhook.verify(payload as string, signature as string, secret as string)
Verify a signature against a payload and secret, with a constant-time compare.
Parameters
payload{string}- the exact request body receivedsignature{string}- the received signature, e.g. "sha256=..."secret{string}- the shared secret
Returns {bool} - true if the signature is valid