Skip to content

Webhooks

Webhooks provide durable notifications for account and API-key connection changes. Create and manage subscriptions under /webhooks with an authenticated user session.

Supported events

  • account.linked
  • account.unlinked
  • key.added
  • key.deleted

Only events emitted by this server are accepted. A newly saved API key emits key.added; replacing the value for an already-connected provider does not create a second event. The /webhooks/{id}/test endpoint queues a webhook.test delivery independently of the subscription's event list.

Destination and secret safety

Destinations must use HTTPS and resolve exclusively to public IP addresses. The server rejects credentials, fragments, loopback, link-local, private, .local, and mixed public/private DNS answers. Each delivery revalidates DNS, connects to one validated IP, and retains the original hostname for the HTTP Host header, TLS SNI, and certificate verification. Redirects and environment proxies are disabled.

A webhook secret is returned only when a subscription is created or its secret is rotated. Store it securely; later API responses expose only a short hint.

Delivery authentication

Each request includes:

  • X-Subconscious-Event
  • X-Subconscious-Delivery
  • X-Subconscious-Timestamp
  • X-Subconscious-Signature

The signature is sha256= followed by the lowercase hex HMAC-SHA256 of this byte sequence:

timestamp + "." + delivery_id + "." + event_type + "." + compact_json_body

Use the webhook secret as the HMAC key, compare signatures in constant time, reject stale timestamps, and use the delivery ID as an idempotency key. Metadata is included in the signed input, so changing the timestamp, delivery ID, event type, or body invalidates the signature.

Durability and retries

Deliveries are persisted in SQLite before the triggering account mutation commits. The single application worker resumes due rows after restart. Network failures, HTTP 408, HTTP 429, and 5xx responses receive bounded exponential retries. Other 4xx responses are terminal. Response bodies are never retained or buffered.

Delivery is at least once: receivers must deduplicate by X-Subconscious-Delivery. Disabling a subscription pauses queued rows; deleting it removes its delivery history. The embedded SQLite design requires exactly one application replica and one Uvicorn worker, as described in the production checklist.