# `Tipalti.HTTP`
[🔗](https://github.com/iamkanishka/tipalti/blob/main/lib/tipalti/http.ex#L1)

Minimal HTTP transport used by every Tipalti API family.

Deliberately built on the OTP-bundled `:httpc` and `:ssl` applications
instead of a third-party HTTP client, so this package doesn't drag in a
large dependency tree. It still provides the things a production client
needs:

  * TLS certificate verification against the OS/OTP trust store
    (`:public_key.cacerts_get/0`, OTP 25+), with hostname verification.
  * Exponential backoff with full jitter, retrying only safe/idempotent
    requests on transient failures (429, 5xx, connection errors).
  * `:telemetry` spans around every request.
  * Uniform error translation into the `Tipalti.Error` hierarchy.

This module is used internally by `Tipalti.Client`, `Tipalti.SOAP.Client`,
and the Procurement modules — you generally won't call it directly.

# `method`

```elixir
@type method() :: :get | :post | :put | :delete | :patch
```

# `response`

```elixir
@type response() :: %{
  status: non_neg_integer(),
  headers: [{String.t(), String.t()}],
  body: binary()
}
```

# `request`

```elixir
@spec request(method(), String.t(), [{String.t(), String.t()}], iodata(), keyword()) ::
  {:ok, response()} | {:error, Exception.t()}
```

Issues an HTTP request with retry/backoff and telemetry, returning
`{:ok, response}` or `{:error, exception}` where `exception` is a
`Tipalti.NetworkError` or `Tipalti.RateLimitError`. Non-transport error
status codes (4xx/5xx other than 429) are returned as-is in `{:ok,
response}` — translating those into `Tipalti.APIError`/`Tipalti.ValidationError`
is the caller's job, since the right error shape differs between the
REST/SOAP/Procurement APIs.

---

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