rCTF Docs
Overview

API reference

Reference for rCTF API versions, authentication, envelopes, permissions, rate limits, and typed route definitions.

The rCTF API is a JSON REST API served from /api. Route definitions are exported from the @rctf/types package, and the API server registers each route by prefixing the typed path with /api.

Versions#

Both API versions are available at the same time:

VersionPrefixStatusUse
V1/api/v1SupportedLegacy clients and compatibility with the original rCTF API.
V2/api/v2RecommendedNew integrations, richer response data, runtime settings, avatars, instancers, admin bot jobs, and admin search APIs.

The two versions overlap rather than forming separate complete APIs. Use V2 where a V2 route exists, and fall back to V1 routes for actions that don’t have V2 replacements. Many V2 routes share the same response kind string as their V1 equivalents, but the data payload is often wider in V2 (avatars, country codes, blood index, and similar additions).

Typed route contract#

The @rctf/types package exports every public route definition, response definition, enum, and helper type:

import {
GetChallengesRouteV2,
type RouteBodyInput,
type RouteQueryInput,
type RouteSuccessResponse,
} from '@rctf/types'
type Query = RouteQueryInput<typeof GetChallengesRouteV2>
type Response = RouteSuccessResponse<typeof GetChallengesRouteV2>

RouteBodyInput<T> describes the client-side input shape before any zod coercions and transforms have run. The matching RouteQueryInput<T> and RouteParamsInput<T> helpers do the same for query strings and path parameters.

Authentication#

User-authenticated routes require an auth token in the Authorization header:

Authorization: Bearer <auth-token>

Service-authenticated admin bot routes also use the Authorization header, but the token here is the shared admin bot service secret from adminBot.provider.options.secretKey.

Auth modeBehavior
PublicNo token is required. Some public routes still accept optional auth so admins can bypass start-time gates.
OptionalThe route works without a token, but an auth token may affect the response.
RequiredA missing or invalid token returns 401 badToken.
PermissionedThe user token must be valid and the user must have every required permission bit. Missing bits return 403 badPerms.
ServiceThe shared service bearer token must match the configured provider secret.

Token types#

TokenLifetimeUsed by
AuthNo expiryAuthorization: Bearer <auth-token> on user routes.
TeamNo expiryAccount recovery and v1 login. V2 registration returns it directly when registration completes without email verification.
VerifyloginTimeoutEmail update verification.
CTFtime authloginTimeoutCTFtime registration and login handoff.

Tokens are encrypted with AES-GCM using the configured tokenKey. Changing tokenKey invalidates every token that was issued before the rotation.

Response envelope#

Most API routes return a JSON envelope:

{
"kind": "goodChallenges",
"message": "The retrieval of challenges was successful.",
"data": []
}

Routes whose response definition has no data schema omit the data field:

{
"kind": "goodFlag",
"message": "The flag is correct."
}

The v1 CTFtime leaderboard route is the only typed route that intentionally returns the data body directly. GET /api/v1/integrations/ctftime/leaderboard returns { "standings": [...] } rather than an rCTF envelope.

Request validation#

JSON routes parse the request body as JSON when a body schema exists. Form routes parse multipart/form-data. Validation failures return 400 badBody with a machine-readable reason string:

{
"kind": "badBody",
"message": "The request body does not meet requirements.",
"data": {
"reason": "query:limit: Too small: expected number to be >=1"
}
}

The reason prefix identifies the source as body, query, or params. Malformed JSON returns 400 badJson. Malformed form data returns 400 badBody with body:formData:malformed.

Permissions#

Admin routes use bitmask permissions from Permissions:

PermissionBitRoutes
challsRead1Admin challenge reads, instancer schema, admin bot status, challenge start-time bypass.
challsWrite2Challenge updates, challenge deletion in v1, file upload.
leaderboardRead4CTFtime leaderboard and leaderboard start-time bypass.
challsSolveWrite8Solve deletion.
usersWrite16Admin user lists, user mutation, pending verification management, submission audit logs.
settingsWrite32Runtime settings reads and updates.

When a route lists multiple permission bits, the user needs all of them.

Timing gates#

Routes marked as start-gated return 401 badNotStarted before startTime. Admin users can bypass that gate when the route defines a bypass permission and their token has the required bit.

POST /api/v1/challs/:id/submit is also end-gated, returning 401 badEnded after endTime.

Captcha#

Captcha-protected routes only validate a challenge response when the configured captcha provider marks that action as protected. V1 request bodies use recaptchaCode, and V2 request bodies use captchaCode.

ActionRoutes
registerPOST /api/v1/auth/register, POST /api/v2/auth/register.
recoverPOST /api/v1/auth/recover, POST /api/v2/auth/recover.
setEmailPUT /api/v1/users/me/auth/email, PUT /api/v2/users/me/auth/email.
avatarUploadPATCH /api/v2/users/me/avatar.
instancerStartPUT /api/v2/integrations/challs/:id/instance.
instancerExtendPATCH /api/v2/integrations/challs/:id/instance.
adminBotSubmitPOST /api/v2/integrations/challs/:id/admin-bot.

Rate limits#

Rate-limited routes return 429 badRateLimit with data.timeLeft, measured in milliseconds:

ActionScopeBucket
Flag submissionUser and challengeBurst 5, refill window 25000 ms.
Profile name updateUserBurst 3, refill window 180000 ms.
Avatar uploadUserBurst 2, refill window 120000 ms.
Admin bot submissionUser and challengeBurst 1, refill window 10000 ms.
Leaderboard searchIP addressBurst 3, refill window 3000 ms.

Route sections#

SectionScope
AuthenticationRegistration, verification, recovery, login, and token validation across V2 and V1 route contracts.
ChallengesPublic challenge listing, solves, v1 flag submission, and the dynamic-scoring webhook.
LeaderboardCurrent standings, graph data, challenge leaderboard metadata, search, and pagination.
UsersPublic profiles, self profile, updates, avatar upload, email/CTFtime auth, and team members.
AdminChallenge management, users, verification queue, submissions, uploads, settings, admin bot service routes, and external-auth clients.
IntegrationsClient config, analytics script proxy, CTFtime, instancers, and participant admin bot routes.
External auth”Sign in with rCTF” flow for external services - client lookup, consent, and token exchange.
ResponsesShared response kinds, error payloads, and common object models.
Esc

Start typing to search the docs.