# Svix
Elixir client for the [Svix](https://www.svix.com) webhook API.
## Installation
Add `svix` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:svix, "~> 0.1.0"}
]
end
```
## Usage
### Client Setup
```elixir
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:
```elixir
client = Svix.new("sk_token", server_url: "https://self-hosted.example.com")
```
### Applications
```elixir
{: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
```elixir
{: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
```elixir
{: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
```elixir
{:ok, _} = Svix.EventType.create(client, %{
name: "invoice.paid",
description: "Invoice was paid"
})
```
### Message Attempts
```elixir
{: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:
```elixir
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:
```elixir
headers = %{
"svix-id" => get_header(conn, "svix-id"),
"svix-timestamp" => get_header(conn, "svix-timestamp"),
"svix-signature" => get_header(conn, "svix-signature")
}
```
### Streaming
```elixir
{: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
```elixir
{: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.
```elixir
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