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

# Status and lifecycle

> How to integrate the Almedia SDK — synced from the source repository.

After `Initialize`, the SDK transitions through a small state machine. `Almedia.Status` holds the current status, and `OnStatusChanged` fires on every change:

```
NotInitialized
      │  (Initialize called, native auth in progress)
      ▼
  ┌── Eligible ─── account-linking flow available, player not linked
  │
  ├── Linked ───── player already linked at init, or just finished linking
  │
  ├── NotAvailable ─ region/eligibility check failed for this user
  │
  ├── Blocked ──── user blocked by backend (e.g. abuse, fraud)
  │
  └── Disabled ── integration killswitch - backend disabled this app
```

Each status is a nested class of [`AlmediaStatus`](https://docs.almedia.dev/technical/api-reference/almedia/models#almediastatus) and carries its own data. `Linked` carries `CanShowRewardHub` and `CanShowOffer`. `NotAvailable` carries `Reason` and `RawReason`. Test a status with a type pattern:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
using AlmediaSDK;

private void OnEnable()
{
    Almedia.OnStatusChanged += Refresh;
    Refresh(Almedia.Status);  // late-mount recovery
}

private void OnDisable() => Almedia.OnStatusChanged -= Refresh;

private void Refresh(AlmediaStatus status)
{
    switch (status)
    {
        case AlmediaStatus.Eligible:
            linkButton.SetActive(true);
            rewardsButton.SetActive(false);
            offerButton.SetActive(false);
            break;
        case AlmediaStatus.Linked linked:
            linkButton.SetActive(false);
            rewardsButton.SetActive(linked.CanShowRewardHub);
            offerButton.SetActive(linked.CanShowOffer);
            break;
        default:
            linkButton.SetActive(false);
            rewardsButton.SetActive(false);
            offerButton.SetActive(false);
            break;
    }
}
```

Keep the `default` branch. A later version can add statuses.

`OnStatusChanged` fires on the first status after `Initialize` and on every change after it, including a flag change while the player stays linked and a change of the `NotAvailable` reason. `Almedia.Status` already holds the new value when it fires. Use it both for one-shot setup that should happen once the SDK has resolved (skip `NotInitialized` and use a guard flag) and for live UI that mirrors the current state - the built-in `LinkButton` shows or hides itself the same way.

When `Initialize` runs again with a different configuration, the status returns to `NotInitialized`, `OnStatusChanged` reports it, and the status then resolves again.

For components that mount after `Initialize` has already completed, read `Almedia.Status` directly to recover the latest status, then subscribe to `OnStatusChanged` for further changes - see the "late-joining components" rule under the bootstrap section above.

## Why the service is not available

`NotAvailable` covers several backend decisions. Its `Reason` tells you which one:

```csharp theme={"theme":{"light":"github-light","dark":"night-owl"}}
Almedia.OnStatusChanged += status =>
{
    if (status is AlmediaStatus.NotAvailable notAvailable)
        Analytics.Track("link_unavailable", notAvailable.Reason.ToString());
};
```

Two values are named. `Holdout`: for a small share of eligible players the Link experience is deliberately not offered, which enables continuous, statistically robust measurement of the effect of offering Link. `Disabled`: your game declared linking in its [disabled features](https://docs.almedia.dev/technical/integration-guide/disabled-features.md). Both are informational - use them in your statistics; there is nothing to act on. Anything this SDK version does not recognize, reads as `Unknown` in an existing build, so handle `Unknown` as a normal case rather than an error. `RawReason` keeps the reason exactly as the server sent it. Compare the reason with `==`, for example `notAvailable.Reason == AlmediaNotAvailableReason.Holdout`. See [`AlmediaNotAvailableReason`](https://docs.almedia.dev/technical/api-reference/almedia/models#almedianotavailablereason).

**This does not change what your UI does.** The entry point hides on `NotAvailable` whatever the reason. The reason is for analytics, support, and messaging.

## What can actually be shown

The status tells you whether the service is available to the player. It does **not** tell you whether a given screen will open. A `Linked` player can have no reward hub, and an offer can appear or disappear mid-session. `CanShowRewardHub` and `CanShowOffer` on the `Linked` status answer that question - check them before calling `ShowRewardHub()` or `ShowOffer()`. A flag change arrives as a new `Linked` status through `OnStatusChanged`, including while the player stays linked, so the `Refresh` handler above keeps every button current.

If you use the bundled `LinkButton`, this is already handled.

***


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.