# Client Create and configure the client, and read the metadata of every API response. A `SynthientClient` is safe for concurrent use and pools connections. Create one and reuse it for the life of the application. ```csharp public sealed class SynthientClient : IDisposable ``` ## Constructors The parameterless constructor reads the API key from the `SYNTHIENT_API_KEY` environment variable, and so do options whose `ApiKey` is `null`. ```csharp public SynthientClient() public SynthientClient(string apiKey) public SynthientClient(SynthientClientOptions options) ``` ```csharp using var client = new SynthientClient(new SynthientClientOptions { MaxRetries = 4, UserAgent = "my-app/1.0", }); ``` - **Input:** Surrounding whitespace is trimmed from the key. A missing or empty key, a key with characters other than printable ASCII, or an invalid option throws an `ArgumentException` (an `ArgumentOutOfRangeException` for `MaxRetries` and `Timeout`). - **Options:** Options are copied, so changing them later has no effect on the client. - **Network:** No constructor performs network I/O. ## SynthientClientOptions - `ApiKey` `string?` — The API key. When `null`, the client reads the `SYNTHIENT_API_KEY` environment variable. Surrounding whitespace is removed. - `BaseAddress` `Uri` — The API base address, including the version path. The default is `SynthientClient.DefaultBaseAddress`. It must be an absolute `http` or `https` URI with no user info, query, or fragment. - `MaxRetries` `int` — How many times a failed request is retried. The default is `2`, and `0` disables retries. It must not be negative. See [Retries and timeouts](https://docs.synthient.com/sdks/csharp/errors#retries-and-timeouts). - `Timeout` `TimeSpan` — How long the client waits on the network before throwing `ApiTimeoutException`. It bounds each wait for response headers and each read of a response body, stream, or download, not the length of a whole call, so long-lived streams and large downloads are not cut off. The default is 60 seconds, and `Timeout.InfiniteTimeSpan` disables it. Any other value must be positive and at most `int.MaxValue` milliseconds. - `UserAgent` `string?` — A product token, such as `"my-app/1.2"`, appended to the `User-Agent` header, which starts with `synthient-dotnet/` followed by the SDK version. It must contain only printable ASCII characters. - `ResponseHook` `Action?` — Called with the metadata of every response from the Synthient API. See [Response metadata](#response-metadata). - `Handler` `HttpMessageHandler?` — The HTTP handler that sends requests, for custom proxies, certificates, or tests. The client never disposes it. It must not follow redirects, because a followed export redirect would send the API key to the storage host, so a `SocketsHttpHandler` or `HttpClientHandler` with `AllowAutoRedirect` set is rejected, even inside a `DelegatingHandler`. Both set it by default. The handler should not retry requests either: the client retries on its own, and a handler that resends a billed lookup can be charged twice. Set `SocketsHttpHandler.MaxResponseDrainSize` to `0` so that leaving a stream or download early closes its connection, as the client's own handler does. ## Static members - `SynthientClient.Version` `const string` — The SDK version, such as `"1.0.0"`. It is sent in the `User-Agent` header. - `SynthientClient.DefaultBaseAddress` `static Uri` — `https://api.synthient.com/api/v4`, the base address of the Synthient HTTP API. ## Dispose Releases the client's connections. ```csharp public void Dispose() ``` - **Errors:** Calls made afterwards throw `ObjectDisposedException`, and calls still waiting for a response or for a retry are cancelled with an `ObjectDisposedException`. ## Response metadata `SynthientClientOptions.ResponseHook` is called synchronously with the metadata of every response from the Synthient API. ```csharp using var client = new SynthientClient(new SynthientClientOptions { ResponseHook = metadata => { if (metadata.RateLimit is not null) { Console.WriteLine($"{metadata.StatusCode} {metadata.RequestId} {metadata.RateLimit.Remaining} {metadata.RateLimit.Reset}"); } }, }); ``` - **Coverage:** The hook is called for error responses, each retry, each page, stream connections, export redirects, and responses that fail to decode. It is not called for export downloads from storage. - **Errors:** If the hook throws, the call fails with its exception. - **Concurrency:** The hook must be safe to call concurrently. The metadata and its headers are read-only copies, so the hook can keep them. ### ResponseMetadata The constructor is public for tests. It copies `headers` and matches their names case-insensitively. ```csharp public sealed class ResponseMetadata public ResponseMetadata(int statusCode, IReadOnlyDictionary> headers) ``` - `StatusCode` `int` — The HTTP status code. - `RequestId` `string?` — The `X-Request-Id` header, or `null` if it is absent or empty. - `RateLimit` `RateLimit?` — The rate limit state, or `null` if the response does not report it, as on `CheckHealthAsync`. - `Headers` `IReadOnlyDictionary>` — The response and content headers, with case-insensitive names. Headers can contain sensitive data, such as presigned download URLs. ### RateLimit The rate limit state of the bucket a request was charged to, from the `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers. `ResponseMetadata.RateLimit` is `null` unless all three are present and valid. Buckets are shared by every key of a team. See [Rate Limits](https://docs.synthient.com/rate-limits). ```csharp public sealed record RateLimit(int Limit, int Remaining, TimeSpan Reset); ``` - `Limit` `int` — The bucket's burst size. - `Remaining` `int` — The number of requests left in the bucket. - `Reset` `TimeSpan` — How long until the bucket is full again.