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

# C#

The C# SDK is an idiomatic .NET client emitted from the same `GlottoIR` as every other target. It
uses file-scoped namespaces, `using`-imported `System.*` types, and XML `///` docs generated from
the operation prose in the spec.

## Quickstart

```bash
dotnet add package Petstore
```

```csharp
using Petstore;

var client = new Petstore.Client(token: Environment.GetEnvironmentVariable("PETSTORE_TOKEN"));

// every method takes a CancellationToken
var pet = await client.Pets.CreatePet(newPet, cancellationToken);

// paging is an IAsyncEnumerable
await foreach (var pet in client.Pets.ListPets())
{
    Console.WriteLine(pet.Name);
}
```

## Injectable HttpClient

The `Client` takes an `HttpClient` you supply rather than constructing (and leaking) one per
instance, so it slots into `IHttpClientFactory`, Polly resilience handlers, and test handlers the
standard .NET way — no socket-exhaustion anti-pattern.

## Resource accessors

Operations are PascalCase methods on resource accessors — `client.Pets.Get(id)`,
`client.Pets.Photos.Add(...)` — and every method accepts a `CancellationToken` so calls honor
cooperative cancellation.

## Typed errors

Non-2xx responses throw a typed `ApiError` carrying the parsed error body; discriminated-union
response bodies resolve to the right concrete type. See [Errors](/docs/errors).

## Pagination

List methods return an async stream (`await foreach`) that walks every page, advancing the cursor
for you. See [Pagination](/docs/pagination).

## Retries & backoff

Transient failures (`5xx`, `429`, transport errors) retry with exponential backoff and jitter,
configurable per client. See [Retries & timeouts](/docs/retries), [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 record has no member to put it in, and `System.Text.Json` discards what it does not recognize. 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.

```csharp
var pet = await client.Pets.CreatePet(body);

// A field your API started returning after this SDK was generated.
if (pet.ExtraFields.TryGetValue("species", out var species))
{
    Console.WriteLine(species.GetString());
}

// Re-encoding preserves it — a read-modify-write never silently drops it.
var json = JsonSerializer.Serialize(pet);
```

`ExtraFields` is an `IReadOnlyDictionary<string, JsonElement>`, so nested objects and arrays
survive intact, and retention is recursive.

Your existing construction still compiles: the retention storage is a record *body* member, not
a positional parameter, so the record's constructor signature is unchanged.

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.

## Pages, request controls, and files

Paginated methods also expose [manual pages](/docs/pagination#fetch-one-page),
so you can inspect one response and request its successor explicitly. Request
overrides apply to the initial call and to each requested next page; see
[Retries & timeouts](/docs/retries) for precedence and cancellation.

[Binary downloads](/docs/file-transfers) return an owned byte response with
metadata, a bounded read helper, and incremental consumption. Close the response
when you stop early. Your generated README demonstrates these operations with
your API's names and the language's native calling conventions.
