README.md

# 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