@fundedfast/sdk 1.5.0 → 3.0.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.
Files changed (39) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +3 -2
  3. package/dist/cjs/client.d.ts +1 -1
  4. package/dist/cjs/client.js +1 -1
  5. package/dist/cjs/index.d.ts +1 -1
  6. package/dist/cjs/index.d.ts.map +1 -1
  7. package/dist/cjs/resources/admin.d.ts +25 -6
  8. package/dist/cjs/resources/admin.d.ts.map +1 -1
  9. package/dist/cjs/resources/admin.js +28 -4
  10. package/dist/cjs/resources/admin.js.map +1 -1
  11. package/dist/cjs/resources/public.d.ts +12 -8
  12. package/dist/cjs/resources/public.d.ts.map +1 -1
  13. package/dist/cjs/resources/public.js +12 -8
  14. package/dist/cjs/resources/public.js.map +1 -1
  15. package/dist/cjs/types.d.ts +244 -84
  16. package/dist/cjs/types.d.ts.map +1 -1
  17. package/dist/cjs/webhooks.d.ts +22 -0
  18. package/dist/cjs/webhooks.d.ts.map +1 -1
  19. package/dist/cjs/webhooks.js +40 -0
  20. package/dist/cjs/webhooks.js.map +1 -1
  21. package/dist/esm/client.d.ts +1 -1
  22. package/dist/esm/client.js +1 -1
  23. package/dist/esm/index.d.ts +1 -1
  24. package/dist/esm/index.d.ts.map +1 -1
  25. package/dist/esm/resources/admin.d.ts +25 -6
  26. package/dist/esm/resources/admin.d.ts.map +1 -1
  27. package/dist/esm/resources/admin.js +28 -4
  28. package/dist/esm/resources/admin.js.map +1 -1
  29. package/dist/esm/resources/public.d.ts +12 -8
  30. package/dist/esm/resources/public.d.ts.map +1 -1
  31. package/dist/esm/resources/public.js +12 -8
  32. package/dist/esm/resources/public.js.map +1 -1
  33. package/dist/esm/types.d.ts +244 -84
  34. package/dist/esm/types.d.ts.map +1 -1
  35. package/dist/esm/webhooks.d.ts +22 -0
  36. package/dist/esm/webhooks.d.ts.map +1 -1
  37. package/dist/esm/webhooks.js +39 -0
  38. package/dist/esm/webhooks.js.map +1 -1
  39. package/package.json +1 -1
@@ -16,12 +16,22 @@ export type BetStatus = 'placed' | 'settled-won' | 'settled-lost' | 'voided';
16
16
  export type ValidationStatus = 'accepted' | 'rejected' | 'flagged';
17
17
  /** Funded account lifecycle state */
18
18
  export type FundedAccountStatus = 'active' | 'revoked' | 'closed';
19
+ /** Why a funded account is closing: its lifetime ended, or it was inactive too long. */
20
+ export type FundedClosingReason = 'expired' | 'inactivity';
19
21
  /** Webhook delivery state */
20
22
  export type WebhookDeliveryStatus = 'pending' | 'delivered' | 'failed';
21
23
  /** Tenant integration mode */
22
24
  export type IntegrationMode = 'sync' | 'async';
23
25
  /** 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' | 'payout_pending' | 'cashout_not_allowed_during_challenge'
26
+ export type RejectionCode = 'min_stake_not_met' | 'max_stake_exceeded' | 'odds_limit_exceeded' | 'min_odds_not_met' | 'max_payout_exceeded' | 'max_selections_exceeded'
27
+ /** Stake x odds above the ruleset's maxTicketPayout (stake included). */
28
+ | 'max_ticket_payout_exceeded'
29
+ /** Stake above the visible balance (ledger balance less open stake). */
30
+ | 'insufficient_balance' | 'lucky_bet_profit_limit' | 'max_drawdown_exceeded'
31
+ /** New tickets are paused by the session stop (daily drawdown). */
32
+ | 'cooldown_active' | 'payout_pending'
33
+ /** The funded account is closing (time up or inactive): no new tickets. */
34
+ | 'account_closing' | 'cashout_not_allowed_during_challenge'
25
35
  /** Settlements only. A won/lost after a different result for the same bet: held for an operator, no balance change. */
