Functions for managing Humaans webhook subscriptions and verifying incoming webhook deliveries.
Managing webhook subscriptions
Standard CRUD on the /api/webhooks endpoint via the generated list/2,
create/2, retrieve/2, update/3, and delete/2 functions.
Verifying a delivery
Humaans signs webhook payloads with HMAC-SHA256 using your endpoint's signing secret. Verifying the signature on every delivery is required — treat any unverified payload as untrusted input.
defp verify(conn, secret) do
{:ok, raw_body, conn} = Plug.Conn.read_body(conn)
signature = Plug.Conn.get_req_header(conn, "x-humaans-signature") |> List.first()
case Humaans.Webhooks.verify_signature(raw_body, signature, secret) do
:ok -> {:ok, conn, raw_body}
{:error, _reason} = err -> err
end
endAlways pass the raw request body to verify_signature/3. Re-serialised
JSON will not match because byte-level differences (key ordering,
whitespace) change the HMAC.
Summary
Functions
Creates a new webhook.
Deletes a specific webhook by ID.
Lists all webhooks.
Retrieves a specific webhook by ID.
Updates a specific webhook by ID.
Verifies a webhook signature against the raw request body.
Types
Functions
@spec create(client :: map(), params :: map() | keyword()) :: {:ok, Humaans.Resources.Webhook.t()} | {:error, Humaans.Error.t()}
Creates a new webhook.
Parameters
client- Client created withHumaans.new/1params- Map of attributes for the new webhook
Examples
client = Humaans.new(access_token: "your_access_token")
params = %{url: "https://example.com/hooks", events: ["person.created"]}
{:ok, webhook} = Humaans.Webhooks.create(client, params)
@spec delete(client :: map(), id :: String.t()) :: {:ok, %{id: String.t(), deleted: boolean()}} | {:error, Humaans.Error.t()}
Deletes a specific webhook by ID.
Parameters
client- Client created withHumaans.new/1id- String ID of the webhook to delete
Examples
client = Humaans.new(access_token: "your_access_token")
{:ok, %{id: "webhook_id", deleted: true}} = Humaans.Webhooks.delete(client, "webhook_id")
@spec list(client :: map(), params :: map() | keyword() | [{String.t(), term()}]) :: {:ok, [Humaans.Resources.Webhook.t()]} | {:error, Humaans.Error.t()}
Lists all webhooks.
Returns a list of webhooks matching the optional filter params.
Parameters
client- Client created withHumaans.new/1params- Optional map of filter parameters (default:%{})
Examples
client = Humaans.new(access_token: "your_access_token")
{:ok, webhooks} = Humaans.Webhooks.list(client)
{:ok, webhooks} = Humaans.Webhooks.list(client, %{})
@spec retrieve(client :: map(), id :: String.t()) :: {:ok, Humaans.Resources.Webhook.t()} | {:error, Humaans.Error.t()}
Retrieves a specific webhook by ID.
Parameters
client- Client created withHumaans.new/1id- String ID of the webhook to retrieve
Examples
client = Humaans.new(access_token: "your_access_token")
{:ok, webhook} = Humaans.Webhooks.retrieve(client, "webhook_id")
@spec update(client :: map(), id :: String.t(), params :: map() | keyword()) :: {:ok, Humaans.Resources.Webhook.t()} | {:error, Humaans.Error.t()}
Updates a specific webhook by ID.
Parameters
client- Client created withHumaans.new/1id- String ID of the webhook to updateparams- Map of attributes to update
Examples
client = Humaans.new(access_token: "your_access_token")
params = %{events: ["person.created", "person.updated"]}
{:ok, webhook} = Humaans.Webhooks.update(client, "webhook_id", params)
@spec verify_signature( payload :: binary(), signature :: String.t() | nil, secret :: String.t() | nil ) :: :ok | {:error, :invalid_signature | :missing_signature | :missing_secret}
Verifies a webhook signature against the raw request body.
Computes HMAC-SHA256(secret, payload) and compares it to signature in
constant time.
Accepts the signature as either a raw hex string ("abc123...") or with a
sha256= prefix ("sha256=abc123..."), so it works regardless of the
exact convention used by the sender.
Returns
:ok- Signature matches.{:error, :invalid_signature}- Signature does not match the payload.{:error, :missing_signature}-signatureisnilor empty.{:error, :missing_secret}-secretisnilor empty.
Examples
iex> body = ~s({"event":"person.updated"})
iex> secret = "test-secret"
iex> sig =
...> :crypto.mac(:hmac, :sha256, secret, body)
...> |> Base.encode16(case: :lower)
iex> Humaans.Webhooks.verify_signature(body, sig, secret)
:ok
iex> Humaans.Webhooks.verify_signature("body", "deadbeef", "secret")
{:error, :invalid_signature}
iex> Humaans.Webhooks.verify_signature("body", nil, "secret")
{:error, :missing_signature}