> ## Documentation Index
> Fetch the complete documentation index at: https://docs.expys.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration reference

> Every client option across the TypeScript, Swift, and Kotlin SDKs - defaults, types, and what each one does.

All three SDKs take the same configuration object with the same option names. Only
the idiomatic types and casing differ per language - the meaning and defaults are
identical.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { initialize } from "@expys/sdk";

  const token = process.env.EXPYS_MEMBER_TOKEN;
  if (!token) {
    throw new Error(
      "Set EXPYS_MEMBER_TOKEN (a member token from your backend's /v1/auth/exchange)",
    );
  }

  // A custom fetch wrapper: log each request, then delegate to the platform fetch.
  // Use this seam for tracing, metrics, or a polyfill on Node < 18. The cast keeps
  // it simple here under bun-types (whose `fetch` carries extra members); in a
  // typical web/Node project the arrow satisfies `typeof fetch` without a cast.
  const instrumentedFetch = ((input, init) => {
    const method = init?.method ?? "GET";
    const url =
      typeof input === "string"
        ? input
        : input instanceof URL
          ? input.href
          : input.url;
    console.log(`-> ${method} ${url}`);
    return fetch(input, init);
  }) as typeof fetch;

  const expys = initialize({
    baseUrl: process.env.EXPYS_BASE_URL,
    environment: "sandbox",
    fetch: instrumentedFetch,
    // Retry 429/5xx up to 3 extra times (4 attempts total) with backoff.
    maxRetries: 3,
    // Abort any single attempt that exceeds 8s.
    timeoutMs: 8_000,
    token,
  });

  async function main(): Promise<void> {
    const { data } = await expys.listOffers({ limit: 3 });
    console.log(`fetched ${data.length} offers with the configured client`);
  }
  ```

  ```swift Swift theme={null}
  import ExpysSDK
  import Foundation

  #if canImport(FoundationNetworking)
    import FoundationNetworking
  #endif

  /// A custom HTTP layer that logs each request, then delegates to URLSession. Use
  /// this seam (the `httpClient` injection point) for tracing, metrics, or a custom
  /// transport - the Swift analogue of the TS example's instrumented `fetch`.
  struct InstrumentedHTTP: HTTPRequesting {
    func data(for request: URLRequest) async throws -> (Data, URLResponse) {
      print("-> \(request.httpMethod ?? "GET") \(request.url?.absoluteString ?? "")")
      return try await URLSession.shared.data(for: request)
    }
  }

  @main
  struct ConfigurationExample {
    static func main() async throws {
      let environment = ProcessInfo.processInfo.environment
      guard let token = environment["EXPYS_MEMBER_TOKEN"] else {
        fatalError("Set EXPYS_MEMBER_TOKEN (a member token from your backend's /v1/auth/exchange)")
      }
      let baseURL =
        environment["EXPYS_BASE_URL"].flatMap(URL.init(string:))
        ?? ExpysConfiguration.defaultBaseURL

      let client = ExpysClient(
        configuration: ExpysConfiguration(
          token: token,
          environment: .sandbox,
          baseURL: baseURL,
          // Retry 429/5xx up to 3 extra times (4 attempts total) with backoff.
          maxRetries: 3,
          // Abort any single attempt that exceeds 8s.
          timeout: 8
        ),
        httpClient: InstrumentedHTTP()
      )

      let offers = try await client.listOffers(limit: 3)
      print("fetched \(offers.data.count) offers with the configured client")
    }
  }
  ```

  ```kotlin Kotlin theme={null}
  package com.expys.sdk.examples.configuration

  import com.expys.sdk.ExpysClient
  import com.expys.sdk.ExpysConfiguration
  import com.expys.sdk.ExpysEnvironment
  import kotlinx.coroutines.runBlocking

  fun main() = runBlocking {
    val token = System.getenv("EXPYS_MEMBER_TOKEN")
      ?: error("Set EXPYS_MEMBER_TOKEN (a member token from your backend's /v1/auth/exchange)")

    val client = ExpysClient.create(
      ExpysConfiguration(
        token = token,
        environment = ExpysEnvironment.SANDBOX,
        baseUrl = System.getenv("EXPYS_BASE_URL") ?: ExpysConfiguration.DEFAULT_BASE_URL,
        orgId = System.getenv("EXPYS_ORG_ID"),
        maxRetries = 3,
        timeoutMs = 10_000,
        refreshSkewMs = 30_000,
        userAgentSuffix = "my-app/1.0",
      ),
    )

    println("offers: ${client.listOffers(limit = 1).`data`.size}")
  }
  ```
</CodeGroup>

## Options

| Option                                | Default        | Description                                                                                                                |
| ------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `token` *(required)*                  | -              | The short-lived member token. For [server-mode](/guides/server-mode) clients, this is the Org-API-Key.                     |
| `environment`                         | `live`         | Declarative label for the credential's environment; the other value is `sandbox`. See [Environments](/environments).       |
| `baseUrl`                             | canonical host | Override the API host.                                                                                                     |
| `orgId`                               | -              | Optional. Included in the `User-Agent` for support attribution.                                                            |
| `tokenExpiresAt` / `tokenExpiresAtMs` | -              | Optional. Token expiry; enables proactive refresh. See [Authentication](/authentication).                                  |
| `refreshToken`                        | -              | Optional hook returning a fresh token and expiry. Called proactively within `refreshSkew`, and reactively once on a `401`. |
| `maxRetries`                          | `2`            | Retry attempts on `429`/`5xx`. See [Retries and idempotency](/guides/retries-and-idempotency).                             |
| `timeout` / `timeoutMs`               | none           | Per-request timeout.                                                                                                       |
| `refreshSkew` / `refreshSkewMs`       | `30s`          | Refresh proactively when the token is within this window of expiry.                                                        |
| `userAgentSuffix`                     | -              | Optional. Appended to the `User-Agent`.                                                                                    |

<Note>
  Names are shared across SDKs; the duplicated rows (for example `timeout` /
  `timeoutMs`) show the idiomatic spelling per language. Pass whichever your SDK
  exposes - they configure the same behavior.
</Note>

## User-Agent

Every request carries a `User-Agent` the server uses for attribution and support.
Its format is:

```text theme={null}
expys-sdk-{lang}/{sdkVersion} (spec/{specVersion}; env=<env>[; org=<org>])[ <suffix>]
```

* `{lang}` is `ts`, `swift`, or `kotlin`.
* `{sdkVersion}` and `{specVersion}` are embedded generated constants - see
  [Versioning](/guides/versioning).
* `env` is your configured `environment`; `org` is appended when `orgId` is set.
* The optional trailing `<suffix>` is your `userAgentSuffix`.

For example: `expys-sdk-ts/1.2.0 (spec/1.0.0; env=live; org=org_123) my-app/1.0`.

## Related

<CardGroup cols={3}>
  <Card title="Authentication" icon="key" href="/authentication">
    Tokens, expiry, and the refresh hook.
  </Card>

  <Card title="Environments" icon="layer-group" href="/environments">
    Sandbox vs live, selected by your credential.
  </Card>

  <Card title="Retries" icon="rotate" href="/guides/retries-and-idempotency">
    Backoff and idempotency behavior.
  </Card>
</CardGroup>
