Skip to content

API reference — index

Top-level navigation for the ebit-api API surface, generated against the live local stack (per CLAUDE.md, the api app on port 4000 and bo on 4003 expose Swagger).

Service map

App Local port Stack Live Swagger UI OpenAPI JSON Markdown reference
api 4000 NestJS REST + Swagger http://localhost:4000/swagger http://localhost:4000/swagger.json · openapi/api.openapi.json api.md — 277 paths, 317 operations
rt 4001 NestJS websockets (socket.io) no Swagger — websockets only n/a rt-events.md
bj 4002 NestJS blackjack server no Swagger registered ¹ n/a orphaned per project_ebit_bj_orphan.md, no public REST surface
bo 4003 NestJS backoffice http://localhost:4003/swagger http://localhost:4003/swagger.json · openapi/bo.openapi.json bo.md — 48 paths, 58 operations
speed-roulette 4004 NestJS speed-roulette server no Swagger registered ¹ n/a internal RPC only; events surface through rt

¹ Verified against the running stack: curl http://localhost:{4001,4002,4004}/swagger returned 404 for all probed paths (/swagger, /api-json, /swagger.json, /swagger-json, /api/json, /api/docs). Only apps/api/src/main.ts and apps/bo/src/main.ts import buildSwagger (@app/shared/common/utils/swagger.utils); the other apps don't.

How auth works

All authenticated endpoints accept the same JWT in two interchangeable ways:

  1. Cookie: access_token=<JWT> (HTTP-only, set by POST /auth/sign-in and POST /auth/refresh). This is what the public site (ebit-fe) uses end-to-end.
  2. Authorization header: Authorization: Bearer <JWT> (the OpenAPI bearer scheme). Easier from curl.

Refresh tokens live in the refresh_token cookie (and Redis-backed session).

Admin-fe legacy gotcha (per project_admin_fe_auth_bugs.md): the admin frontend also reads/writes jwt_access_token for back-compat. Both names exist in the wild; new code should use access_token. See auth-flow.md for the full lifecycle.

The full auth lifecycle (sign-up → sign-in → 2FA → /user/me → sign-out) is documented in auth-flow.md.

Captcha bypass (local only)

Endpoints guarded by RecaptchaGuard (apps/api/src/captcha/google/recaptcha.guard.ts) accept the literal token pass when the API was started with NODE_ENV=local:

x-captcha-token: pass

The check is at apps/api/src/captcha/google/recaptcha.service.ts:28if (isLocal && token === 'pass') return;. The bypass is silently rejected in staging/prod (isLocal is false). See docs/audits/doppler-perf-audit.md for the full call chain.

This bypass matters for POST /auth/sign-up, POST /auth/sign-in, and a handful of payment endpoints — without it, you can't reach those endpoints from k6 or curl without solving a real reCAPTCHA challenge.

Per-app references

  • api.md — public + admin REST. Grouped by Swagger tag (Authorization API, User API, Bets API, Casino API, …). Each operation includes auth requirement, request/response schema (table form), sample curl, and a Tracing context note pointing to manual spans / blind spots from docs/audits/perf-trace-coverage-audit.md.
  • bo.md — backoffice equivalent. No tracing context section (perf audit didn't cover bo).
  • rt-events.md — websockets: handshake, auth, throttle limits, server→client and client→server event catalog.
  • auth-flow.md — sequenced lifecycle, including the x-captcha-token: pass and 2FA branches.
  • README.md — "how to use these docs."

Regenerating the static reference

The local stack must be running:

# Pull fresh OpenAPI JSON
curl -s http://localhost:4000/swagger.json -o docs/api-reference/openapi/api.openapi.json
curl -s http://localhost:4003/swagger.json -o docs/api-reference/openapi/bo.openapi.json

# Re-render the Markdown
python3 docs/api-reference/_gen.py

The generator is stdlib-only — no pip install required.

Top gotchas (read before integrating)

  1. Captcha bypass is local-only and silent in prod. x-captcha-token: pass works only when NODE_ENV=local (apps/api/src/captcha/google/recaptcha.service.ts:28). k6 perf scripts that rely on it fail in staging without an alternate path — see ../audits/doppler-perf-audit.md.
  2. Two cookie names mean the same thing in admin-fe. access_token is canonical; jwt_access_token is legacy (read by the admin middleware). New code uses access_token only. See auth-flow.md.
  3. socket.io auth reads the cookie, not the header. extractSocketAuthToken order: auth.socket_token → cookie socket_token → cookie access_token. Setting Authorization: Bearer … on the upgrade request is ignored.
  4. Bet endpoints have an OTel blind spot. The BullMQ bet-settled consumer starts an orphan trace because traceparent isn't in the job data. See ../audits/perf-trace-coverage-audit.md.
  5. WS throttler default is 240/60s (not 120/60s). WS_THROTTLER_LIMIT=240, WS_THROTTLER_TTL=60000 in libs/ws-throttler/src/ws-throttler.module.ts.
  6. Authorization tag covers nine operations. Email+password sign-in plus Steam OAuth, Google OAuth, OAuth username setup, refresh, and 2FA verify all share one Swagger tag.
  7. Debug API is exposed on api. 13 mutating helpers (/debug/give-balance, /debug/reset-…). Verify the guard before relying on them in tests; they should not be reachable in production.

Notes for readers

  • The Markdown is lossy — it intentionally summarises. Live Swagger remains the source of truth for nested DTO fields, validation rules, and error response shapes.
  • Operation counts (277 paths × 317 operations) come from openapi/api.openapi.json — some paths expose multiple methods (e.g. GET/PATCH /user/me).
  • For e2e tracing demos (request → spans → Jaeger), see ../e2e-trace-demo.md.
  • Postman collection generated from this OpenAPI: ../api/. Refresh: docs/api/sync-postman.sh. API surface changelog: ../api/changelog.md.