> For the complete documentation index, see [llms.txt](/llms.txt)

# Elixir

The Elixir SDK is an idiomatic Hex package emitted from the same `GlottoIR` as every other target.
It is functional and module-first: the public package facade builds the client with
`Petstore.new/2`, and each resource gets its own module whose functions take that struct as their
first argument — `Petstore.Pets.list_pets(client)`. It is built on `Req`.

## Quickstart

```elixir
def deps do
  [
    {:petstore, "~> 1.0"}
  ]
end
```

```elixir
client =
  Petstore.new("https://api.petstore.example",
    token: System.get_env("PETSTORE_TOKEN")
  )

# calls return {:ok, _} / {:error, %Petstore.ApiError{}} tuples
{:ok, pet} = Petstore.Pets.create_pet(client, %{name: "Rex"})

# paginated functions return a lazy Stream
Petstore.Pets.list_pets(client)
|> Enum.each(&IO.puts(&1.name))
```

## Typed models

Each `GlottoIR` model becomes a struct module with `from_map`/`to_map`; functions decode and return
the typed response and accept a typed request body. Discriminated unions resolve to the right
variant.

## Typed errors

Functions return a `%Glotto.ApiError{}` struct carrying the parsed error body, with
`Glotto.ApiError.kind/1` mapping the status to a documented atom so callers `case` on `:not_found`
rather than matching status codes. See [Errors](/docs/errors).

## Pagination

Paginated list functions return a lazy `Stream` that walks every page as you enumerate, advancing
the cursor for you. Manual-page companions expose typed items, the full response, and explicit next-page navigation. See [Pagination](/docs/pagination).

## Retries & backoff

Transient failures (`5xx`, `429`, transport errors) retry with exponential backoff and jitter,
configurable per client and per call. A trailing keyword list accepts request headers, timeout, retry count, idempotency and applicable extra query/body values; explicit values override configured method/resource defaults. Terminating the request-owning Task cancels its request and retry wait. See [Retries & timeouts](/docs/retries).

## SSE streaming

Server-sent-event endpoints return a `Stream` of typed events decoded from the `text/event-stream`
framing. See [Streaming](/docs/streaming) and [Authentication](/docs/authentication).

## Unknown response fields

Your API can add a response field without it being a breaking change — but a generated struct has only the keys it declares, and its `from_map/1` factory reads only those. The generated
models keep it instead: a field the SDK wasn't generated from is retained on decode, readable
through an accessor, and written back out when the model is re-serialized.

```elixir
{:ok, pet} = Glotto.Pets.create_pet(client, body)

# A field your API started returning after this SDK was generated.
species = Glotto.Pet.extra_fields(pet)["species"]

# Re-encoding preserves it — a read-modify-write never silently drops it.
json = pet |> Glotto.Pet.to_map() |> Jason.encode!()
```

`extra_fields/1` returns a plain map, so nested objects and lists survive intact, and retention is
recursive.

The struct key defaults to an empty map, so `%Glotto.Pet{id: "p1"}` still builds.

The retained fields are read-only by design. To *send* a field your spec doesn't model yet, use the
per-call extra-body escape hatch rather than writing to the retained bag.

## File uploads

`multipart/form-data` operations build the multipart body from their fields for you; an
`application/octet-stream` operation takes a positional `body` (a binary) sent raw with the right
`content-type`.

## Binary downloads

Declared binary responses return an owned `Glotto.BinaryDownload` with status, headers, media type, content length, filename and request ID. Consume its `chunks/1` stream, call `read_all/2` with a required `max_bytes` bound, or `pipe/2` to a binary IO device or callback. Limits count delivered bytes, including decoded gzip bytes. Close an abandoned response explicitly; terminating its original request Task also closes it. The request timeout covers the first byte or EOF, and no retry occurs after delivery. See [File transfers](/docs/file-transfers).
