Webhook keys
The JWKS endpoint Relu publishes for verifying webhook signatures, plus how key rotation works.
Relu signs every outbound webhook with Ed25519. The public verification keys are served openly at:
GET https://api.automate.relu.ai/.well-known/webhook-keys.jsonThere is no shared secret — anything you need to verify a callback is in the JWKS. See Callbacks → Security for the full verification example.
Response shape
JWKS-compatible (RFC 7517) so existing tooling (jose for Node, python-jose / cryptography for Python) understands it:
{
"keys": [
{
"kty": "OKP",
"crv": "Ed25519",
"alg": "EdDSA",
"use": "sig",
"kid": "2026-04",
"x": "<base64url-32-byte-public-key>"
}
]
}x is the raw 32-byte Ed25519 public key encoded as base64url with no padding. Multiple keys appear during rotation windows (see below).
The endpoint sets Cache-Control: public, max-age=300, stale-while-revalidate=86400. Receivers should respect that — refetching every request is wasteful and adds a hard dependency on the endpoint being reachable.
Choosing the right key
Each callback's X-Relu-Signature header carries the kid of the key that signed it:
X-Relu-Signature: kid=2026-04;alg=ed25519;sig=…Look up the entry whose kid matches and verify against that key's x. If the kid is not in your cached JWKS, refresh the JWKS once and try again — receivers that always re-verify after a refresh handle rotation transparently.
Rotation
Keys are rotated periodically. The transition is overlap-based — both the old and new key are served at the same time so receivers can swap keys without coordinated downtime:
- New key published. The JWKS lists both the previous active key and the new one. Receivers refresh on their next cache miss.
- Cutover. Some time later, Relu starts signing with the new
kid. Callbacks already in flight may still be signed with the oldkid— both keys remain in the JWKS during this window. - Old key retired. ~30 days after cutover the old key is removed from the JWKS.
Practical implication: cache the JWKS for at least 5 minutes (so we don't hammer your network), but no longer than ~1 hour (so a forced rotation propagates within the same business day). Treat an unknown kid as a hint to refresh.
Verifying offline
The JWKS is served over HTTPS and is a thin GET. We recommend caching it in-process — a per-process map keyed by base URL is enough. There is no need to persist it; rebooting your service and refetching is safe.