# `Rapyd.Signing`
[🔗](https://github.com/iamkanishka/rapyd/blob/v1.0.0/lib/rapyd/signing.ex#L1)

Generates and verifies Rapyd HMAC-SHA256 request signatures.

## Request Signing

Every API request must carry three headers built from the signature:

* `access_key` — your Rapyd access key
* `salt` — a random 8-byte hex string (16 chars), unique per request
* `timestamp` — current Unix epoch in seconds
* `signature` — `BASE64(HMAC-SHA256(lower(method) + path + salt + timestamp + access_key + secret_key + body))`

## Webhook Verification

Incoming Rapyd webhooks are signed with the same algorithm but without a
method prefix:

    BASE64(HMAC-SHA256(http_body + salt + timestamp + access_key + secret_key))

Call `verify_webhook/4` to authenticate an inbound event.

# `sign_request`

```elixir
@spec sign_request(
  method :: atom() | String.t(),
  path :: String.t(),
  body :: iodata(),
  access_key :: String.t(),
  secret_key :: String.t()
) :: {salt :: String.t(), timestamp :: String.t(), signature :: String.t()}
```

Compute the three signing headers needed for an authenticated API request.

Returns `{access_key, salt, timestamp_string, signature_base64}`.

## Parameters

* `method` — HTTP method atom or string, e.g. `:get` or `"POST"`
* `path` — request path including query string, e.g. `"/v1/payments"`
* `body` — request body as an iodata-compatible value; pass `""` for GET
* `access_key` — Rapyd access key
* `secret_key` — Rapyd secret key

# `verify_webhook`

```elixir
@spec verify_webhook(
  raw_body :: iodata(),
  salt :: String.t(),
  timestamp :: String.t(),
  received_sig :: String.t(),
  access_key :: String.t(),
  secret_key :: String.t()
) :: :ok | {:error, Rapyd.Error.t()}
```

Verify the HMAC-SHA256 signature on an inbound Rapyd webhook.

Uses constant-time comparison to prevent timing attacks.

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

---

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