@fundedfast/sdk 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,9 +21,17 @@ export type WebhookDeliveryStatus = 'pending' | 'delivered' | 'failed';
21
21
  /** Tenant integration mode */
22
22
  export type IntegrationMode = 'sync' | 'async';
23
23
  /** All possible rejection reason codes from the rules engine */
24
- export type RejectionCode = 'min_stake_not_met' | 'max_stake_exceeded' | 'odds_limit_exceeded' | 'min_odds_not_met' | 'max_payout_exceeded' | 'max_selections_exceeded' | 'max_win_exceeded' | 'lucky_bet_profit_limit' | 'daily_drawdown_exceeded' | 'max_drawdown_exceeded' | 'cooldown_active' | 'cashout_not_allowed_during_challenge';
24
+ export type RejectionCode = 'min_stake_not_met' | 'max_stake_exceeded' | 'odds_limit_exceeded' | 'min_odds_not_met' | 'max_payout_exceeded' | 'max_selections_exceeded' | 'max_win_exceeded' | 'lucky_bet_profit_limit' | 'daily_drawdown_exceeded' | 'max_drawdown_exceeded' | 'cooldown_active' | 'payout_pending' | 'cashout_not_allowed_during_challenge'
25
+ /** Settlements only. A won/lost after a different result for the same bet: held for an operator, no balance change. */
26
+ | 'conflicting_settlement'
27
+ /** Settlements only. Stake or odds differ from the accepted placement, or the payout exceeds stake x odds: held, no balance change. */
28
+ | 'settlement_mismatch'
29
+ /** Settlements only. FAST never accepted this bet (rejected, or placed with no programme). Recorded, no balance change. */
30
+ | 'no_accepted_placement'
31
+ /** Settlements only. Accepted on a programme that has closed since, typically a challenge that passed with the bet still open. Recorded under that programme, no balance change. */
32
+ | 'program_closed';
25
33
  /** Webhook event types emitted by FAST */
26
- export type WebhookEventType = 'challenge.activated' | 'challenge.passed' | 'challenge.completed' | 'challenge.failed' | 'challenge.cancelled' | 'challenge.expiring_soon' | 'challenge.stake_refunded' | 'challenge.bonus_voided' | 'funded_account.activated' | 'funded_account.revoked' | 'funded_account.payout' | 'funded_account.stake_refunded' | 'cooldown.triggered' | 'cooldown.lifted' | 'bet.validation_result' | 'achievement.earned' | 'reward.granted' | 'reward.applied' | 'user.self_excluded' | 'user.self_exclusion_lifted' | 'bonus.activated' | 'bonus.progress' | 'bonus.completed' | 'bonus.expired' | 'bonus.forfeited' | 'mission.enrolled' | 'mission.progress' | 'mission.completed' | 'mission.expired' | 'tournament.started' | 'tournament.user_joined' | 'tournament.user_invited' | 'tournament.settled' | 'tournament.cancelled' | 'loyalty.tier_upgraded' | 'loyalty.tier_downgraded' | 'loyalty.cashback_settled' | 'reward.expired';
34
+ export type WebhookEventType = 'challenge.activated' | 'challenge.passed' | 'challenge.completed' | 'challenge.failed' | 'challenge.cancelled' | 'challenge.expiring_soon' | 'challenge.stake_refunded' | 'challenge.bonus_voided' | 'funded_account.activated' | 'funded_account.revoked' | 'funded_account.payout' | 'funded_account.stake_refunded' | 'funded_account.payout_requested' | 'funded_account.payout_rejected' | 'cooldown.triggered' | 'cooldown.lifted' | 'bet.validation_result' | 'achievement.earned' | 'reward.granted' | 'reward.applied' | 'user.self_excluded' | 'user.self_exclusion_lifted' | 'bonus.activated' | 'bonus.progress' | 'bonus.completed' | 'bonus.expired' | 'bonus.forfeited' | 'mission.enrolled' | 'mission.progress' | 'mission.completed' | 'mission.expired' | 'tournament.started' | 'tournament.user_joined' | 'tournament.user_invited' | 'tournament.settled' | 'tournament.cancelled' | 'loyalty.tier_upgraded' | 'loyalty.tier_downgraded' | 'loyalty.cashback_settled' | 'reward.expired';
27
35
  /** Body for POST /challenges/purchase */