26
36
  | 'conflicting_settlement'
27
37
  /** Settlements only. Stake or odds differ from the accepted placement, or the payout exceeds stake x odds: held, no balance change. */
@@ -29,17 +39,17 @@ export type RejectionCode = 'min_stake_not_met' | 'max_stake_exceeded' | 'odds_l
29
39
  /** Settlements only. FAST never accepted this bet (rejected, or placed with no programme). Recorded, no balance change. */
30
40
  | 'no_accepted_placement'
31
41
  /** 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';
42
+ | 'program_closed'
43
+ /** The challenge or funded account names a ruleset FAST cannot load: no ticket is accepted until the operator fixes the tier. */
44
+ | 'ruleset_unavailable';
33
45
  /** Webhook event types emitted by FAST */
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';
46
+ 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.inactivity_warning' | 'funded_account.closing' | 'funded_account.closed' | 'funded_account.payout_debt' | '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';
35
47
  /** Body for POST /challenges/purchase */
36
48
  export interface PurchaseRequest {
37
49
  /** Your sportsbook user identifier */
38
50
  userId: string;
39
51
  /** UUID of the challenge tier to purchase */
40
52
  challengeTierId: string;
41
- /** ISO 8601 timestamp (defaults to server time) */
42
- timestamp?: string;
43
53
  /** Optional affiliate/referral tracking code */
44
54
  referralCode?: string;
45
55
  }
@@ -68,55 +78,94 @@ export interface BetEvent {
68
78
  }
69
79
  /** Body for POST /users/:userId/withdraw */
70
80
  export interface WithdrawRequest {
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;
81
+ /**
82
+ * Gross virtual profit to take off the balance, in whole cents, between
83
+ * `payout.minGrossAmount` and `payout.withdrawableGross`. The user is paid
84
+ * profitSplitPercent of it, rounded down to the cent. Required on every
85
+ * payout but the last allowed one (`payout.isFinal`), which always takes the
86
+ * whole gross profit: there it may be omitted.
87
+ */
88
+ grossAmount?: number;
73
89
  /** Leave the request pending for a later confirm/reject instead of executing it now. */
74
90
  deferred?: boolean;
75
91
  }
76
92
  /** Why a payout is not possible yet. Every reason that applies is listed. */
77
93
  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. */
94
+ code: 'account_not_active' | 'payout_pending' | 'max_payouts_reached' | 'no_profit' | 'below_min_payout' | 'payout_interval' | 'open_bets' | 'payout_debt' | 'profit_held' | 'first_payout_below_stake';
95
+ /**
96
+ * Whether this reason stops a request. `open_bets` on the last payout does
97
+ * not: only its execution waits. `profit_held` blocks only the last payout,
98
+ * or an account with no matured profit.
99
+ */
80
100
  blocking: boolean;
81
101
  current?: number;
82
102
  required?: number;
83
103
  missing?: number;
104
+ /** below_min_payout: the gross amount whose share reaches the minimum. */
105
+ requiredGross?: number;
84
106
  until?: string;
85
107
  }
86
108
  export interface PendingPayout {
87
109
  id: string;
110
+ /** The user's share. */
88
111
  amount: number;
89
- fromUnpaid: number;
90
- fromCycle: number;
112
+ /** Gross virtual profit the payout takes off the balance; `amount` is the user's split of it. */
113
+ grossAmount: number;
91
114
  isFinal: boolean;
92
115
  isMandatory: boolean;
93
116
  createdAt: string;
94
117
  }
