> For the complete documentation index, see [llms.txt](https://docs.ggwp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ggwp.com/ggwp-client-sdk/handling-sanctions.md).

# Handling Sanctions

The client SDK offers handling warnings and sanctions across all the channels - `chat`, `game` and `voice` . These can be doled out to users either [manually from the dashboard](/dashboard-user-guide/player-list.md#sanctioning-a-player) or by [automod](https://docs.ggwp.com/ggwp-client-sdk/pages/KmYPTiLMfie1EjI9Rxe7#id-4.2-ggwp-automod).&#x20;

The Sanctions becomes available after SDK initialization:

```csharp
GGWPSDK.Instance?.InitializeSDK("user_id", "username");

if (GGWPSDK.Instance?.SanctionsAPI != null)
{
    // Sanction callbacks are ready to use
}
```

#### Subscribing for Sanctions

```csharp
using GGWP.Sanctions;
using GGWP.Utils.Async;

// You can create the subscription before authentication
var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

// But real-time updates will only start after code exchange auth
string authCode = GetAuthCodeFromYourBackend();
await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(authCode);

// Now the connection is established and you'll receive real-time updates
await foreach (var state in subscriber.GetStream())
{
    Debug.Log($"Chat status: {state.chat.status}");
    Debug.Log($"Game status: {state.game.status}");
    Debug.Log($"Voice status: {state.voice.status}");
}
```

#### Monitoring Sanctions State

Subscribe to sanctions state changes across all channels. Remember that real-time updates will only begin flowing after you've completed authentication:

```csharp
using GGWP.Sanctions;
using GGWP.Utils.Async;

var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

await foreach (var state in subscriber.GetStream())
{
    // Check chat channel
    Debug.Log($"Chat status: {state.chat.status}");
    
    // Check game channel
    Debug.Log($"Game status: {state.game.status}");
    
    // Check voice channel
    Debug.Log($"Voice status: {state.voice.status}");
}
```

#### Understanding Channel States

Each channel has the following properties:

```csharp
// Get a specific channel state
SanctionState chatState = state.chat;

// Status (Active or Muted)
GGWP.Sanctions.Impl.MuteStatus status = chatState.status;

// Expiry time (if muted)
DateTime? expiryAt = chatState.expiryAt;

// Warning information (if warned)
var warning = chatState.warning;

// Sanction details (if sanctioned)
var sanction = chatState.sanction;
```

#### Initial State

When a user has no sanctions, all channels will be in the Active state. You'll receive this initial state once the connection is established after authentication:

```csharp
await foreach (var state in subscriber.GetStream())
{
    // All channels start as Active
    Assert.AreEqual(state.chat.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    Assert.AreEqual(state.game.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    Assert.AreEqual(state.voice.status, GGWP.Sanctions.Impl.MuteStatus.Active);
    
    // No expiry, warnings, or sanctions
    Assert.Null(state.chat.expiryAt);
    Assert.Null(state.chat.warning);
    Assert.Null(state.chat.sanction);
    
    break;
}
```

#### Handling Applied Sanctions

When a sanction is applied, monitor the state change.

```csharp
using System.Threading;

var subscriber = new Subscriber<ChannelSanctionsState>(
    GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
);

using var cts = new CancellationTokenSource();

await foreach (var state in subscriber.GetStream(cts.Token))
{
    if (state.game.status == GGWP.Sanctions.Impl.MuteStatus.Muted)
    {
        Debug.Log("User is muted in game channel");
        
        // Check expiry time to see when the mute will be lifted
        if (state.game.expiryAt != null)
        {
            Debug.Log($"Mute expires at: {state.game.expiryAt}");
        }
        
        // Get sanction details to understand the status transition
        if (state.game.sanction != null)
        {
            var sanction = state.game.sanction.Value;
            Debug.Log($"Previous status: {sanction.previousStatus}");
            Debug.Log($"Current status: {sanction.currentStatus}");
        }
        
        break;
    }
}
```

#### Recommended Usage Pattern

The recommended pattern is to authenticate first, then subscribe to sanctions. This ensures that the connection is established immediately and you don't miss any initial state information:

```csharp
// Step 1: Authenticate the user
string authCode = GetAuthCodeFromYourBackend();
var authResult = await GGWPSDK.Instance?.AuthManager.ExchangeAuthCode(authCode);

if (authResult == GGWP.Impl.Result.Success)
{
    // Step 2: Now subscribe to sanctions
    var subscriber = new Subscriber<ChannelSanctionsState>(
        GGWPSDK.Instance?.SanctionsAPI.SubscribeSanctionsState()
    );

    // Step 3: Process sanctions state updates in real-time
    await foreach (var state in subscriber.GetStream())
    {
        // Handle sanctions state changes as they occur
        Debug.Log($"Chat: {state.chat.status}");
    }
}
```

#### Using Cancellation Tokens

Control the subscription lifetime using cancellation tokens. This is useful when you want to stop monitoring sanctions, such as when a user logs out or closes a particular screen:

```csharp
using System.Threading;

var cts = new CancellationTokenSource();

try
{
    await foreach (var state in subscriber.GetStream(cts.Token))
    {
        // Process state
        
        if (someCondition)
        {
            cts.Cancel(); // Stop listening
            break;
        }
    }
}
catch (OperationCanceledException)
{
    Debug.Log("Sanctions monitoring cancelled");
}
```
