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

Structured error returned by every failed SDK operation.

## Fields

* `:type` — atom classifying the failure; pattern-match on this.
* `:message` — human-readable summary.
* `:error_code` — Rapyd API error code string (e.g. `"ERROR_PAYMENT_NOT_FOUND"`).
* `:status_code` — HTTP status code integer, or `nil` for network-level errors.
* `:operation_id` — Rapyd `operation_id` from the response envelope, when present.
* `:retryable?` — `true` when the call can be safely retried.

## Error Types

| Type | Meaning |
|---|---|
| `:api_error` | Generic Rapyd API error |
| `:payment_not_found` | Payment ID does not exist |
| `:payment_failed` | Payment processing failure |
| `:payment_canceled` | Payment was canceled |
| `:insufficient_funds` | Insufficient funds in wallet or card |
| `:card_declined` | Card was declined by the network |
| `:expired_card` | Card has expired |
| `:invalid_card` | Card number or CVV is invalid |
| `:do_not_honor` | Generic do-not-honor from card network |
| `:fraud` | Transaction flagged as fraudulent |
| `:rate_limit` | Too many requests; back off and retry |
| `:unauthorized` | Invalid access/secret key pair |
| `:forbidden` | Operation not permitted for this account |
| `:not_found` | Resource does not exist |
| `:validation` | Request body failed client-side validation |
| `:webhook_signature` | Webhook HMAC signature mismatch |
| `:network` | TCP/TLS transport failure |
| `:timeout` | Request timed out |
| `:unknown` | Unclassified server error |

# `error_type`

```elixir
@type error_type() ::
  :api_error
  | :payment_not_found
  | :payment_failed
  | :payment_canceled
  | :insufficient_funds
  | :card_declined
  | :expired_card
  | :invalid_card
  | :do_not_honor
  | :fraud
  | :rate_limit
  | :unauthorized
  | :forbidden
  | :not_found
  | :validation
  | :webhook_signature
  | :network
  | :timeout
  | :unknown
```

# `t`

```elixir
@type t() :: %Rapyd.Error{
  __exception__: true,
  error_code: String.t() | nil,
  message: String.t(),
  operation_id: String.t() | nil,
  retryable?: boolean(),
  status_code: non_neg_integer() | nil,
  type: error_type()
}
```

# `from_api_response`

```elixir
@spec from_api_response(map(), non_neg_integer()) :: t()
```

Build an error from a decoded Rapyd API error envelope.

The envelope looks like:
    %{"status" => %{"status" => "ERROR", "error_code" => "...", "message" => "...",
                     "operation_id" => "..."}, ...}

# `from_exception`

```elixir
@spec from_exception(Exception.t()) :: t()
```

Build a transport-level (network or timeout) error.

# `retryable?`

```elixir
@spec retryable?(t()) :: boolean()
```

Returns `true` when this error type is safe to retry.

# `validation`

```elixir
@spec validation(String.t()) :: t()
```

Build a client-side validation error.

# `webhook_signature`

```elixir
@spec webhook_signature(String.t()) :: t()
```

Build a webhook signature error.

---

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