Signs and verifies Gaiia webhook deliveries.
Verification requires the exact raw request body bytes. Parsing JSON and then
re-encoding it can change those bytes and break the signature. In Phoenix,
cache the raw body with a custom body reader before Plug.Parsers decodes it.
Subscriptions
Endpoints are managed with the generated operations — Gaiia.Queries.webhooks/4,
Gaiia.Mutations.create_webhook/4, Gaiia.Mutations.delete_webhook/4 — and
deliveries are auditable through Gaiia.Queries.webhook_execution/4.
CreateWebhookInput.eventNames is [String!]!: the schema does not enumerate
event names, so this library cannot check them and no list is bundled here to
go stale. The catalog (85 events as of 2026-09-07, from account.created to
work_order.updated) is at https://app.gaiia.com/docs/webhooks/overview, and
a live endpoint's current subscriptions read back from webhook.eventNames.
A misspelled name is accepted and simply never fires.
Summary
Functions
Build a complete webhook signature header.
Verify a webhook signature against the exact raw request body.
Types
@type error_reason() :: :malformed_signature | :expired | :invalid_signature
Reason a webhook signature could not be verified.
@type verify_option() :: {:tolerance, non_neg_integer()} | {:now, integer()}
Options for verify/4.
Functions
Build a complete webhook signature header.
This is useful when constructing webhook fixtures for tests.
@spec verify(binary(), String.t(), binary(), [verify_option()]) :: :ok | {:error, error_reason()}
Verify a webhook signature against the exact raw request body.
The timestamp must be within :tolerance seconds of :now. The default
tolerance is 300 seconds and the default time is the current Unix time.