ExDaytona.Webhooks (ex_daytona v0.3.0)

Copy Markdown View Source

Daytona webhooks: enabling them for an organization, and verifying the deliveries your endpoint receives.

Setting up

Daytona delivers webhooks through Svix. Initialize the org once, then configure endpoints and event subscriptions in the Svix app portal:

{:ok, _status} = ExDaytona.Webhooks.initialize(client, org_id)
{:ok, %{url: portal_url}} = ExDaytona.Webhooks.portal(client, org_id)
# open portal_url in a browser to add endpoints / choose events

Receiving

Deliveries are signed (Svix / Standard Webhooks scheme). In your endpoint, verify with the endpoint's signing secret (whsec_..., from the portal) using the raw request body — any re-encoding breaks the signature:

# e.g. in a Phoenix controller with a raw-body plug
case ExDaytona.Webhooks.verify(raw_body, conn.req_headers, secret) do
  {:ok, event} -> handle(event["type"] || event, ...)
  {:error, %ExDaytona.Error{}} -> send_resp(conn, 400, "invalid signature")
end

verify/4 checks the HMAC signature and the timestamp tolerance, then returns the decoded JSON payload.

Summary

Functions

Enable webhooks for an organization (idempotent server-side). Returns the ExDaytona.Model.WebhookInitializationStatus.

A short-lived URL (and token) for the organization's Svix app portal, where endpoints and event subscriptions are managed. Returns {:ok, %{url, token}}.

Re-sync the organization's webhook endpoint configuration. Returns :ok.

The organization's webhook initialization status.

Verify a webhook delivery and return its decoded JSON payload.

Functions

initialize(client, org_id)

Enable webhooks for an organization (idempotent server-side). Returns the ExDaytona.Model.WebhookInitializationStatus.

portal(client, org_id)

@spec portal(ExDaytona.Client.t(), String.t()) ::
  {:ok, %{url: String.t(), token: String.t() | nil}}
  | {:error, ExDaytona.Error.t()}

A short-lived URL (and token) for the organization's Svix app portal, where endpoints and event subscriptions are managed. Returns {:ok, %{url, token}}.

refresh_endpoints(client, org_id)

@spec refresh_endpoints(ExDaytona.Client.t(), String.t()) ::
  :ok | {:error, ExDaytona.Error.t()}

Re-sync the organization's webhook endpoint configuration. Returns :ok.

status(client, org_id)

The organization's webhook initialization status.

verify(payload, headers, secret, opts \\ [])

@spec verify(binary(), Enumerable.t(), String.t(), keyword()) ::
  {:ok, map() | list() | binary()} | {:error, ExDaytona.Error.t()}

Verify a webhook delivery and return its decoded JSON payload.

  • payload — the raw request body, exactly as received
  • headers — the request headers (a map or a [{name, value}] list; names are matched case-insensitively). Svix's svix-id, svix-timestamp, svix-signature and the Standard Webhooks webhook-* aliases are both accepted.
  • secret — the endpoint's signing secret (whsec_...)

Options

  • :tolerance_seconds — max allowed clock skew for the timestamp (default 300)
  • :now — unix seconds to validate against (defaults to the current time; useful in tests)