# `Rapyd.Services.Webhook`
[🔗](https://github.com/iamkanishka/rapyd/blob/v1.0.0/lib/rapyd/services/webhook.ex#L1)

Rapyd Webhooks — verify inbound events and route to handlers.

## Verification

Every inbound webhook from Rapyd is signed with HMAC-SHA256. Always call
`parse_and_verify/2` before trusting any event data:

    def handle_webhook(conn, client) do
      raw_body = conn.assigns[:raw_body]   # must be the raw, unparsed body
      headers = %{
        salt:      get_req_header(conn, "salt")      |> List.first(),
        timestamp: get_req_header(conn, "timestamp") |> List.first(),
        signature: get_req_header(conn, "signature") |> List.first()
      }

      case Rapyd.Services.Webhook.parse_and_verify(client, raw_body, headers) do
        {:ok, event} ->
          dispatch(event)
          send_resp(conn, 200, "ok")

        {:error, %Rapyd.Error{type: :webhook_signature}} ->
          send_resp(conn, 401, "invalid signature")
      end
    end

## Routing

Use `Rapyd.Types.WebhookEvent.dispatch/2` to branch by event type, or
pattern-match on `event.type` directly.

# `create_webhook`

```elixir
@spec create_webhook(Rapyd.Client.t(), map()) ::
  {:ok, map()} | {:error, Rapyd.Error.t()}
```

Register a Rapyd webhook endpoint via the API.

# `delete_webhook`

```elixir
@spec delete_webhook(Rapyd.Client.t(), String.t()) ::
  {:ok, map()} | {:error, Rapyd.Error.t()}
```

Delete a registered webhook endpoint.

# `get_webhook`

```elixir
@spec get_webhook(Rapyd.Client.t(), String.t()) ::
  {:ok, map()} | {:error, Rapyd.Error.t()}
```

Retrieve a registered webhook endpoint.

# `list_webhooks`

```elixir
@spec list_webhooks(Rapyd.Client.t()) :: {:ok, list()} | {:error, Rapyd.Error.t()}
```

List registered webhook endpoints.

# `parse_and_verify`

```elixir
@spec parse_and_verify(Rapyd.Client.t(), iodata(), map()) ::
  {:ok, Rapyd.Types.WebhookEvent.t()} | {:error, Rapyd.Error.t()}
```

Parse and cryptographically verify an inbound Rapyd webhook event.

`raw_body` must be the exact wire bytes sent by Rapyd — do not pre-decode.
`headers` is a map with keys `:salt`, `:timestamp`, and `:signature`.

Returns `{:ok, %Rapyd.Types.WebhookEvent{}}` or
`{:error, %Rapyd.Error{type: :webhook_signature}}`.

# `update_webhook`

```elixir
@spec update_webhook(Rapyd.Client.t(), String.t(), map()) ::
  {:ok, map()} | {:error, Rapyd.Error.t()}
```

Update a registered webhook endpoint.

---

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