Webhooks

Registering an endpoint

If you would rather be called than hold a socket, register an HTTPS endpoint. We POST each matching event as the same JSON envelope, signed with HMAC-SHA256 over the raw body in X-XSF-Signature.

register — the secret is shown once
curl -X PUT https://api.xsignalfeed.com/v1/account/webhook \
  -H "Authorization: Bearer xsf_your_key" -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/xsf"}'

Verifying a delivery

Verify over the raw body. Re-serialising the parsed JSON changes the bytes and the signature will never match. Read the body as bytes before anything else touches it.
import hmac, hashlib

def valid(raw_body: bytes, signature: str, secret: str) -> bool:
    want = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(want, signature)

Retries and recovery

We retry three times on a non-2xx or a timeout, then drop that delivery. Nothing is queued forever. If your endpoint was down, take the last sid you stored and catch up with GET /v1/events or a replaying WebSocket — that, not the retry policy, is the real recovery path.