Frozen contract. This is the integration boundary between the NestJS backend and the Next.js frontend. TypeScript shapes live in
@casino/sharedand are the source of truth for field names/types. Backend and frontend tracks build against this document in parallel.
- Base URL:
NEXT_PUBLIC_API_URL(e.g.http://localhost:4000). - All request/response bodies are JSON.
- Money is integer minor units (LUNA: 1 = 1 coin; SWEEPS: 100 = 1.00 SC).
- Auth:
Authorization: Bearer <accessToken>on protected routes. - Validation: unknown body fields rejected (
forbidNonWhitelisted). - Timestamps: ISO‑8601 strings (UTC).
{ "statusCode": 400, "error": "Bad Request", "message": "Insufficient funds", "code": "INSUFFICIENT_FUNDS" }code is one of ErrorCode in @casino/shared. The frontend switches on code,
never on message.
Req RegisterRequest: { email, password } (email valid; password ≥ 8 chars).
On success creates user + wallet + VIP progress and grants the signup bonus
(10,000 LUNA + 2.00 SC).
Res 201 AuthResponse: { accessToken, user: UserProfile }.
Errors: VALIDATION_FAILED (400), EMAIL_TAKEN (409).
Req LoginRequest: { email, password }.
Res 200 AuthResponse.
Errors: INVALID_CREDENTIALS (401).
Res 200 UserProfile: { id, email, balances, vip, dailyStreak }.
Errors: UNAUTHORIZED (401).
Res 200 WalletResponse: { balances, recent: LedgerEntry[] } (recent = last 20, newest first).
Res 200 SlotConfig: symbols, paylines, paytable, scatterPays, betOptions per currency, targetRtp.
(Static config; safe to cache client‑side per session.)
Req SpinRequest: { currency, bet } — bet MUST be one of betOptions[currency].
Server‑authoritative: validates balance + bet, runs the provably‑fair engine,
debits wager, credits payout, awards XP, recomputes VIP — all in one DB transaction.
Res 200 SpinResult (grid, lineWins, payout, balances, xpGained, vip, tierUp, fairness proof).
Errors: INVALID_BET (400), INSUFFICIENT_FUNDS (400), RATE_LIMITED (429).
Res 200 VipStatus: { xp, tier, nextTier, xpIntoTier, xpForNextTier, progressPct, allTiers }.
Res 200 DailyBonusStatus: { claimable, nextAvailableAt, streak, previewLuna, previewSweeps }.
Claims today's bonus (idempotent per UTC day). Updates streak, credits the wallet.
Res 200 DailyBonusClaimResult: { lunaAwarded, sweepsAwarded, streak, balances }.
Errors: BONUS_ALREADY_CLAIMED (409).
Req RedemptionRequest: { sweepsAmount, method }.
Requires sweepsAmount ≥ MIN_REDEEM_SWEEPS (5000 = 50.00 SC) and
sweepsAmount ≤ balances.sweepsRedeemable. Holds the SC (debit + reduce redeemable),
creates a PENDING redemption.
Res 201 Redemption.
Errors: REDEMPTION_BELOW_MINIMUM (400), REDEMPTION_INSUFFICIENT_REDEEMABLE (400).
Res 200 Redemption[] (newest first).
Global throttle (THROTTLE_LIMIT/THROTTLE_TTL); tighter buckets on POST /auth/*
and POST /slot/spin. On limit: 429 with code: RATE_LIMITED.
Res 200 { status: "ok", db: "up" } — used by the container healthcheck.