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

# Best Practices

> How to balance earn rates with withdrawal limits, handle SDK failures gracefully, and keep the player experience smooth.

## Balancing earn rate with withdrawal limit

A player's rewards balance and their withdrawal limit are two separate values. It's possible to credit a player more than they can currently withdraw — and if that gap gets too large, it creates a frustrating experience.

Keep the earn rate roughly aligned with the player's withdrawal capacity. Occasionally letting players earn ahead of their limit is fine and can drive return visits. Consistently crediting far more than they can access is not — a player who earns 1,000 units but can only withdraw 100 will disengage.

<Steps>
  <Step title="Limit reward frequency">
    Avoid giving out rewards too often or at passive moments. Rewards tied to skill or effort feel earned; passive rewards feel arbitrary and train players to expect them without engagement.
  </Step>

  <Step title="Scale difficulty over time">
    Make early rewards easy to earn, then gradually slow down progression as the session continues. This mirrors good game economy design and keeps withdrawal limits in sync with balance growth.
  </Step>

  <Step title="Check balance before sending">
    Use `ZBDController.Instance.GetBalance` to retrieve the player's current balance and daily withdrawal cap before issuing a reward. Adjust the reward amount based on how much headroom they have.
  </Step>
</Steps>

### Example

In a game with a daily task chest mechanic, rewards are balanced dynamically:

* If the player's balance is already above their daily limit, the chest reward is reduced or deferred until tomorrow.
* Early in a session, rewards are more generous. Later in the session, as the balance builds, rewards taper off.

This pattern keeps the balance/limit relationship healthy and avoids the frustration of a player who can see they've earned rewards but can't withdraw them.

## Handling SDK initialization failures

Call `ZBDController.Instance.Init` as early as possible — ideally on game launch. Keep the instance alive with a singleton or `DontDestroyOnLoad` so it persists across scenes.

`Init` reports its result on the `completion` object. Handle each outcome distinctly — never fail silently:

* **Success** (`completion.success`) — the SDK is ready; proceed normally.
* **Maintenance** (`completion.maintenance`) — ZBD is temporarily down for maintenance. This is **not** an error and has no retry path, so don't show the modal. For players who haven't started earning, hide all Earn UI; for players who have already earned, show a "rewards temporarily unavailable" message. See [Maintenance Mode](/earn/sdk/error-handling#maintenance-mode).
* **Unsupported region** (`completion.type == "region"`) — the player is in a region where Earn isn't available, and there's no retry path, so the modal won't help. Hide all Earn-related UI and functionality (recommended), or show a message that Earn isn't available in their region.
* **Other failures** (network, VPN/proxy, attestation) — call `ShowModal()`. The modal surfaces the reason and gives the player a retry path.

```csharp theme={null}
ZBDController.Instance.Init(completion =>
{
    if (completion.success)
    {
        // SDK ready — proceed normally
        return;
    }

    if (completion.maintenance)
    {
        // Not an error — ZBD is in maintenance, no retry path.
        // New players: hide Earn UI. Existing earners: show a
        // "rewards temporarily unavailable" message.
        ShowMaintenanceMessage();
    }
    else if (completion.type == "region")
    {
        // Unsupported region — no retry path.
        // Hide all Earn UI/functionality, or show a "not available in your region" message.
        HideEarnUI();
    }
    else
    {
        // Network, VPN/proxy, or attestation failure —
        // show the modal so the player can see why and retry.
        ZBDModalController.Instance.ShowModal();
    }
});
```

See [Error Handling](/earn/sdk/error-handling) for the full matrix of failure states and correct responses.
