Svix

Elixir client for the Svix webhook API.

Installation

Add svix to your list of dependencies in mix.exs:

def deps do
  [
    {:svix, "~> 0.1.0"}
  ]
end

Usage

Client Setup

client = Svix.new("sk_your_token.eu")

The token suffix (.us, .eu, .ca, .au, .in) automatically selects the regional API endpoint. Override with the :server_url option:

client = Svix.new("sk_token", server_url: "https://self-hosted.example.com")

Applications

{:ok, app} = Svix.Application.create(client, %{name: "My App", uid: "my-app-uid"})

{:ok, apps} = Svix.Application.list(client, limit: 10)

{:ok, app} = Svix.Application.get(client, "app_123")

{:ok, _} = Svix.Application.update(client, "app_123", %{name: "Updated"})

{:ok, nil} = Svix.Application.delete(client, "app_123")

{:ok, app} = Svix.Application.get_or_create(client, %{name: "My App", uid: "my-uid"})

Messages

{:ok, msg} = Svix.Message.create(client, "app_123", %{
  event_type: "invoice.paid",
  payload: %{id: "inv_123", amount: 1000}
})

{:ok, messages} = Svix.Message.list(client, "app_123",
  event_types: ["invoice.paid"],
  limit: 20
)

Endpoints

{:ok, ep} = Svix.Endpoint.create(client, "app_123", %{
  url: "https://example.com/webhook",
  filter_types: ["invoice.paid"]
})

{:ok, secret} = Svix.Endpoint.get_secret(client, "app_123", "ep_123")

Event Types

{:ok, _} = Svix.EventType.create(client, %{
  name: "invoice.paid",
  description: "Invoice was paid"
})

Message Attempts

{:ok, attempts} = Svix.MessageAttempt.list_by_endpoint(client, "app_123", "ep_123",
  status: 0,
  limit: 50
)

{:ok, nil} = Svix.MessageAttempt.resend(client, "app_123", "msg_123", "ep_123")

Webhook Verification

Verify incoming webhook signatures:

wh = Svix.Webhook.new("whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw")

case Svix.Webhook.verify(wh, raw_body, headers) do
  {:ok, data} ->
    # Process the verified webhook payload
    handle_event(data)

  {:error, _reason} ->
    # Reject the request
    send_resp(conn, 400, "Invalid signature")
end

Where headers is a map with string keys:

headers = %{
  "svix-id" => get_header(conn, "svix-id"),
  "svix-timestamp" => get_header(conn, "svix-timestamp"),
  "svix-signature" => get_header(conn, "svix-signature")
}

Streaming

{:ok, stream} = Svix.Stream.create(client, %{uid: "my-stream"})
{:ok, sink} = Svix.Stream.Sink.create(client, stream["id"], %{type: "http", url: "https://..."})
{:ok, _} = Svix.Stream.Events.create(client, stream["id"], %{
  event_type: "order.created",
  payload: %{order_id: "ord_123"}
})

Ingest

{:ok, source} = Svix.Ingest.Source.create(client, %{name: "GitHub", type: %{type: "generic"}})
{:ok, ep} = Svix.Ingest.Endpoint.create(client, source["id"], %{
  url: "https://example.com/ingest"
})

Error Handling

All functions return {:ok, result} or {:error, exception} tuples. Bang variants (create!, get!, etc.) raise on error.

case Svix.Application.get(client, "app_123") do
  {:ok, app} ->
    app["name"]

  {:error, %Svix.Error.ApiError{status: 404}} ->
    nil

  {:error, %Svix.Error.ValidationError{detail: errors}} ->
    Logger.error("Validation failed: #{inspect(errors)}")
end

All Resources

Module Description
Svix.Application Manage applications
Svix.Authentication Portal access and token management
Svix.Endpoint Manage endpoints (URLs, headers, secrets, recovery)
Svix.EventType Manage event types
Svix.Message Send and manage messages
Svix.MessageAttempt Query delivery attempts
Svix.Integration Manage integrations
Svix.Webhook Verify webhook signatures
Svix.OperationalWebhookEndpoint Operational webhook endpoints
Svix.BackgroundTask Query background tasks
Svix.Statistics Usage statistics
Svix.Environment Export/import configuration
Svix.Connector Manage connectors
Svix.Stream Manage event streams
Svix.Stream.EventType Stream event types
Svix.Stream.Events Stream events
Svix.Stream.Sink Stream sinks
Svix.Ingest.Source Ingest sources
Svix.Ingest.Endpoint Ingest endpoints
Svix.MessagePoller Poll for messages

License

MIT