Skip to content

Latest commit

 

History

History
112 lines (78 loc) · 3.71 KB

File metadata and controls

112 lines (78 loc) · 3.71 KB

API Contract — Lunaland Casino (v1)

Frozen contract. This is the integration boundary between the NestJS backend and the Next.js frontend. TypeScript shapes live in @casino/shared and are the source of truth for field names/types. Backend and frontend tracks build against this document in parallel.

Conventions

  • 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).

Error envelope (every non‑2xx)

{ "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.


Auth

POST /auth/register — public

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).

POST /auth/login — public

Req LoginRequest: { email, password }. Res 200 AuthResponse. Errors: INVALID_CREDENTIALS (401).

GET /auth/me — protected

Res 200 UserProfile: { id, email, balances, vip, dailyStreak }. Errors: UNAUTHORIZED (401).


Wallet

GET /wallet — protected

Res 200 WalletResponse: { balances, recent: LedgerEntry[] } (recent = last 20, newest first).


Slot

GET /slot/config — protected

Res 200 SlotConfig: symbols, paylines, paytable, scatterPays, betOptions per currency, targetRtp. (Static config; safe to cache client‑side per session.)

POST /slot/spin — protected

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).


VIP

GET /vip — protected

Res 200 VipStatus: { xp, tier, nextTier, xpIntoTier, xpForNextTier, progressPct, allTiers }.


Daily bonus

GET /bonus/daily — protected

Res 200 DailyBonusStatus: { claimable, nextAvailableAt, streak, previewLuna, previewSweeps }.

POST /bonus/daily/claim — protected

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).


Redemption

POST /redemptions — protected

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).

GET /redemptions — protected

Res 200 Redemption[] (newest first).


Rate limiting

Global throttle (THROTTLE_LIMIT/THROTTLE_TTL); tighter buckets on POST /auth/* and POST /slot/spin. On limit: 429 with code: RATE_LIMITED.

Health

GET /health — public

Res 200 { status: "ok", db: "up" } — used by the container healthcheck.