# Configuration

> Register STX.Sdk services and pick the right endpoints per environment.

Source: https://docs.stxapp.io/sdks/csharp/configuration/

One call wires up every service, channel, and background worker the SDK provides.

## Register services

Name the environment and supply credentials. You do not need to know any URLs:

```csharp
using STX.Sdk;
using STX.Sdk.Auth;
using STX.Sdk.Settings;
using Microsoft.Extensions.DependencyInjection;

services.ConfigureSTXServices(
    STXEnvironment.OntarioDemo,
    STXApiKeyCredentials.FromPemFile(keyId, "~/.stx/ontario.pem"));
```

The same overload exists without credentials, for email and password:

```csharp
services.ConfigureSTXServices(STXEnvironment.OntarioDemo);
```

`ConfigureSTXServices` adds:

- GraphQL HTTP client + typed services (`STXLoginService`, `STXMarketService`, `STXOrderService`, …)
- Phoenix channel classes + wrappers (`STXPortfolioChannel`, `STXActiveOrdersChannel`, …)
- User storage (`STXUserStorage`) as a singleton
- Two hosted background services (`STXSessionBackgroundService`, `STXGeoLocationBackgroundService`) that the hosting framework starts automatically

## Named environments

| | Jurisdiction | Real money |
|---|---|---|
| `STXEnvironment.OntarioDemo` | Ontario | No |
| `STXEnvironment.OntarioProduction` | Ontario | **Yes** |
| `STXEnvironment.USDemo` | United States | No |

Each one carries both the GraphQL endpoint and the WebSocket endpoint, so there is nothing to assemble by hand and no `{0}` placeholder to remember. Demo environments are shared by every integrator, so their order books carry real activity.

:::caution
`OntarioProduction` is live money. Point at it only once your integration is exercised end to end against a demo environment.
:::

### Anything else

For an endpoint not listed above, supply both URLs yourself:

```csharp
services.ConfigureSTXServices(
    STXEnvironment.Custom(
        graphQLUri:  "https://your-host/api/graphql",
        channelsUri: "wss://your-host/socket/websocket?token={0}&vsn=2.0.0"),
    credentials);
```

:::note
`{0}` in a custom `channelsUri` is a format placeholder. Under email and password it is filled with the session token; under API-key authentication there is no token, so it is left empty and the handshake is signed instead. An empty `token=` in the URL is expected in that case, not a failure. The named environments already include the placeholder.
:::

Select the environment from configuration rather than code, so a deploy can swap it without recompiling:

```csharp
var environment = builder.Configuration["STX:Environment"] switch
{
    "ontario-production" => STXEnvironment.OntarioProduction,
    "ontario-demo"       => STXEnvironment.OntarioDemo,
    "us-demo"            => STXEnvironment.USDemo,
    _ => throw new InvalidOperationException("Set STX:Environment")
};

services.ConfigureSTXServices(environment, credentials);
```

### Supplying URLs directly

The original overload still works and is unchanged:

```csharp
services.ConfigureSTXServices(
    _ => builder.Configuration["STX:GraphQLUri"]!,
    _ => builder.Configuration["STX:ChannelsUri"]!);
```

`appsettings.json`:

```json
{
  "STX": {
    "GraphQLUri":  "https://demo.stxapp.ca/api/graphql",
    "ChannelsUri": "wss://demo.stxapp.ca/socket/websocket?token={0}&vsn=2.0.0"
  }
}
```

Override per environment with `appsettings.Production.json` or env vars (`STX__GraphQLUri=…`).

## Dynamic endpoint resolution

If the endpoints depend on something inside DI (a tenant selector, feature flag, etc.), the overload that takes `Func<IServiceProvider, string>` gives you a callback:

```csharp
services.ConfigureSTXServices(
    getGraphQLUri:  sp => sp.GetRequiredService<IMyEnvResolver>().GraphQLUri,
    getChannelsUri: sp => sp.GetRequiredService<IMyEnvResolver>().ChannelsUri);
```

## Resolving services

Register once, resolve anywhere:

```csharp
public class OrderPlacer
{
    private readonly STXOrderService _orders;
    private readonly STXMarketService _markets;

    public OrderPlacer(STXOrderService orders, STXMarketService markets)
    {
        _orders = orders;
        _markets = markets;
    }

    public async Task PlaceAsync() { /* ... */ }
}
```

Services are registered as `Transient`, so they are safe to resolve per operation. Channel classes are `Singleton` so state (the active websocket, subscribed topics) is shared across the app.

## Logging

The SDK uses `Microsoft.Extensions.Logging`. Hook up the provider you prefer:

```csharp
services.AddLogging(builder =>
    builder
        .SetMinimumLevel(LogLevel.Information)
        .AddConsole());
```

The SDK logs at `Debug` for every GraphQL request/response body, `Information` for connection lifecycle, and `Warning`/`Error` for transient + fatal issues.

## GeoComply / GeoLocation

`ConfigureSTXServices` registers `STX.GeoComply` and `STX.GeoLocation` internally. For trading bots running server-side, the default behavior is usually what you want: the geolocation token is fetched lazily and cached. If you're embedding the SDK in a client app (desktop, mobile), integrate with GeoComply's SDK per their docs.
