# `BankingCircle.Error`
[🔗](https://github.com/iamkanishka/banking_circle/blob/main/lib/banking_circle/error.ex#L1)

Canonical error representation for every failure mode this client can
surface: transport failures, HTTP 4xx/5xx responses (in either of Banking
Circle's two documented error body shapes), auth failures, and
client-side validation errors raised before a request is ever sent.

Banking Circle returns **two distinct error body shapes** depending on
the endpoint family:

  * Standard operations (e.g. single payments):

        %{"propertyName" => _, "errorCode" => _, "errorDescription" => _}

  * Bulk operations (e.g. bulk payment initiation), one entry per row:

        %{"fieldIndex" => _, "elementIndex" => _, "errorCode" => _, "errorDescription" => _}

`parse/2` normalizes both into `t:detail/0` so callers never need to
branch on which shape came back.

# `detail`

```elixir
@type detail() :: %{
  optional(:property_name) =&gt; String.t() | nil,
  optional(:field_index) =&gt; integer() | nil,
  optional(:element_index) =&gt; integer() | nil,
  code: String.t() | nil,
  description: String.t() | nil
}
```

# `kind`

```elixir
@type kind() ::
  :transport_error
  | :timeout
  | :auth_error
  | :validation_error
  | :rate_limited
  | :concurrency_conflict
  | :not_found
  | :client_error
  | :server_error
  | :unexpected_response
```

# `t`

```elixir
@type t() :: %BankingCircle.Error{
  __exception__: true,
  details: [detail()],
  kind: kind(),
  message: String.t(),
  raw_body: term(),
  request_id: String.t() | nil,
  retry_after_ms: non_neg_integer() | nil,
  status: pos_integer() | nil
}
```

# `parse`

```elixir
@spec parse(pos_integer(), term(), keyword()) :: t()
```

Parses an HTTP response (status + body) into a `t:t/0`, normalizing
either documented error body shape and classifying the failure kind
from the status code.

# `retryable?`

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

True if the error kind is generally safe to retry (429 and 5xx).

# `timeout`

```elixir
@spec timeout(pos_integer()) :: t()
```

# `transport_error`

```elixir
@spec transport_error(term()) :: t()
```

Builds a transport-level error (connection reset, DNS failure, etc.).

---

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