28
36
  export interface PurchaseRequest {
29
37
  /** Your sportsbook user identifier */
@@ -60,8 +68,98 @@ export interface BetEvent {
60
68
  }
61
69
  /** Body for POST /users/:userId/withdraw */
62
70
  export interface WithdrawRequest {
63
- /** Amount to withdraw. Must be <= withdrawable profit. */
71
+ /** Amount to pay out. Must be <= withdrawable and >= the minimum payout. Ignored on the last allowed payout, which is always the full available amount. */
72
+ amount?: number;
73
+ /** Leave the request pending for a later confirm/reject instead of executing it now. */
74
+ deferred?: boolean;
75
+ }
76
+ /** Why a payout is not possible yet. Every reason that applies is listed. */
77
+ export interface PayoutReason {
78
+ code: 'account_not_active' | 'payout_pending' | 'max_payouts_reached' | 'no_profit' | 'insufficient_active_days' | 'insufficient_bets' | 'below_min_payout' | 'payout_interval' | 'open_bets';
79
+ /** False when the reason only keeps the cycle share out and unpaid profit can still be requested. */
80
+ blocking: boolean;
81
+ current?: number;
82
+ required?: number;
83
+ missing?: number;
84
+ until?: string;
85
+ }
86
+ export interface PendingPayout {
87
+ id: string;
64
88
  amount: number;
89
+ fromUnpaid: number;
90
+ fromCycle: number;
91
+ isFinal: boolean;
92
+ isMandatory: boolean;
93
+ createdAt: string;
94
+ }
95
+ /** Payout state of a funded account (the per-cycle model). */
96
+ export interface PayoutState {
97
+ currentBalance: number;
98
+ fundedAmount: number;
99
+ profitSplitPercent: number;
100
+ cycleProfit: number;
101
+ cycleShare: number;
102
+ /** Already split, not yet paid. Not part of the balance, never split again. */
103
+ unpaidProfit: number;
104
+ available: number;
105
+ withdrawableNow: number;
106
+ activeDays: number;
107
+ minActiveDays: number;
108
+ cycleBets: number;
109
+ minBets: number;
110
+ conditionsMet: boolean;
111
+ payoutCount: number;
112
+ maxPayouts: number | null;
113
+ remainingPayouts: number | null;
114
+ isFinal: boolean;
115
+ minPayout: number | null;
116
+ payoutIntervalDays: number | null;
117
+ lastPayoutAt: string | null;
118
+ nextPayoutAt: string | null;
119
+ mandatoryPayoutThreshold: number | null;
120
+ totalWithdrawn: number;
121
+ openStake: number;
122
+ pending: PendingPayout | null;
123
+ reasons: PayoutReason[];
124
+ canRequest: boolean;
125
+ }
126
+ export interface PayoutRequest {
127
+ id: string;
128
+ fundedAccountId: string;
129
+ userId: string;
130
+ amount: number;
131
+ fromUnpaid: number;
132
+ fromCycle: number;
133
+ isFinal: boolean;
134
+ isMandatory: boolean;
135
+ status: 'pending' | 'executed' | 'rejected';
136
+ rejectionReason: string | null;
137
+ ownStakeReturned: number | null;
138
+ /** Paid by the operator on top of `amount` from payout bonus rewards (0 until executed). */
139
+ rewardBonus: number;
140
+ /** Sum of the payout bonus percents applied. */
141
+ rewardBonusPercent: number;
142
+ decidedBy: string | null;
143
+ createdAt: string;
144
+ decidedAt: string | null;
145
+ }
146
+ /** A payout request as the user's own list returns it: who decided it is not included. */
147
+ export type UserPayoutRequest = Omit<PayoutRequest, 'decidedBy'>;
148
+ /** Result of confirming a payout request. */
149
+ export interface PayoutExecution {
150
+ payoutRequestId: string;
151
+ userPayout: number;
152
+ ownStakeReturned: number;
153
+ /** Paid on top of userPayout from payout bonus rewards; not deducted from the balance. */
154
+ rewardBonus: number;
155
+ /** userPayout + ownStakeReturned + rewardBonus */
156
+ totalPayout: number;
157
+ operatorShare: number;
158
+ newBalance: number;
159
+ unpaidProfit: number;
160
+ cycleClosed: boolean;
161
+ forfeitedProfit: number;
162
+ accountClosed: boolean;
65
163
  }
66
164
  /** A challenge instance */
67
165
  export interface Challenge {
@@ -88,6 +186,54 @@ export interface Challenge {
88
186
  createdAt: string;
89
187
  updatedAt: string;
90
188
  }
189
+ /** A challenge as GET /users/:userId/history returns it. */
190
+ export interface ChallengeHistory {
191
+ id: string;
192
+ status: ChallengeStatus;
193
+ failureReason?: string | null;
194
+ ownStake: number;
195
+ startingBalance: number;
196
+ currentBalance: number;
197
+ targetBalance: number;
198
+ startedAt?: string | null;
199
+ expiresAt?: string | null;
200
+ totalBetsPlaced: number;
201
+ totalBetsAccepted: number;
202
+ activeDaysCount: number;
203
+ createdAt?: string | null;
204
+ /** Name of the tier it was bought as. */
205
+ tierName?: string | null;
206
+ /** When it finished. Null while active or awaiting the continue/refund choice. */
207
+ endedAt?: string | null;
208
+ }
209
+ /** A payout request as listed on a funded account in the user history. */
210
+ export interface HistoryPayout {
211
+ amount: number;
212
+ status: 'pending' | 'executed' | 'rejected';
213
+ isFinal: boolean;
214
+ isMandatory: boolean;
215
+ createdAt: string;
216
+ decidedAt?: string | null;
217
+ }
218
+ /** A funded account as GET /users/:userId/history returns it. */
219
+ export interface FundedAccountHistory {
220
+ id: string;
221
+ status: string;
222
+ revocationReason?: string | null;
223
+ fundedAmount: number;
224
+ currentBalance: number;
225
+ totalWithdrawn: number;
226
+ profitSplitPercent: number;
227
+ createdAt?: string | null;
228
+ /** The passed challenge the account was created from. */
229
+ challengeId?: string | null;
230
+ payoutCount?: number;
231
+ maxPayouts?: number | null;
232
+ /** When it closed or was revoked. Null while active. */
233
+ endedAt?: string | null;
234
+ /** Payout requests on the account, newest first. */
235
+ payouts?: HistoryPayout[];
236
+ }
91
237
  /** A challenge product tier (as returned by the public /challenge-tiers endpoint) */
92
238
  export interface ChallengeTier {
93
239
  id: string;
@@ -123,21 +269,50 @@ export interface ChallengeTier {
123
269
  /** Lucky bet max profit as % of target */
124
270
  luckyBetMaxProfitPercent: number;
125
271
  }
126
- /** Full challenge tier with admin-level fields (from /admin/challenge-tiers) */
127
- export interface ChallengeTierFull extends ChallengeTier {
128
- /** Max payout as % of funded balance per cycle. null = no cap */
129
- payoutCapPercent: number | null;
130
- /** ISO 4217 currency code */
131
- currency: string;
132
- enabled: boolean;
272
+ /** Full challenge tier with admin-level fields (from /admin/challenge-tiers). The bet limits live on the referenced rulesets. */
273
+ export interface ChallengeTierFull {
274
+ id: string;
275
+ tenantId: string;
276
+ name: string;
277
+ /** Own stake the user pays to enter */
278
+ ownStake: number;
279
+ /** Conditional bonus granted by the operator */
280
+ bonusAmount: number;
281
+ targetBalance: number;
282
+ durationDays: number;
133
283
  challengeRulesetId: string;
134
284
  fundedRulesetId: string;
285
+ fundedAccountBalance: number;
286
+ /** Profit split in user's favor (e.g. 80 = 80%) */
287
+ profitSplitPercent: number;
288
+ /** Max payout as % of funded balance per cycle. null = no cap */
289
+ payoutCapPercent: number | null;
290
+ /** @deprecated Decides nothing: every payout that includes the cycle share returns the balance to the funded amount. */
135
291
  resetBalanceOnPayout: boolean;
136
292
  fundedMinActiveDays: number;
137
293
  fundedActiveDayPercent: number;
294
+ /** Whether the user may take back the own stake during the funded phase. */
295
+ fundedStakeRefundable?: boolean;
296
+ /** Lifetime payout cap on the funded account. Null = none. */
297
+ fundedTotalPayoutCap?: number | null;
298
+ /** Accepted bets required per payout cycle. */
299
+ fundedMinBets?: number;
300
+ /** Most payouts the funded account allows. Null = no limit. */
301
+ fundedMaxPayouts?: number | null;
302
+ /** Smallest payout that may be requested. Null = none. */
303
+ fundedMinPayout?: number | null;
304
+ /** Days between payouts. Null = no interval. */
305
+ fundedPayoutIntervalDays?: number | null;
306
+ /** Balance at which a payout becomes mandatory. Null = never. */
307
+ fundedMandatoryPayoutThreshold?: number | null;
308
+ /** ISO 4217 currency code */
309
+ currency: string;
310
+ enabled: boolean;
138
311
  createdAt: string;
139
312
  updatedAt: string;
140
313
  }
314
+ /** Body for creating a challenge tier: the fields the API requires, plus any optional ones. */
315
+ export type ChallengeTierCreateRequest = Pick<ChallengeTierFull, 'name' | 'ownStake' | 'bonusAmount' | 'targetBalance' | 'durationDays' | 'challengeRulesetId' | 'fundedRulesetId' | 'fundedAccountBalance' | 'profitSplitPercent' | 'payoutCapPercent' | 'resetBalanceOnPayout' | 'fundedMinActiveDays' | 'fundedActiveDayPercent'> & Partial<Omit<ChallengeTierFull, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>>;
141
316
  /** Rules engine validation result */
142
317
  export interface ValidationResult {
143
318
  /** accepted = passes all rules, rejected = violates rules, flagged = accepted but noted */
@@ -160,8 +335,17 @@ export interface Ruleset {
160
335
  dailyDrawdownPercent: number;
161
336
  totalDrawdownPercent: number;
162
337
  cooldownDurationHours: number | null;
163
- balanceCalculationBasis: 'original' | 'current';
164
- enabled: boolean;
338
+ balanceCalculationBasis?: 'original' | 'current';
339
+ /** Max selections in an accumulator bet. 0 = no limit. */
340
+ maxAccumulatorSelections?: number;
341
+ /** Absolute cap on potential win per ticket. Null = no cap. */
342
+ maxWinPerTicket?: number | null;
343
+ /** Basis for the daily drawdown calculation. */
344
+ sessionStopBasis?: 'original' | 'current';
345
+ enabled?: boolean;
346
+ tenantId?: string;
347
+ createdAt?: string;
348
+ updatedAt?: string;
165
349
  }
166
350
  /** Live challenge progress for sportsbook UI */
167
351
  export interface ChallengeProgress {
@@ -208,7 +392,18 @@ export interface FundedAccountProgress {
208
392
  fundedAccountId: string;
209
393
  currentBalance: number;
210
394
  fundedAmount: number;
211
- purchasePrice: number;
395
+ /** @deprecated Never returned by the API; always undefined. */
396
+ purchasePrice?: number;
397
+ /** Own stake the user paid to enter. */
398
+ ownStake?: number;
399
+ /** Operator bonus: never withdrawable. */
400
+ nonWithdrawableBonus?: number;
401
+ /** Own stake the user can still take back with `refundFundedStake` (0 when not allowed). */
402
+ refundableOwnStake?: number;
403
+ /** Whether the tier allows an own-stake refund in the funded phase. */
404
+ stakeRefundable?: boolean;
405
+ /** Lifetime payout cap, null for none. */
406
+ totalPayoutCap?: number | null;
212
407
  withdrawableProfit: number;
213
408
  earnedProfit: number;
214
409
  rawProfit: number;
@@ -218,8 +413,27 @@ export interface FundedAccountProgress {
218
413
  totalWithdrawn: number;
219
414
  activeDays: number;
220
415
  minActiveDays: number;
221
- status: 'active';
416
+ status: 'active' | 'closed' | 'revoked';
222
417
  reserved: number;
418
+ /** Stake on bets not yet settled. */
419
+ openStake?: number;
420
+ payoutCount?: number;
421
+ maxPayouts?: number | null;
422
+ unpaidProfit?: number;
423
+ /** Accepted bets in the current payout cycle. */
424
+ totalBetsAccepted?: number;
425
+ /** Stake a day needs for it to count as an active day. */
426
+ activeDayThreshold?: number;
427
+ /** Stake placed today towards `activeDayThreshold`. */
428
+ todayWagered?: number;
429
+ minBetsRequired?: number;
430
+ maxWinPerTicket?: number | null;
431
+ payout?: PayoutState | null;
432
+ /** Split points rewards added when this account opened (0 if none). */
433
+ profitSplitRewardBoost?: number;
434
+ /** Payout bonus percent waiting for the next executed payout (0 if none). */
435
+ payoutBonusPercent?: number;
436
+ lastPayoutRequest?: Pick<PayoutRequest, 'id' | 'amount' | 'status' | 'rejectionReason' | 'isFinal' | 'isMandatory' | 'createdAt' | 'decidedAt' | 'rewardBonus'> | null;
223
437
  currency?: string;
224
438
  selfExcluded?: boolean;
225
439
  }
@@ -227,6 +441,11 @@ export interface FundedAccountProgress {
227
441
  export interface NoProgress {
228
442
  type: 'none';
229
443
  message: string;
444
+ /** How the last programme ended: a failed challenge, or a funded account that finished. */
445
+ lastOutcome?: (Record<string, unknown> & {
446
+ type: 'challenge_failed' | 'funded_closed';
447
+ endedAt: string;
448
+ }) | null;
230
449
  selfExcluded?: boolean;
231
450
  }
232
451
  /** Discriminated union - check the `type` field */
@@ -241,12 +460,25 @@ export interface WithdrawableInfo {
241
460
  activeDaysCount: number;
242
461
  minActiveDays: number;
243
462
  activeDaysMet: boolean;
463
+ payout: PayoutState;
244
464
  }
245
- /** Withdrawal result with profit split breakdown */
465
+ /** Payout request result. `executed` carries the profit split breakdown. */
246
466
  export interface WithdrawalResult {
247
- newBalance: number;
248
- userPayout: number;
249
- operatorShare: number;
467
+ status: 'pending' | 'executed';
468
+ payoutRequestId: string;
469
+ amount: number;
470
+ isFinal: boolean;
471
+ newBalance?: number;
472
+ userPayout?: number;
473
+ ownStakeReturned?: number;
474
+ /** Paid on top of userPayout from payout bonus rewards. */
475
+ rewardBonus?: number;
476
+ totalPayout?: number;
477
+ operatorShare?: number;
478
+ resetApplied?: boolean;
479
+ unpaidProfit?: number;
480
+ forfeitedProfit?: number;
481
+ accountClosed?: boolean;
250
482
  }
251
483
  /** Bet ingestion result (sync or async mode) */
252
484
  export interface BetIngestResult {
@@ -255,17 +487,35 @@ export interface BetIngestResult {
255
487
  validationResult?: ValidationResult;
256
488
  message?: string;
257
489
  }
490
+ /** One bet's outcome in a batch. */
491
+ export interface BatchBetItemResult {
492
+ /** Zero-based position of the bet in the submitted array. */
493
+ index: number;
494
+ /**
495
+ * The submitted bet's externalBetId, filled in by the SDK from `index`.
496
+ * @sdkComputed
497
+ */
498
+ externalBetId?: string;
499
+ /** processed (sync mode), accepted (async mode, queued), or error. */
500
+ status: 'processed' | 'accepted' | 'error';
501
+ validationResult?: ValidationResult;
502
+ /** Why the bet failed, when status is 'error'. */
503
+ error?: string;
504
+ }
258
505
  /** Batch bet ingestion result */
259
506
  export interface BatchBetResult {
507
+ status: 'completed';
260
508
  total: number;
509
+ /** Bets processed or accepted. */
510
+ succeeded: number;
511
+ /**
512
+ * @deprecated Use `succeeded`. Kept as an alias, filled in by the SDK.
513
+ * @sdkComputed
514
+ */
261
515
  processed: number;
262
516
  failed: number;
263
- results: Array<{
264
- externalBetId: string;
265
- status: 'processed' | 'failed';
266
- validationResult?: ValidationResult;
267
- error?: string;
268
- }>;
517
+ /** Per-bet results in submission order. */
518
+ results: BatchBetItemResult[];
269
519
  }
270
520
  /** Reconciliation data for cross-referencing with sportsbook records */
271
521
  export interface ReconciliationData {
@@ -280,13 +530,46 @@ export interface SseToken {
280
530
  ttl: number;
281
531
  userId: string;
282
532
  }
283
- /** Challenge tier terms and disclosures (regulatory compliance) */
533
+ /** The ruleset limits disclosed with a tier's terms. */
534
+ export interface TierTermsRules {
535
+ maxStakePercent: number;
536
+ minOdds: number;
537
+ maxOdds: number;
538
+ maxPayoutMultiplier: number;
539
+ maxWinPerTicket: number | null;
540
+ minBetsRequired: number;
541
+ minActiveDays: number;
542
+ dailyDrawdownPercent: number;
543
+ totalDrawdownPercent: number;
544
+ cooldownDurationHours: number | null;
545
+ luckyBetMaxProfitPercent: number;
546
+ luckyBetMaxOdds: number;
547
+ balanceCalculationBasis: string;
548
+ }
549
+ /** Language of the human-readable terms and disclosures. */
550
+ export type TermsLanguage = 'en' | 'hr' | 'de';
551
+ /** Challenge tier terms and disclosures (regulatory compliance), as GET /challenge-tiers/:id/terms returns them. */
284
552
  export interface TierTerms {
285
553
  tierId: string;
286
554
  tierName: string;
287
- rules: string[];
555
+ purchasePrice: number;
556
+ ownStake: number;
557
+ bonusAmount: number;
558
+ currency: string;
559
+ /** Balance the user plays with: own stake + bonus. */
560
+ challengeBalance: number;
561
+ targetBalance: number;
562
+ durationDays: number;
563
+ /** Base balance of the reward (funded) account on continuing. */
564
+ rewardAccountBalance: number;
565
+ profitSplitPercent: number;
566
+ payoutCapPercent: number | null;
567
+ /** @deprecated Decides nothing: every payout that includes the cycle share returns the balance to the funded amount. */
568
+ resetBalanceOnPayout?: boolean;
569
+ rules: TierTermsRules;
570
+ /** Sentences to show the user before purchase, in `lang`. */
288
571
  disclosures: string[];
289
- terms: string;
572
+ lang: TermsLanguage;
290
573
  }
291
574
  /** Webhook event payload delivered to your endpoint */
292
575
  export interface WebhookPayload<T = Record<string, unknown>> {
@@ -296,9 +579,8 @@ export interface WebhookPayload<T = Record<string, unknown>> {
296
579
  timestamp: string;
297
580
  data: T;
298
581
  }
299
- /** A user achievement (earned or locked) */
300
- export interface Achievement {
301
- id: string;
582
+ /** Fields every achievement carries, earned or not. */
583
+ export interface AchievementBase {
302
584
  code: string;
303
585
  name: string;
304
586
  description: string;
@@ -306,35 +588,54 @@ export interface Achievement {
306
588
  category: string;
307
589
  points: number;
308
590
  rarity: 'common' | 'rare' | 'epic' | 'legendary';
309
- earned: boolean;
310
- earnedAt: string | null;
311
- progress: number | null;
312
- target: number | null;
591
+ }
592
+ /** An achievement the user has earned. */
593
+ export interface Achievement extends AchievementBase {
594
+ earnedAt: string;
595
+ metadata: Record<string, unknown> | null;
596
+ }
597
+ /** An achievement not yet earned, with progress towards it. */
598
+ export interface LockedAchievement extends AchievementBase {
599
+ sortOrder: number;
600
+ /** What earns it: `progress` counts towards `threshold`. */
601
+ criteria: {
602
+ type: string;
603
+ threshold: number;
604
+ } | null;
605
+ progress: number;
313
606
  }
314
607
  /** User achievements response */
315
608
  export interface UserAchievements {
609
+ /** Earned achievements, most recent first. */
316
610
  achievements: Achievement[];
611
+ /** Achievements not yet earned, in display order. */
612
+ locked: LockedAchievement[];
317
613
  totalPoints: number;
318
614
  level: number;
319
615
  streak: {
320
616
  current: number;
321
617
  longest: number;
322
- lastActiveDate: string | null;
323
618
  };
324
619
  }
325
620
  /** Reward type */
326
- export type RewardType = 'balance_bonus' | 'balance_boost_percent' | 'purchase_discount_percent' | 'purchase_discount_fixed' | 'profit_split_boost' | 'extended_duration' | 'payout_cap_boost_percent' | 'free_bet' | 'bonus_credit' | 'cashback_credit' | 'loyalty_points' | 'custom';
621
+ export type RewardType = 'balance_bonus' | 'balance_boost_percent' | 'purchase_discount_percent' | 'purchase_discount_fixed' | 'profit_split_boost' | 'extended_duration' | 'payout_cap_boost_percent'
622
+ /** Percent of the next executed payout, paid on top by the operator. */
623
+ | 'payout_bonus_percent' | 'free_bet' | 'bonus_credit' | 'cashback_credit' | 'loyalty_points' | 'custom';
327
624
  /** Reward apply mode */
328
625
  export type RewardApplyMode = 'auto' | 'claim';
329
626
  /** A user reward */
330
627
  export interface Reward {
331
628
  id: string;
332
629
  rewardType: RewardType;
630
+ /** In EUR for money types, otherwise percent or days. */
333
631
  rewardValue: number;
632
+ /** On claimable items the API omits this; the SDK fills `'claim'`. */
334
633
  applyMode: RewardApplyMode;
634
+ /** ISO 8601, or null when it never expires. */
335
635
  expiresAt: string | null;
336
636
  achievementCode: string | null;
337
637
  achievementName: string | null;
638
+ /** ISO 8601 */
338
639
  createdAt: string;
339
640
  }
340
641
  /** User rewards response */
@@ -343,11 +644,28 @@ export interface UserRewards {
343
644
  rewards: Reward[];
344
645
  /** Rewards waiting for user to claim */
345
646
  claimable: Reward[];
647
+ /** Reward rules the user can still earn, with progress. */
648
+ available: EarnableReward[];
346
649
  }
347
- /** Reward claim result */
650
+ /** A reward rule the user has not used up yet, and how far along they are. */
651
+ export interface EarnableReward {
652
+ ruleId: string;
653
+ name: string;
654
+ description: string | null;
655
+ rewardType: RewardType;
656
+ rewardValue: number;
657
+ applyMode: RewardApplyMode;
658
+ /** e.g. `win_streak` (winning slips in a row), `clean_days` (betting days since the last cooldown). */
659
+ criteriaType: string;
660
+ threshold: number;
661
+ /** Where the user stands against `threshold`; null for a criteria FAST cannot measure. */
662
+ current: number | null;
663
+ /** 0 to 1 */
664
+ progress: number;
665
+ }
666
+ /** Reward claim result. Read the reward back with `users.getRewards()` if you need it. */
348
667
  export interface RewardClaimResult {
349
668
  claimed: boolean;
350
- reward: Reward;
351
669
  }
352
670
  /** Leaderboard entry */
353
671
  export interface LeaderboardEntry {
@@ -380,27 +698,41 @@ export interface SandboxResetResult {
380
698
  export interface SandboxUserResetResult {
381
699
  status: string;
382
700
  userId: string;
383
- deleted: Record<string, number>;
701
+ /** Which kinds of data were cleared (challenges, fundedAccounts, betEvents, webhookDeliveries). */
702
+ deleted: Record<string, boolean>;
384
703
  }
385
704
  /** Bet event as returned by admin endpoints */
386
705
  export interface AdminBetEvent {
387
706
  id: string;
707
+ tenantId?: string;
388
708
  userId: string;
389
709
  externalBetId: string;
710
+ challengeId?: string | null;
711
+ fundedAccountId?: string | null;
390
712
  stakeAmount: number;
391
713
  odds: number;
714
+ betTypeIdentifier?: string | null;
392
715
  status: BetStatus;
716
+ isCashOut?: boolean;
393
717
  validationResult: ValidationStatus | null;
394
- reasonCodes: RejectionCode[];
718
+ /** Rule violation codes. Empty when accepted. */
719
+ rejectionReasons: RejectionCode[];
720
+ /**
721
+ * @deprecated The API calls this `rejectionReasons`; the SDK fills this alias from it.
722
+ * @sdkComputed
723
+ */
724
+ reasonCodes?: RejectionCode[];
395
725
  settlementAmount: number | null;
726
+ currency?: string;
396
727
  eventTimestamp: string;
728
+ processedAt?: string | null;
397
729
  createdAt: string;
398
730
  }
399
731
  /** Settle a bet event */
400
732
  export interface BetSettleRequest {
401
733
  outcome: 'won' | 'lost';
402
734
  }
403
- /** Bulk settle request */
735
+ /** Bulk settle request (max 50 settlements per call) */
404
736
  export interface BulkSettleRequest {
405
737
  settlements: Array<{
406
738
  betEventId: string;
@@ -411,6 +743,10 @@ export interface BulkSettleRequest {
411
743
  export interface BulkSettleResult {
412
744
  results: Array<{
413
745
  betEventId: string;
746
+ status: 'settled' | 'error';
747
+ /** Why it was not settled, e.g. `not_found`, `already_settled`. */
748
+ error?: string;
749
+ /** @deprecated Use `status === 'settled'`. Filled in by the SDK. */
414
750
  success: boolean;
415
751
  }>;
416
752
  settled: number;
@@ -422,120 +758,294 @@ export interface WebhookDelivery {
422
758
  eventId: string;
423
759
  eventType: WebhookEventType;
424
760
  userId: string;
761
+ /** The exact body that was (or will be) POSTed. */
762
+ payload: WebhookPayload;
763
+ webhookUrl: string;
425
764
  status: WebhookDeliveryStatus;
426
765
  responseStatus: number | null;
427
766
  attempts: number;
428
767
  lastAttemptAt: string | null;
429
768
  createdAt: string;
430
769
  }
431
- /** Audit log entry */
770
+ /** A webhook delivery that exhausted its retries. */
771
+ export interface WebhookDeadLetter {
772
+ id: string;
773
+ tenantId: string;
774
+ deliveryId: string;
775
+ eventId: string;
776
+ eventType: WebhookEventType;
777
+ userId: string;
778
+ payload: WebhookPayload;
779
+ webhookUrl: string;
780
+ finalAttempts: number;
781
+ lastError: string | null;
782
+ /** When it was replayed. Null until then; a dead letter replays once. */
783
+ replayedAt: string | null;
784
+ replayDeliveryId: string | null;
785
+ createdAt: string;
786
+ }
787
+ /** Result of rotating the webhook signing secret. */
788
+ export interface WebhookSecretRotation {
789
+ /** The new signing secret. Shown once: store it now. */
790
+ newSecret: string;
791
+ /** Hours the old secret keeps being accepted. */
792
+ gracePeriodHours: number;
793
+ oldSecretExpiresAt: string;
794
+ /** @deprecated Use `newSecret`. Filled in by the SDK. */
795
+ webhookSecret: string;
796
+ }
797
+ /** Admin audit log entry (GET /admin/audit-log) */
432
798
  export interface AuditEntry {
433
799
  id: string;
800
+ tenantId: string;
434
801
  action: string;
802
+ /** Admin email, or `api-key` for server-key calls. */
435
803
  actor: string;
436
- tenantId: string;
437
- targetId: string | null;
438
- targetType: string | null;
439
- metadata: Record<string, unknown>;
804
+ resourceType: string | null;
805
+ resourceId: string | null;
806
+ details: Record<string, unknown> | null;
807
+ ipAddress: string | null;
440
808
  createdAt: string;
441
809
  }
810
+ /** Which ledger GET /audit/log reads. */
811
+ export type AuditLogType = 'bets' | 'webhooks';
812
+ /** Page of GET /audit/log: bet events or webhook deliveries. */
813
+ export interface AuditLogPage {
814
+ /** `bet_events` or `webhook_deliveries`. */
815
+ type: string;
816
+ total: number;
817
+ limit: number;
818
+ offset: number;
819
+ entries: Array<Record<string, unknown>>;
820
+ }
442
821
  /** Tenant settings */
443
822
  export interface TenantSettings {
823
+ tenantId?: string;
824
+ name?: string;
825
+ environment?: string;
444
826
  integrationMode: IntegrationMode;
445
827
  webhookUrl: string | null;
446
828
  /** Single URL FAST calls before any money/irreversible action (type in payload). */
447
829
  approvalUrl: string | null;
448
830
  operatorChallengeLimit: number | null;
831
+ monthlyChallengeLimit?: number | null;
832
+ effectiveChallengeLimit?: number | null;
833
+ revenueSharePercent?: number;
834
+ exposureAlertThreshold?: number | null;
835
+ exportEnabled?: boolean;
836
+ exportEmail?: string | null;
837
+ exportWebhookUrl?: string | null;
838
+ defaultCurrency?: string;
839
+ supportedCurrencies?: string[];
840
+ widgetLayout?: {
841
+ fundedOnly: boolean;
842
+ history: boolean;
843
+ };
844
+ createdAt?: string;
449
845
  }
450
- /** Admin overview stats */
846
+ /** Admin overview stats (GET /admin/overview) */
451
847
  export interface AdminOverview {
848
+ period: {
849
+ month: number;
850
+ year: number;
851
+ };
852
+ /** Count per challenge status. */
452
853
  challenges: Record<string, number>;
854
+ /** Count per funded account status. */
453
855
  fundedAccounts: Record<string, number>;
454
- totalBets: number;
455
- uniqueUsers: number;
856
+ revenue: {
857
+ allTime: Record<string, number>;
858
+ /** Includes `uniqueUsers` for the month. */
859
+ month: Record<string, number>;
860
+ revenueShare: Record<string, number>;
861
+ };
862
+ exposure: Record<string, unknown>;
863
+ usage: Record<string, number>;
456
864
  }
457
- /** Bonus offer (admin) */
865
+ /** Bonus type */
866
+ export type BonusType = 'deposit_match' | 'free_bet' | 'no_deposit' | 'cashback' | 'reload';
867
+ /** Bonus offer (admin). Money fields are integer cents. */
458
868
  export interface BonusOffer {
459
869
  id: string;
870
+ tenantId?: string;
460
871
  name: string;
461
- bonusType: string;
872
+ description: string | null;
873
+ bonusType: BonusType;
462
874
  matchPercent: number | null;
875
+ /** Integer cents. */
463
876
  maxBonusAmount: number;
464
877
  wageringMultiplier: number;
465
- durationDays: number;
466
878
  minOdds: number | null;
879
+ /** Integer cents. */
880
+ maxBetFromBonus: number | null;
881
+ excludedMarkets: string[] | null;
882
+ durationDays: number;
883
+ /** Integer cents. */
884
+ minQualifyingDeposit: number | null;
885
+ maxActivations: number | null;
467
886
  maxPerUser: number | null;
887
+ stackable: boolean;
468
888
  forfeitOnWithdrawal: boolean;
469
889
  enabled: boolean;
890
+ startsAt: string | null;
891
+ endsAt: string | null;
892
+ sortOrder: number;
470
893
  createdAt: string;
894
+ updatedAt: string;
471
895
  }
472
- /** Bonus stats */
896
+ /** Bonus stats (GET /admin/bonuses/stats) */
473
897
  export interface BonusStats {
474
- totalActive: number;
475
- totalCompleted: number;
476
- totalForfeited: number;
477
- totalBonusAmount: number;
898
+ activeCount: number;
899
+ /** Percent of bonuses completed over the last 30 days. */
900
+ completionRate30d: number;
901
+ /** Bonus balance outstanding, integer cents. */
902
+ totalOutstanding: number;
903
+ avgProgress: number;
478
904
  }
479
905
  /** Mission definition (admin) */
480
906
  export interface MissionDef {
481
907
  id: string;
908
+ tenantId?: string;
482
909
  name: string;
483
910
  description: string | null;
911
+ icon: string | null;
484
912
  criteriaType: string;
485
913
  criteriaThreshold: number;
914
+ criteriaMeta: Record<string, unknown> | null;
486
915
  rewardType: string | null;
916
+ /** In cents for money types (bonus credit, free bet, fixed discount...), otherwise percent, days or points. Unlike reward rules and grants, which take EUR. */
487
917
  rewardValue: number;
488
- enrollmentMode: 'auto' | 'opt_in';
489
- durationHours: number | null;
490
- maxParticipants: number | null;
918
+ rewardApplyMode: string;
919
+ startsAt: string;
920
+ endsAt: string;
921
+ enrollmentMode: 'auto' | 'opt_in' | 'targeted';
922
+ repeatable: boolean;
923
+ maxCompletionsPerUser: number;
491
924
  enabled: boolean;
925
+ sortOrder: number;
492
926
  createdAt: string;
927
+ updatedAt: string;
928
+ }
929
+ /** Fields the API assigns itself and drops from a request body. */
930
+ type ServerManaged = 'id' | 'tenantId' | 'createdAt' | 'updatedAt';
931
+ /** Body for creating a mission: the fields the API requires, plus any optional ones. A new mission starts enabled. */
932
+ export type MissionCreateRequest = Pick<MissionDef, 'name' | 'criteriaType' | 'criteriaThreshold' | 'startsAt' | 'endsAt'> & Partial<Omit<MissionDef, ServerManaged | 'enabled'>>;
933
+ /** Body for updating a mission: any subset of its editable fields. */
934
+ export type MissionUpdateRequest = Partial<Omit<MissionDef, ServerManaged>>;
935
+ type RulesetRequired = 'name' | 'maxStakePercent' | 'minOdds' | 'maxOdds' | 'maxPayoutMultiplier' | 'dailyDrawdownPercent' | 'totalDrawdownPercent' | 'minActiveDays' | 'minBetsRequired' | 'luckyBetMaxOdds' | 'luckyBetMaxProfitPercent';
936
+ /** Body for creating a ruleset: the limits the API requires, plus any optional ones. */
937
+ export type RulesetCreateRequest = Pick<Ruleset, RulesetRequired> & Partial<Omit<Ruleset, RulesetRequired | ServerManaged>>;
938
+ /** Body for updating a ruleset: any subset of its editable fields. */
939
+ export type RulesetUpdateRequest = Partial<Omit<Ruleset, ServerManaged>>;
940
+ /** Body for creating a bonus offer. A new offer starts enabled. */
941
+ export type BonusOfferCreateRequest = Pick<BonusOffer, 'name' | 'bonusType' | 'maxBonusAmount'> & Partial<Omit<BonusOffer, 'name' | 'bonusType' | 'maxBonusAmount' | 'enabled' | ServerManaged>>;
942
+ /** Body for updating a bonus offer. The bonus type is fixed once created. */
943
+ export type BonusOfferUpdateRequest = Partial<Omit<BonusOffer, 'bonusType' | ServerManaged>>;
944
+ /** Body for updating the loyalty programme configuration. */
945
+ export type LoyaltyConfigUpdateRequest = Partial<Omit<LoyaltyConfig, ServerManaged>>;
946
+ /** Tournament lifecycle state */
947
+ export type TournamentStatus = 'upcoming' | 'active' | 'settling' | 'completed' | 'cancelled';
948
+ /** A prize band: ranks rankFrom..rankTo each receive the reward. */
949
+ export interface TournamentPrize {
950
+ rankFrom: number;
951
+ rankTo: number;
952
+ rewardType: string;
953
+ /** In cents for money types, otherwise percent, days or points. */
954
+ rewardValue: number;
493
955
  }
494
956
  /** Tournament definition (admin) */
495
957
  export interface TournamentDef {
496
958
  id: string;
959
+ tenantId?: string;
497
960
  name: string;
498
961
  description: string | null;
499
- status: 'draft' | 'scheduled' | 'active' | 'settling' | 'settled';
500
- entryMode: 'free' | 'paid';
501
- entryFee: number;
502
- prizePool: number;
503
- maxEntrants: number | null;
504
- scoringMetric: string;
962
+ scoringMetric: 'net_profit' | 'total_wagered' | 'win_count' | 'bet_count' | 'highest_odds_won' | 'longest_win_streak';
505
963
  startsAt: string;
506
964
  endsAt: string;
965
+ entryMode: 'auto' | 'opt_in' | 'invite';
966
+ minBetsToQualify: number;
967
+ maxParticipants: number | null;
968
+ prizes: TournamentPrize[];
969
+ tiebreaker: 'earliest_entry' | 'most_bets' | 'highest_single_win' | null;
970
+ status: TournamentStatus;
971
+ totalEntries: number;
972
+ settledAt: string | null;
507
973
  createdAt: string;
974
+ updatedAt?: string;
508
975
  }
976
+ /** Body for creating a tournament: the fields the API requires, plus any optional ones. */
977
+ export type TournamentCreateRequest = Pick<TournamentDef, 'name' | 'scoringMetric' | 'startsAt' | 'endsAt' | 'prizes'> & Partial<Pick<TournamentDef, 'description' | 'entryMode' | 'minBetsToQualify' | 'maxParticipants' | 'tiebreaker'>>;
509
978
  /** Tournament leaderboard entry */
510
979
  export interface TournamentLeaderboardEntry {
511
980
  rank: number;
512
981
  userId: string;
982
+ /** Masked user id for display. */
513
983
  displayName: string;
514
984
  score: number;
515
- prize: number | null;
985
+ qualifyingBets: number;
516
986
  }
517
- /** Loyalty config */
987
+ /** A tournament entry row as the admin entries list returns it. */
988
+ export interface TournamentEntry {
989
+ id: string;
990
+ tenantId: string;
991
+ tournamentId: string;
992
+ userId: string;
993
+ score: number | null;
994
+ qualifyingBets: number | null;
995
+ rank: number | null;
996
+ prizeType: string | null;
997
+ /** In cents for money types. */
998
+ prizeValue: number | null;
999
+ prizeGranted: boolean | null;
1000
+ enteredAt: string | null;
1001
+ lastScoreUpdate: string | null;
1002
+ }
1003
+ /** Loyalty config (GET/PUT /admin/loyalty/config) */
518
1004
  export interface LoyaltyConfig {
519
- enabled: boolean;
520
- pointsPerEurWagered: number;
521
- cashbackPercent: number;
522
- decayDays: number | null;
1005
+ id?: string;
1006
+ tenantId?: string;
1007
+ /** Activity-to-points rules, e.g. `{ activity: 'bet_placed', pointsPerEurWagered: 1, maxPerDay: 500 }`. */
1008
+ pointRules: Array<Record<string, unknown>>;
1009
+ decayMode: string;
523
1010
  decayPercent: number | null;
1011
+ cashbackEnabled: boolean;
1012
+ cashbackSettleMode: string;
1013
+ demotionEnabled: boolean;
1014
+ demotionGraceDays: number;
1015
+ enabled: boolean;
1016
+ createdAt?: string;
1017
+ updatedAt?: string;
524
1018
  }
525
1019
  /** Loyalty tier */
526
1020
  export interface LoyaltyTier {
527
1021
  id: string;
1022
+ tenantId?: string;
528
1023
  name: string;
1024
+ /** Rank order; higher is more prestigious. Required on create. */
1025
+ level: number;
529
1026
  minPoints: number;
530
- multiplier: number;
531
- perks: string[];
1027
+ cashbackPercent: number;
1028
+ benefits: unknown[];
1029
+ icon: string;
1030
+ color: string;
1031
+ createdAt?: string;
532
1032
  }
1033
+ /** Body for creating a loyalty tier. */
1034
+ export type LoyaltyTierCreateRequest = Pick<LoyaltyTier, 'name' | 'level' | 'minPoints'> & Partial<Pick<LoyaltyTier, 'cashbackPercent' | 'benefits' | 'icon' | 'color'>>;
1035
+ /** Body for updating a loyalty tier: any subset of its editable fields. */
1036
+ export type LoyaltyTierUpdateRequest = Partial<Pick<LoyaltyTier, 'name' | 'level' | 'minPoints' | 'cashbackPercent' | 'benefits' | 'icon' | 'color'>>;
533
1037
  /** Loyalty stats */
534
1038
  export interface LoyaltyStats {
535
- totalMembers: number;
536
- totalPointsIssued: number;
1039
+ totalUsers: number;
1040
+ avgPoints: number;
537
1041
  totalCashbackPaid: number;
538
- tierDistribution: Record<string, number>;
1042
+ /** Users active in the last 7 days. */
1043
+ active7d: number;
1044
+ tierDistribution: Array<{
1045
+ name: string;
1046
+ level: number;
1047
+ userCount: number;
1048
+ }>;
539
1049
  }
540
1050
  /** Webhook echo entry */
541
1051
  export interface WebhookEchoEntry {
@@ -565,28 +1075,131 @@ export interface ReconciliationFlag {
565
1075
  flaggedBy: string;
566
1076
  createdAt: string;
567
1077
  }
1078
+ /** Reward types an operator can grant or attach to a reward rule. */
1079
+ export type GrantableRewardType = 'balance_bonus' | 'balance_boost_percent' | 'purchase_discount_percent' | 'purchase_discount_fixed' | 'profit_split_boost' | 'extended_duration' | 'payout_cap_boost_percent' | 'payout_bonus_percent';
568
1080
  /** Reward rule definition (auto-grants rewards on criteria match) */
569
1081
  export interface RewardRule {
570
1082
  id: string;
1083
+ tenantId?: string;
571
1084
  name: string;
572
- triggerType: string;
573
- triggerThreshold: number;
574
- rewardType: RewardType;
1085
+ description: string | null;
1086
+ /** What triggers the grant: `type` reaching `threshold` (e.g. `{ type: 'active_days', threshold: 30 }`). */
1087
+ criteria: {
1088
+ type: string;
1089
+ threshold: number;
1090
+ };
1091
+ rewardType: GrantableRewardType;
1092
+ /** In EUR for money types, otherwise percent or days. Unlike missions and tournament prizes, which take cents. */
575
1093
  rewardValue: number;
576
1094
  applyMode: RewardApplyMode;
577
- maxGrantsPerUser: number | null;
1095
+ maxGrantsPerUser: number;
578
1096
  expiresInDays: number | null;
579
1097
  enabled: boolean;
580
1098
  sortOrder: number;
581
1099
  createdAt: string;
582
1100
  }
1101
+ /** Body for creating an achievement definition. */
1102
+ export interface AchievementCreateRequest {
1103
+ /** Unique code within the tenant. */
1104
+ code: string;
1105
+ name: string;
1106
+ description?: string;
1107
+ icon?: string;
1108
+ category?: AchievementCategory;
1109
+ points?: number;
1110
+ /** Unlock criteria, evaluated by the achievement engine. */
1111
+ criteria?: Record<string, unknown>;
1112
+ /** Reward granted on unlock, or null for none. Money values in EUR. */
1113
+ reward?: {
1114
+ type: GrantableRewardType;
1115
+ value: number;
1116
+ applyMode?: RewardApplyMode;
1117
+ expiresInDays?: number | null;
1118
+ } | null;
1119
+ }
1120
+ export type AchievementCategory = 'general' | 'streak' | 'volume' | 'profit' | 'milestone';
1121
+ /** Body for updating an achievement definition. Its code and reward are fixed once created. */
1122
+ export type AchievementUpdateRequest = Partial<Pick<AchievementCreateRequest, 'name' | 'description' | 'icon' | 'category' | 'points' | 'criteria'>> & {
1123
+ enabled?: boolean;
1124
+ };
1125
+ /** Body for updating the widget theme. */
1126
+ export interface ThemeUpdateRequest {
1127
+ primaryColor?: string;
1128
+ secondaryColor?: string;
1129
+ fontFamily?: string;
1130
+ /** Absolute URL of the logo image. */
1131
+ logoUrl?: string;
1132
+ /** Text overrides keyed by copy id. */
1133
+ customCopy?: Record<string, unknown>;
1134
+ }
1135
+ /** Events an operator can switch notifications on or off for. */
1136
+ export type NotificationPreferenceEvent = 'bet.validation_result' | 'challenge.activated' | 'challenge.completed' | 'challenge.failed' | 'cooldown.triggered' | 'cooldown.lifted' | 'funded_account.activated' | 'funded_account.payout' | 'funded_account.payout_requested' | 'funded_account.payout_rejected' | 'funded_account.revoked' | 'user.self_excluded' | 'user.self_exclusion_lifted';
1137
+ /** Body for updating notification preferences: the events to change, true to notify. */
1138
+ export type NotificationPreferencesUpdate = Partial<Record<NotificationPreferenceEvent, boolean>>;
1139
+ /** Body for excluding a user. Without expiresAt or durationDays the exclusion is permanent. */
1140
+ export interface SelfExclusionRequest {
1141
+ userId: string;
1142
+ reason?: string;
1143
+ /** ISO 8601 end of the exclusion, or null for permanent. Wins over durationDays. */
1144
+ expiresAt?: string | null;
1145
+ /** Exclusion length in days from now; the SDK turns it into expiresAt. */
1146
+ durationDays?: number;
1147
+ /** E.g. a national registry reference. */
1148
+ metadata?: Record<string, unknown>;
1149
+ }
1150
+ /** Body for creating or updating a reward rule. */
1151
+ export interface RewardRuleInput {
1152
+ name?: string;
1153
+ description?: string;
1154
+ criteria?: {
1155
+ type: string;
1156
+ threshold: number;
1157
+ };
1158
+ rewardType?: GrantableRewardType;
1159
+ /** In EUR for money types, otherwise percent or days. */
1160
+ rewardValue?: number;
1161
+ applyMode?: RewardApplyMode;
1162
+ maxGrantsPerUser?: number;
1163
+ expiresInDays?: number | null;
1164
+ sortOrder?: number;
1165
+ /** Update only. */
1166
+ enabled?: boolean;
1167
+ /** @deprecated Use `criteria.type`. Mapped to `criteria` by the SDK. */
1168
+ triggerType?: string;
1169
+ /** @deprecated Use `criteria.threshold`. Mapped to `criteria` by the SDK. */
1170
+ triggerThreshold?: number;
1171
+ }
1172
+ /** A reward that has been applied, from the grant history. */
1173
+ export interface RewardApplication {
1174
+ id: string;
1175
+ tenantId: string;
1176
+ userId: string;
1177
+ rewardId: string;
1178
+ /** What it was applied to (challenge / funded account / purchase). */
1179
+ appliedTo: string;
1180
+ rewardType: string;
1181
+ rewardValue: number;
1182
+ effectDescription: string | null;
1183
+ appliedAt: string;
1184
+ originalType: string;
1185
+ achievementId: string | null;
1186
+ achievementCode: string | null;
1187
+ achievementName: string | null;
1188
+ }
583
1189
  /** Self-exclusion record */
584
1190
  export interface SelfExclusionRecord {
1191
+ id: string;
1192
+ tenantId: string;
585
1193
  userId: string;
586
1194
  reason: string;
1195
+ excludedBy: string | null;
1196
+ /** ISO 8601 */
587
1197
  excludedAt: string;
1198
+ /** ISO 8601. Null = permanent. */
588
1199
  expiresAt: string | null;
589
- liftedAt: string | null;
1200
+ metadata: Record<string, unknown>;
1201
+ /** ISO 8601 */
1202
+ createdAt: string;
590
1203
  }
591
1204
  /** Standard API error response */
592
1205
  export interface FastError {
@@ -648,4 +1261,5 @@ export interface FastClientConfig {
648
1261
  */
649
1262
  dangerouslyAllowBrowser?: boolean;
650
1263
  }
1264
+ export {};
651
1265
  //# sourceMappingURL=types.d.ts.map