Skip to content
Jennifer Programming Language

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 URL
  • payload {string} - the request body
  • secret {string} - the shared secret

Returns {http.Response} - the receiver's response (status / headers / body)

Throws

  • {Error} - on a network failure (a positioned http / net error)

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 body
  • secret {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 secret
  • body {string} - the exact request body
  • timestamp {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 secret
  • body {string} - the exact request body received
  • timestamp {int} - the request timestamp (seconds) from the header
  • signature {string} - the received v0=... header value
  • toleranceSeconds {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 secret
  • body {string} - the exact request body
  • timestamp {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 secret
  • body {string} - the exact request body received
  • header {string} - the received t=...,v1=... header value
  • toleranceSeconds {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 secret
  • body {string} - the exact request body
  • timestamp {int} - the unix timestamp (seconds) to stamp and sign
  • algo {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 secret
  • body {string} - the exact request body received
  • timestamp {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 seconds
  • now {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 received
  • signature {string} - the received signature, e.g. "sha256=..."
  • secret {string} - the shared secret

Returns {bool} - true if the signature is valid