# `Boop`
[🔗](https://github.com/chrisgreg/boop_ex/blob/v1.0.0/lib/boop.ex#L1)

Send events to a self-hosted [Boop](https://github.com/chrisgreg/boop) server.

Boop is a tiny notification inbox: your app POSTs a small JSON event, Boop stores it and
pushes a notification to your phone. This library does one thing — send events reliably
without ever taking your application down.

## Configuration

    config :boop_ex,
      url: System.fetch_env!("BOOP_URL"),
      api_key: System.fetch_env!("BOOP_API_KEY"),
      source: "my_app",              # optional default for every event
      timeout: 10_000,               # ms, default 10_000
      enabled: config_env() == :prod # default true

`url` and `api_key` fall back to the `BOOP_URL` and `BOOP_API_KEY` environment variables
when not configured.

## Usage

    Boop.send("Deploy complete")

    Boop.send(title: "Payment received", body: "£19.99", level: :success, source: "polar",
              data: %{customer_id: "123", amount: 19.99, currency: "GBP"})

    Boop.send(%Boop.Event{title: "Backup failed", level: :error, data: %{host: "db-01"}})

    Boop.send_async(title: "Cron finished", level: :info)

`send/2` returns `{:ok, %{id: "evt_...", created_at: ~U[...]}}` or `{:error, %Boop.Error{}}`.
`send_async/2` returns `:ok` immediately and never raises.

# `result`

```elixir
@type result() ::
  {:ok, %{id: String.t(), created_at: DateTime.t()}}
  | {:ok, :disabled}
  | {:error, Boop.Error.t()}
```

# `enabled?`

```elixir
@spec enabled?() :: boolean()
```

Whether sending is enabled by configuration.

# `healthy?`

```elixir
@spec healthy?(keyword()) :: boolean()
```

Checks whether the configured server is reachable (`GET /health`, no auth).

# `send`

```elixir
@spec send(
  String.t() | keyword() | map() | Boop.Event.t(),
  keyword()
) :: result()
```

Sends an event and waits for the server's answer.

Accepts a title string, a keyword list / map of event fields, or a `%Boop.Event{}`.
`opts` may override `:url`, `:api_key`, `:timeout`, and `:enabled` for this call.

Never raises: bad input, network failures and server errors all come back as
`{:error, %Boop.Error{}}`. When Boop is disabled it returns `{:ok, :disabled}`.

# `send_async`

```elixir
@spec send_async(
  String.t() | keyword() | map() | Boop.Event.t(),
  keyword()
) :: :ok
```

Sends an event on a supervised task and returns `:ok` immediately.

Failures are logged at `:warning` and never surface to the caller. Use this on hot paths
and anywhere a notification must not slow down or break the request.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
