# Battle pass

`client.BattlePass` (`BattlePassService`), verified against the bundled
`Rudder.Core.dll`. There is no sample scene for this feature.

Progress is tied to a scenario battle-pass node. Prefer `BattlePassEffect`
delivered by `Effects.OnBattlePass` — it binds `scenarioId`/`nodeId`/
`runId` for you. Direct `BattlePassService` calls need those ids manually.

## BattlePassEffect (preferred)

```csharp
client.Effects.OnBattlePass += async effect =>
{
    var progress = await effect.GetProgressAsync();
    await effect.AddXpAsync("kills", 100);
    var claim = await effect.ClaimRewardAsync(level, BattlePassService.TrackFree);
};
```

- `Task<GetBattlePassProgressResponse> GetProgressAsync(CancellationToken = default)`
- `Task<AddBattlePassXpResponse> AddXpAsync(string source, long amount, CancellationToken = default)`
- `Task<ClaimBattlePassRewardResponse> ClaimRewardAsync(int level, string track, CancellationToken = default)`
- `Task<PurchaseBattlePassPremiumResponse> PurchasePremiumAsync(CancellationToken = default)` — posts `onPremiumPurchase` on success
- `LevelUp()` / `LevelUpAsync()` — posts `onLevelUp`
- `End()` / `EndAsync()` — posts `onComplete`
- `Get<T>(key, fallback)`, `RunId`, `ScenarioId`, `NodeId`, `Data` like other effects

`BattlePassLevelEffect` (from `OnBattlePassLevel`) has `Claim()` /
`ClaimAsync()` (posts `onComplete`) and a `Level` property.

## BattlePassService (direct)

- `Task<GetBattlePassProgressResponse> GetProgressAsync(string scenarioId, string nodeId, CancellationToken = default)`
- `Task<AddBattlePassXpResponse> AddXpAsync(AddBattlePassXpRequest request, CancellationToken = default)`
- `Task<ClaimBattlePassRewardResponse> ClaimRewardAsync(ClaimBattlePassRewardRequest request, CancellationToken = default)`
- `Task<PurchaseBattlePassPremiumResponse> PurchasePremiumAsync(PurchaseBattlePassPremiumRequest request, CancellationToken = default)`
- Track constants: `BattlePassService.TrackFree`, `BattlePassService.TrackPremium` (static fields).

Request models carry `ScenarioId`, `NodeId`, and (except progress)
`RunId`; `PurchaseBattlePassPremiumRequest` also takes `IdempotencyKey`.

## Response models

- `GetBattlePassProgressResponse` — `Level` (`int?`), `Xp` (`long?`),
  `PremiumOwned` (`bool?`), `ClaimedTiers` (`List<ClaimedTier>`: `Level`,
  `Track`).
- `AddBattlePassXpResponse` — `Xp` (`long?`), `Level` (`int?`),
  `LeveledUp` (`bool?`), `MaxLevel` (`bool?`).
- `ClaimBattlePassRewardResponse` — `Success` (`bool?`),
  `AlreadyClaimed` (`bool?`), `Granted` (`List<Reward>`), `Error`.
- `PurchaseBattlePassPremiumResponse` — `Success` (`bool?`), `Error`.

Business failures come back in the response (`Success != true`, `Error`)
with codes from `RudderErrorCodes` (`LevelNotReached`,
`ObjectivesIncomplete`, `NodeNotActive`, `RunExpired`, ...); transport
failures throw `RudderApiException` subclasses.