95
- /** Payout state of a funded account (the per-cycle model). */
118
+ /**
119
+ * Payout state of a funded account. The user takes part of the gross virtual
120
+ * profit (virtual balance above the funded amount); their share is
121
+ * profitSplitPercent of it and exactly that gross amount leaves the balance.
122
+ * All of it is virtual until a payout executes.
123
+ */
96
124
  export interface PayoutState {
97
125
  currentBalance: number;
126
+ /** currentBalance minus the stake of open bets. */
127
+ virtualBalance: number;
98
128
  fundedAmount: number;
99
129
  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;
130
+ /** Virtual balance above the funded amount, held part included. Not money owed to anyone yet. */
131
+ grossProfit: number;
132
+ /** Part of grossProfit from wins inside the operator's settlement hold: no payout may take it yet. */
133
+ heldProfit: number;
134
+ /** When the profit held now is all free to pay out. Null when nothing is held. */
135
+ heldUntil: string | null;
136
+ /**
137
+ * Shortfall below the funded amount that a void opened after an executed
138
+ * payout, up to the gross paid out. Later profit repays it before any payout
139
+ * opens; written off if the account ends first.
140
+ */
141
+ payoutDebt: number;
142
+ /** The user's split of grossProfit. */
143
+ profitShare: number;
144
+ /** Largest share a payout may take after caps, whether or not a condition blocks it now. */
104
145
  available: number;
146
+ /** Gross amount behind `available`. */
147
+ availableGross: number;
148
+ /** Share the user can request right now: `available`, or 0 while any reason blocks. */
105
149
  withdrawableNow: number;
106
- activeDays: number;
107
- minActiveDays: number;
108
- cycleBets: number;
109
- minBets: number;
110
- conditionsMet: boolean;
150
+ /** Largest `grossAmount` a request may send right now: `availableGross`, or 0 while any reason blocks. */
151
+ withdrawableGross: number;
152
+ /** Smallest gross amount a request may take: the minimum payout grossed up, and on the first payout at least the own stake. */
153
+ minGrossAmount: number;
154
+ /** End of the account's lifetime. Null = no end. */
155
+ expiresAt: string | null;
156
+ /** Why the account is closing: no new tickets, open ones settle, then the profit left is paid in a final payout. Null while not closing. */
157
+ closingReason: FundedClosingReason | null;
111
158
  payoutCount: number;
112
159
  maxPayouts: number | null;
113
160
  remainingPayouts: number | null;
161
+ /** The last allowed payout, or any payout while the account is closing. */
114
162
  isFinal: boolean;
115
163
  minPayout: number | null;
116
164
  payoutIntervalDays: number | null;
117
165
  lastPayoutAt: string | null;
118
166
  nextPayoutAt: string | null;
119
- mandatoryPayoutThreshold: number | null;
167
+ /** Gross profit at which a payout of this gross amount is created on its own. Null = none. */
168
+ mandatoryPayoutAmount: number | null;
120
169
  totalWithdrawn: number;
121
170
  openStake: number;
122
171
  pending: PendingPayout | null;
@@ -127,9 +176,10 @@ export interface PayoutRequest {
127
176
  id: string;
128
177
  fundedAccountId: string;
129
178
  userId: string;
179
+ /** The user's share. */
130
180
  amount: number;
131
- fromUnpaid: number;
132
- fromCycle: number;
181
+ /** Gross virtual profit taken off the balance; `amount` is the user's split of it. */
182
+ grossAmount: number;
133
183
  isFinal: boolean;
134
184
  isMandatory: boolean;
135
185
  status: 'pending' | 'executed' | 'rejected';
@@ -145,6 +195,80 @@ export interface PayoutRequest {
145
195
  }
146
196
  /** A payout request as the user's own list returns it: who decided it is not included. */
147
197
  export type UserPayoutRequest = Omit<PayoutRequest, 'decidedBy'>;
198
+ /** One funded account in the operator overview. Every balance and profit figure is virtual. */
199
+ export interface FundedAccountOverview {
200
+ id: string;
201
+ userId: string;
202
+ tierName: string | null;
203
+ status: 'active' | 'closed' | 'revoked';
204
+ revocationReason: string | null;
205
+ createdAt: string;
206
+ currency: string;
207
+ fundedAmount: number;
208
+ currentBalance: number;
209
+ virtualBalance: number;
210
+ grossProfit: number;
211
+ profitSplitPercent: number;
212
+ profitShare: number;
213
+ /** Share the user could request right now, every condition met; 0 otherwise. */
214
+ withdrawableNow: number;
215
+ canRequest: boolean;
216
+ /** Payout reason codes that currently stop a request. */
217
+ blockedBy: string[];
218
+ payoutCount: number;
219
+ maxPayouts: number | null;
220
+ remainingPayouts: number | null;
221
+ totalWithdrawn: number;
222
+ mandatoryPayoutAmount: number | null;
223
+ /** End of the account's lifetime. Null = no end. */
224
+ expiresAt: string | null;
225
+ /** Why the account is closing, and once closed why it ended. Null for an account that never closed this way. */
226
+ closingReason: FundedClosingReason | null;
227
+ openBets: number;
228
+ openStake: number;
229
+ /** Potential: stake x odds of open bets. Not a liability. */
230
+ openPotentialReturn: number;
231
+ pending: PendingPayout | null;
232
+ lastRequestStatus: 'pending' | 'executed' | 'rejected' | null;
233
+ }
234
+ export interface FundedAccountsOverview {
235
+ summary: {
236
+ activeAccounts: number;
237
+ /** Shares requestable now with every condition met. */
238
+ payableNow: number;
239
+ payableAccounts: number;
240
+ virtualGrossProfit: number;
241
+ virtualProfitShare: number;
242
+ pending: {
243
+ count: number;
244
+ amount: number;
245
+ grossAmount: number;
246
+ };
247
+ executed: {
248
+ count: number;
249
+ /** Users' shares paid. */
250
+ amount: number;
251
+ grossAmount: number;
252
+ operatorShare: number;
253
+ /** Own stakes returned with first payouts. */
254
+ ownStakeReturned: number;
255
+ /** Payout bonuses the operator paid on top. */
256
+ rewardBonus: number;
257
+ /** Everything paid out: shares, returned stakes and bonuses. */
258
+ totalPaid: number;
259
+ };
260
+ rejected: {
261
+ count: number;
262
+ };
263
+ open: {
264
+ bets: number;
265
+ stake: number;
266
+ potentialReturn: number;
267
+ };
268
+ };
269
+ accounts: FundedAccountOverview[];
270
+ truncated: boolean;
271
+ }
148
272
  /** Result of confirming a payout request. */
149
273
  export interface PayoutExecution {
150
274
  payoutRequestId: string;
@@ -155,9 +279,10 @@ export interface PayoutExecution {
155
279
  /** userPayout + ownStakeReturned + rewardBonus */
156
280
  totalPayout: number;
157
281
  operatorShare: number;
282
+ /** Gross virtual profit taken off the balance (userPayout + operatorShare). */
283
+ grossAmount: number;
158
284
  newBalance: number;
159
- unpaidProfit: number;
160
- cycleClosed: boolean;
285
+ /** Share a cap kept from the last payout, which can no longer be paid. */
161
286
  forfeitedProfit: number;
162
287
  accountClosed: boolean;
163
288
  }
@@ -252,17 +377,23 @@ export interface ChallengeTier {
252
377
  profitSplitPercent: number;
253
378
  /** Min odds for bets */
254
379
  minOdds: number;
255
- /** Max odds for bets */
256
- maxOdds: number;
257
- /** Max stake as % of balance */
258
- maxStakePercent: number;
380
+ /** Max odds for bets. Null = no limit. */
381
+ maxOdds: number | null;
382
+ /** Max stake as % of balance. Null = no percentage limit. */
383
+ maxStakePercent: number | null;
384
+ /** Min stake as % of balance (the absolute minimum is 1). */
385
+ minStakePercent: number;
386
+ /** Cap on stake x odds per ticket, stake included. Null = no cap. */
387
+ maxTicketPayout: number | null;
388
+ /** Hours new tickets pause after the daily drawdown. Null = until the next local midnight. */
389
+ cooldownDurationHours: number | null;
259
390
  /** Max accumulator selections */
260
391
  maxAccumulatorSelections: number;
261
392
  /** Minimum bets to pass */
262
393
  minBetsRequired: number;
263
394
  /** Minimum active betting days */
264
395
  minActiveDays: number;
265
- /** Daily loss limit as % of balance */
396
+ /** Session stop: % fall from the day's base balance that pauses new tickets. 0 = off. */
266
397
  dailyDrawdownPercent: number;
267
398
  /** Total drawdown limit as % of starting balance */
268
399
  totalDrawdownPercent: number;
@@ -285,26 +416,24 @@ export interface ChallengeTierFull {
285
416
  fundedAccountBalance: number;
286
417
  /** Profit split in user's favor (e.g. 80 = 80%) */
287
418
  profitSplitPercent: number;
288
- /** Max payout as % of funded balance per cycle. null = no cap */
419
+ /** Max user share per payout, as % of the funded balance. null = no cap */
289
420
  payoutCapPercent: number | null;
290
- /** @deprecated Decides nothing: every payout that includes the cycle share returns the balance to the funded amount. */
291
- resetBalanceOnPayout: boolean;
292
- fundedMinActiveDays: number;
293
- fundedActiveDayPercent: number;
294
421
  /** Whether the user may take back the own stake during the funded phase. */
295
422
  fundedStakeRefundable?: boolean;
296
423
  /** Lifetime payout cap on the funded account. Null = none. */
297
424
  fundedTotalPayoutCap?: number | null;
298
- /** Accepted bets required per payout cycle. */
299
- fundedMinBets?: number;
300
425
  /** Most payouts the funded account allows. Null = no limit. */
301
426
  fundedMaxPayouts?: number | null;
302
- /** Smallest payout that may be requested. Null = none. */
427
+ /** Smallest payout, measured on the user's share. Null = none. */
303
428
  fundedMinPayout?: number | null;
304
- /** Days between payouts. Null = no interval. */
429
+ /** Days between payouts. Null = no gap. */
305
430
  fundedPayoutIntervalDays?: number | null;
306
- /** Balance at which a payout becomes mandatory. Null = never. */
307
- fundedMandatoryPayoutThreshold?: number | null;
431
+ /** Gross profit at which a payout of this gross amount is created on its own; the rest stays in play. Null = none. */
432
+ fundedMandatoryPayoutAmount?: number | null;
433
+ /** Lifetime of the funded account in days; then it closes with a final payout. Null = no end. */
434
+ fundedDurationDays?: number | null;
435
+ /** Days without activity after which the funded account closes with a final payout. Null = never. */
436
+ fundedInactivityDays?: number | null;
308
437
  /** ISO 4217 currency code */
309
438
  currency: string;
310
439
  enabled: boolean;
@@ -312,7 +441,7 @@ export interface ChallengeTierFull {
312
441
  updatedAt: string;
313
442
  }
314
443
  /** 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'>>;
444
+ export type ChallengeTierCreateRequest = Pick<ChallengeTierFull, 'name' | 'ownStake' | 'bonusAmount' | 'targetBalance' | 'durationDays' | 'challengeRulesetId' | 'fundedRulesetId' | 'fundedAccountBalance' | 'profitSplitPercent' | 'payoutCapPercent'> & Partial<Omit<ChallengeTierFull, 'id' | 'tenantId' | 'createdAt' | 'updatedAt'>>;
316
445
  /** Rules engine validation result */
317
446
  export interface ValidationResult {
318
447
  /** accepted = passes all rules, rejected = violates rules, flagged = accepted but noted */
@@ -324,29 +453,47 @@ export interface ValidationResult {
324
453
  export interface Ruleset {
325
454
  id: string;
326
455
  name: string;
327
- maxStakePercent: number;
328
- maxOdds: number;
456
+ /** Max stake as % of the reference balance. Null = no percentage limit. */
457
+ maxStakePercent: number | null;
458
+ /** Min stake as % of the reference balance (0..100). The absolute minimum stake is 1. */
459
+ minStakePercent?: number;
460
+ /** Null = no odds limit. */
461
+ maxOdds: number | null;
329
462
  minOdds: number;
330
463
  maxPayoutMultiplier: number;
331
464
  minBetsRequired: number;
332
465
  luckyBetMaxProfitPercent: number;
333
466
  luckyBetMaxOdds: number;
334
467
  minActiveDays: number;
468
+ /**
469
+ * Session stop: when the visible balance falls this % below the session
470
+ * base (the visible balance at the operator's local midnight), new tickets
471
+ * pause. 0 = off.
472
+ */
335
473
  dailyDrawdownPercent: number;
336
474
  totalDrawdownPercent: number;
475
+ /** Pause length in hours after the session stop. Null = until the next local midnight. */
337
476
  cooldownDurationHours: number | null;
477
+ /** Balance the stake percentages read, in both phases (default `current`). */
338
478
  balanceCalculationBasis?: 'original' | 'current';
339
479
  /** Max selections in an accumulator bet. 0 = no limit. */
340
480
  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';
481
+ /** Cap on stake x odds per ticket, stake included. Null = no cap. */
482
+ maxTicketPayout?: number | null;
345
483
  enabled?: boolean;
346
484
  tenantId?: string;
347
485
  createdAt?: string;
348
486
  updatedAt?: string;
349
487
  }
488
+ /**
489
+ * The session stop line: the session base (visible balance at the operator's
490
+ * local midnight, re-based when a pause ends, lowered by an executed payout)
491
+ * and the visible balance at or below which new tickets pause.
492
+ */
493
+ export interface SessionStop {
494
+ baseBalance: number;
495
+ limitBalance: number;
496
+ }
350
497
  /** Live challenge progress for sportsbook UI */
351
498
  export interface ChallengeProgress {
352
499
  type: 'challenge';
@@ -367,6 +514,12 @@ export interface ChallengeProgress {
367
514
  cooldownUntil: string | null;
368
515
  /** Total stake amount in pending (unsettled) bets */
369
516
  reserved: number;
517
+ /** Cap on stake x odds per ticket, stake included. Null = no cap. */
518
+ maxTicketPayout?: number | null;
519
+ /** Session stop line for today. Null when the daily drawdown is off. */
520
+ sessionStop?: SessionStop | null;
521
+ /** Pause length in hours. Null = until the next local midnight. */
522
+ pauseHours?: number | null;
370
523
  currency?: string;
371
524
  selfExcluded?: boolean;
372
525
  }
@@ -392,8 +545,6 @@ export interface FundedAccountProgress {
392
545
  fundedAccountId: string;
393
546
  currentBalance: number;
394
547
  fundedAmount: number;
395
- /** @deprecated Never returned by the API; always undefined. */
396
- purchasePrice?: number;
397
548
  /** Own stake the user paid to enter. */
398
549
  ownStake?: number;
399
550
  /** Operator bonus: never withdrawable. */
@@ -411,23 +562,28 @@ export interface FundedAccountProgress {
411
562
  profitSplitPercent: number;
412
563
  payoutCapPercent: number | null;
413
564
  totalWithdrawn: number;
414
- activeDays: number;
415
- minActiveDays: number;
416
565
  status: 'active' | 'closed' | 'revoked';
417
566
  reserved: number;
418
567
  /** Stake on bets not yet settled. */
419
568
  openStake?: number;
420
569
  payoutCount?: number;
421
570
  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;
571
+ /** Gross profit at which a payout is created on its own. Null = none. */
572
+ mandatoryPayoutAmount?: number | null;
573
+ /** End of the account's lifetime. Null = no end. */
574
+ expiresAt?: string | null;
575
+ /** Why the account is closing. Null while not closing. */
576
+ closingReason?: FundedClosingReason | null;
577
+ /** When inactivity would close the account if nothing happens before then. Null when not counting. */
578
+ closesAt?: string | null;
579
+ /** ISO 8601 end of the session stop pause, null when not paused. */
580
+ cooldownUntil?: string | null;
581
+ /** Session stop line for today. Null when the daily drawdown is off. */
582
+ sessionStop?: SessionStop | null;
583
+ /** Pause length in hours. Null = until the next local midnight. */
584
+ pauseHours?: number | null;
585
+ /** Cap on stake x odds per ticket, stake included. Null = no cap. */
586
+ maxTicketPayout?: number | null;
431
587
  payout?: PayoutState | null;
432
588
  /** Split points rewards added when this account opened (0 if none). */
433
589
  profitSplitRewardBoost?: number;
@@ -457,16 +613,18 @@ export interface WithdrawableInfo {
457
613
  fundedAmount: number;
458
614
  profitSplitPercent: number;
459
615
  payoutCapPercent: number | null;
460
- activeDaysCount: number;
461
- minActiveDays: number;
462
- activeDaysMet: boolean;
463
616
  payout: PayoutState;
464
617
  }
465
618
  /** Payout request result. `executed` carries the profit split breakdown. */
466
619
  export interface WithdrawalResult {
467
620
  status: 'pending' | 'executed';
468
621
  payoutRequestId: string;
622
+ /** The user's share. */
469
623
  amount: number;
624
+ /** Gross virtual profit the payout takes off the balance. */
625
+ grossAmount: number;
626
+ /** The operator's share: grossAmount minus the user's share. */
627
+ operatorShare: number;
470
628
  isFinal: boolean;
471
629
  newBalance?: number;
472
630
  userPayout?: number;
@@ -474,9 +632,7 @@ export interface WithdrawalResult {
474
632
  /** Paid on top of userPayout from payout bonus rewards. */
475
633
  rewardBonus?: number;
476
634
  totalPayout?: number;
477
- operatorShare?: number;
478
- resetApplied?: boolean;
479
- unpaidProfit?: number;
635
+ /** Share a cap kept from the last payout, which can no longer be paid. */
480
636
  forfeitedProfit?: number;
481
637
  accountClosed?: boolean;
482
638
  }
@@ -532,11 +688,12 @@ export interface SseToken {
532
688
  }
533
689
  /** The ruleset limits disclosed with a tier's terms. */
534
690
  export interface TierTermsRules {
535
- maxStakePercent: number;
691
+ maxStakePercent: number | null;
692
+ minStakePercent: number;
536
693
  minOdds: number;
537
- maxOdds: number;
694
+ maxOdds: number | null;
538
695
  maxPayoutMultiplier: number;
539
- maxWinPerTicket: number | null;
696
+ maxTicketPayout: number | null;
540
697
  minBetsRequired: number;
541
698
  minActiveDays: number;
542
699
  dailyDrawdownPercent: number;
@@ -564,8 +721,6 @@ export interface TierTerms {
564
721
  rewardAccountBalance: number;
565
722
  profitSplitPercent: number;
566
723
  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
724
  rules: TierTermsRules;
570
725
  /** Sentences to show the user before purchase, in `lang`. */
571
726
  disclosures: string[];
@@ -823,6 +978,8 @@ export interface TenantSettings {
823
978
  tenantId?: string;
824
979
  name?: string;
825
980
  environment?: string;
981
+ /** What the server API key may do: `integration` (all but /v1/admin/*) or `admin`. FAST changes it on request. */
982
+ apiKeyScope?: 'integration' | 'admin';
826
983
  integrationMode: IntegrationMode;
827
984
  webhookUrl: string | null;
828
985
  /** Single URL FAST calls before any money/irreversible action (type in payload). */
@@ -837,6 +994,8 @@ export interface TenantSettings {
837
994
  exportWebhookUrl?: string | null;
838
995
  defaultCurrency?: string;
839
996
  supportedCurrencies?: string[];
997
+ /** Operator IANA timezone (default Europe/Zagreb). Days and midnights are local to it. */
998
+ timezone?: string;
840
999
  widgetLayout?: {
841
1000
  fundedOnly: boolean;
842
1001
  history: boolean;
@@ -864,7 +1023,7 @@ export interface AdminOverview {
864
1023
  }
865
1024
  /** Bonus type */
866
1025
  export type BonusType = 'deposit_match' | 'free_bet' | 'no_deposit' | 'cashback' | 'reload';
867
- /** Bonus offer (admin). Money fields are integer cents. */
1026
+ /** Bonus offer (admin). Money fields are EUR, whole cents. */
868
1027
  export interface BonusOffer {
869
1028
  id: string;
870
1029
  tenantId?: string;
@@ -872,15 +1031,15 @@ export interface BonusOffer {
872
1031
  description: string | null;
873
1032
  bonusType: BonusType;
874
1033
  matchPercent: number | null;
875
- /** Integer cents. */
1034
+ /** EUR, whole cents. */
876
1035
  maxBonusAmount: number;
877
1036
  wageringMultiplier: number;
878
1037
  minOdds: number | null;
879
- /** Integer cents. */
1038
+ /** EUR, whole cents. */
880
1039
  maxBetFromBonus: number | null;
881
1040
  excludedMarkets: string[] | null;
882
1041
  durationDays: number;
883
- /** Integer cents. */
1042
+ /** EUR, whole cents. */
884
1043
  minQualifyingDeposit: number | null;
885
1044
  maxActivations: number | null;
886
1045
  maxPerUser: number | null;
@@ -898,7 +1057,7 @@ export interface BonusStats {
898
1057
  activeCount: number;
899
1058
  /** Percent of bonuses completed over the last 30 days. */
900
1059
  completionRate30d: number;
901
- /** Bonus balance outstanding, integer cents. */
1060
+ /** Bonus balance outstanding (EUR, whole cents). */
902
1061
  totalOutstanding: number;
903
1062
  avgProgress: number;
904
1063
  }
@@ -910,10 +1069,11 @@ export interface MissionDef {
910
1069
  description: string | null;
911
1070
  icon: string | null;
912
1071
  criteriaType: string;
1072
+ /** EUR, whole cents for total_wagered and total_wagered_window; otherwise a count. */
913
1073
  criteriaThreshold: number;
914
1074
  criteriaMeta: Record<string, unknown> | null;
915
1075
  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. */
1076
+ /** EUR, whole cents for money types (bonus credit, free bet, fixed discount...), otherwise percent, days or points. */
917
1077
  rewardValue: number;
918
1078
  rewardApplyMode: string;
919
1079
  startsAt: string;
@@ -950,7 +1110,7 @@ export interface TournamentPrize {
950
1110
  rankFrom: number;
951
1111
  rankTo: number;
952
1112
  rewardType: string;
953
- /** In cents for money types, otherwise percent, days or points. */
1113
+ /** EUR, whole cents for money types, otherwise percent, days or points. */
954
1114
  rewardValue: number;
955
1115
  }
956
1116
  /** Tournament definition (admin) */
@@ -994,7 +1154,7 @@ export interface TournamentEntry {
994
1154
  qualifyingBets: number | null;
995
1155
  rank: number | null;
996
1156
  prizeType: string | null;
997
- /** In cents for money types. */
1157
+ /** EUR, whole cents for money types. */
998
1158
  prizeValue: number | null;
999
1159
  prizeGranted: boolean | null;
1000
1160
  enteredAt: string | null;
@@ -1083,13 +1243,13 @@ export interface RewardRule {
1083
1243
  tenantId?: string;
1084
1244
  name: string;
1085
1245
  description: string | null;
1086
- /** What triggers the grant: `type` reaching `threshold` (e.g. `{ type: 'active_days', threshold: 30 }`). */
1246
+ /** What triggers the grant: `type` reaching `threshold` (e.g. `{ type: 'active_days', threshold: 30 }`). A total_wagered or total_profit threshold is EUR, whole cents. */
1087
1247
  criteria: {
1088
1248
  type: string;
1089
1249
  threshold: number;
1090
1250
  };
1091
1251
  rewardType: GrantableRewardType;
1092
- /** In EUR for money types, otherwise percent or days. Unlike missions and tournament prizes, which take cents. */
1252
+ /** EUR, whole cents for money types, otherwise percent or days. */
1093
1253
  rewardValue: number;
1094
1254
  applyMode: RewardApplyMode;
1095
1255
  maxGrantsPerUser: number;
@@ -1133,7 +1293,7 @@ export interface ThemeUpdateRequest {
1133
1293
  customCopy?: Record<string, unknown>;
1134
1294
  }
1135
1295
  /** 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';
1296
+ 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' | 'funded_account.inactivity_warning' | 'funded_account.closing' | 'funded_account.closed' | 'funded_account.payout_debt' | 'user.self_excluded' | 'user.self_exclusion_lifted';
1137
1297
  /** Body for updating notification preferences: the events to change, true to notify. */
1138
1298
  export type NotificationPreferencesUpdate = Partial<Record<NotificationPreferenceEvent, boolean>>;
1139
1299
  /** Body for excluding a user. Without expiresAt or durationDays the exclusion is permanent. */