Skip to main content
Custom-mode webhooks can be signed with HMAC-SHA256 so your server can reject spoofed payloads. Opt in by passing enable_signature: true when creating the webhook — backward-compatible, off by default.

Headers sent on every POST

The signed string is "{timestamp}.{raw_body}", joined with a literal dot. Use the raw request body — do not re-serialize the JSON, whitespace differences will break the check.

Verify on your server

Reject requests where X-Linkup-Timestamp is more than ~5 minutes off from your current clock — protects against replay of an old captured payload.

Rotate the secret

POST /v2/webhooks/{webhook_id}/rotate-secret Generates a fresh secret. The previous one is invalidated immediately, so deploy the new secret to your verifier before calling this. Returns the new secret in plaintext once.

Disable signing

DELETE /v2/webhooks/{webhook_id}/secret Clears the secret. Subsequent POSTs go out without X-Linkup-Signature headers.

Notes

  • Hosted-mode webhooks (SSE/polling) are not signed — they are already authenticated by your api_key on the stream URL.
  • Legacy V1 webhooks (webhook_url on the account doc) are not signed. V2-only feature.
  • disconnection events are signed too when signing is enabled on the webhook.
  • GET /v2/webhooks returns signature_enabled: true|false. The secret itself is never returned by list/get — if you lose it, rotate.