rCTF Docs
Overview

Responses

Reference for rCTF response envelopes, common errors, response data, and shared API objects.

Response definitions are in @rctf/types under packages/types/src/responses/. Each definition records the response kind, HTTP status, message, and optional data schema. Endpoint pages show the responses that matter most for each route, while this page gives a broader lookup table.

Envelope#

Most API responses use a small JSON wrapper. When a response includes data, it looks like this:

{
"kind": "goodUserSelfData",
"message": "The user's own data was successfully retrieved.",
"data": {}
}

When there is no data, the data property is left out:

{
"kind": "goodToken",
"message": "The authorization token is valid."
}

Unknown API routes usually return 404 badEndpoint. Unexpected server errors return 500 errorInternal.

Common errors#

ResponseDataMeaning
400 badJsonNo dataThe request body was not valid JSON.
400 badBody{ reason: string }Validation did not pass for body, query, path parameters, or form data.
401 badTokenNo dataThe auth token was missing or could not be used.
403 badPermsNo dataThe authenticated team does not have the permission bits for this route.
404 badEndpointNo dataThe route is not available, or the provider behind the route is not configured.
401 badNotStartedNo dataThe CTF has not started yet for this request.
401 badEndedNo dataThe CTF has ended for this action.
403 badCaptchaNo dataV2 captcha validation did not pass.
401 badRecaptchaCodeNo dataV1 captcha validation did not pass.
429 badRateLimit{ timeLeft: number }This rate limit needs more time before another request.
500 errorInternalNo dataThe server hit an unexpected error.

Auth and account errors#

ResponseDataMeaning
400 badEmailNo dataThe email did not pass validation.
400 badNameNo dataThe team name did not pass validation.
409 badKnownEmailNo dataAnother account already uses this email.
409 badKnownNameNo dataAnother account already uses this team name.
409 badKnownCtftimeIdNo dataAnother account already uses this CTFtime ID.
404 badUnknownEmailNo dataNo account is associated with this email.
404 badUnknownUserNo dataNo user exists for that ID.
401 badTokenVerificationNo dataThe verify, team, or CTFtime auth token could not be verified.
401 badCtftimeTokenNo dataThe CTFtime auth token could not be used.
401 badCtftimeCodeNo dataThe CTFtime OAuth code could not be used.
404 badCtftimeNoExistsNo dataThe current user does not have a linked CTFtime team.
404 badEmailNoExistsNo dataThe current user does not have an email address.
403 badEmailChangeDivisionNo dataThe new email would move the account outside its current division rules.
403 badDivisionNotAllowedNo dataThe account is not allowed to use the requested division.
403 badCompetitionNotAllowedNo dataRegistration rules do not allow this account.
400 badRegistrationsDisabledNo dataRegistrations are currently disabled.
409 badTooManyMembersNo dataThe team is already at maxMembers.
409 badZeroAuthNo dataThe change would remove the final auth method from the account.
403 badUserPrivilegedNo dataThe target user has admin permissions, so this route does not modify it.

Challenge and integration errors#

ResponseDataMeaning
404 badChallengeNo dataThe challenge was not found or is not available to this route.
400 badFlagNo dataThe submitted flag was not accepted.
409 badAlreadySolvedChallengeNo dataThe team has already solved this challenge.
404 badUnknownSolveNo dataThe solve row was not found.
400 badDataUriNo dataThe V1 upload data URI could not be read.
500 badFilesUploadNo dataThe upload provider could not finish the upload.
400 badAvatarFileNo dataThe avatar file was not accepted as an image.
400 badAvatarFileSize{ maxSize: number }The avatar is larger than maxAvatarSize.
400 badModerationNotPassedNo dataAvatar moderation did not approve the image.
400 badInstancerConfig{ error: string }The instancer provider did not accept the challenge config.
400 badInstancerError{ message: string }The instancer provider returned a lifecycle error.
400 badInstancerState{ error: string }The admin bot route needs a running instance, but one was not available.
400 badAdminBotConfig{ error: string }The admin bot provider did not accept the challenge source.
404 badUnknownVerificationNo dataThe pending user verification was not found.
401 badSignatureNo dataThe dynamic-scoring webhook signature, timestamp, or challenge target was rejected. The endpoint deliberately doesn’t distinguish causes.
400 badExternalAuthRequestNo dataAn external-auth call was rejected. The same response is used for unknown client, wrong secret, wrong/expired/reused code, and mismatched redirect URI so the endpoint can’t be probed.

Success response data#

ResponseData
200 goodRegister{ authToken: string }
200 goodRegisterV2{ authToken: string, teamToken: string }
200 goodLogin{ authToken: string }
200 goodVerify{ authToken: string }
200 goodVerifyInfo{ kind: "register" | "team" | "update", email: string | null, name?: string }
200 goodTokenNo data.
200 goodVerifySentNo data.
200 goodEmailSetNo data.
200 goodEmailRemovedNo data.
200 goodCtftimeAuthSetNo data.
200 goodCtftimeRemovedNo data.
200 goodCtftimeToken{ ctftimeToken: string, ctftimeName: string, ctftimeId: string }
200 goodChallengesChallenge array. Fields depend on API version.
200 goodChallengeSolvesSolve list. Fields depend on API version.
200 goodFlagNo data.
200 goodLeaderboard{ total: number, leaderboard: LeaderboardEntry[] }
200 goodLeaderboardWithGraph{ total: number, leaderboard: LeaderboardEntryV2[], graph: LeaderboardGraphEntry[] }
200 goodLeaderboardGraph{ graph: LeaderboardGraphEntry[] }
200 goodLeaderboardChallenges{ challenges: Record<string, LeaderboardChallenge> }
200 goodUserDataPublic user profile. Fields depend on API version.
200 goodUserSelfDataAuthenticated user’s own profile. Fields depend on API version.
200 goodUserUpdate{ user: UserUpdateResult }
200 goodAvatarUpdated{ url: string | null }
200 goodMemberDataTeam member array.
200 goodMemberCreateTeam member object.
200 goodMemberDeleteNo data.
200 goodAdminChallengesAdmin challenge array. Fields depend on API version.
200 goodAdminChallengeAdmin challenge object. Fields depend on API version.
200 goodChallengeUpdateUpdated admin challenge object.
200 goodChallengeDeleteNo data.
200 goodChallengeSolveDeleteNo data.
200 goodFilesUploadUploaded file array. Fields depend on API version.
200 goodUploadsQueryUpload query result array. Fields depend on API version.
200 goodAdminUsers{ total: number, users: AdminUserListItem[] }
200 goodAdminUserAdmin user detail with solves.
200 goodAdminUserUpdateNo data.
200 goodAdminUserDeleteNo data.
200 goodCreateUserToken{ token: string }
200 goodAdminUserVerifications{ verifications: PendingUserVerification[] }
200 goodAdminUserVerificationComplete{ userId: string }
200 goodAdminUserVerificationResend{ id: string }
200 goodAdminSubmissions{ total: number, submissions: AdminSubmission[] }
200 goodAdminSettings{ overrides: AdminSettings, defaults: AdminSettings }
200 goodAdminSettingsUpdate{ overrides: AdminSettings, defaults: AdminSettings }
200 goodClientConfigClient config object. Fields depend on API version.
200 goodCtftimeLeaderboard{ standings: { pos: number, team: string, score: number }[] }
200 goodInstanceStatus{ status: InstanceStatus, timeLeftMilliseconds: number | null, endpoints: Endpoint[] | null }
200 goodInstancerSchema{ schema: Record<string, unknown>, defaults: Record<string, unknown> }
200 goodAdminBotConfig{ sourceCode: string, fileExtension: string }
200 goodAdminBotStatus{ enabled: boolean, configLanguage: string }
200 goodAdminBotJobSubmitted{ jobId: string }
200 goodAdminBotJobStatus{ job: AdminBotJobStatusResponse | null }
200 goodAdminBotJobHistory{ jobs: AdminBotJobHistoryItem[] }
200 goodAdminBotJobLogs{ logs: string | null }
200 goodAdminBotJobPull{ job: PulledAdminBotJob | null }
200 goodAdminBotChallengeSource{ sourceCode: string, configRevision: string }
200 goodAdminBotJobUpdate{ ok: boolean }
200 goodAdminBotQueueDepth{ depth: number }
200 goodDynamicScores{ inserted: number, updated: number, deleted: number }
200 goodExternalAuthClient{ id: string, name: string, redirectUri: string }
200 goodExternalAuthAuthorize{ redirectTo: string }
200 goodExternalAuthToken{ accessToken: string, tokenType: "bearer" }
200 goodAdminExternalAuthClients{ id, name, redirectUri, createdAt, createdBy }[]
200 goodAdminExternalAuthClientCreate{ id, name, redirectUri, createdAt, createdBy, secret } (secret shown once)
200 goodAdminExternalAuthClientDeleteNo data.

Shared objects#

ChallengeFileV2#

FieldType
namestring
urlstring
sizenumber | null

Endpoint#

FieldType
kind"tcp" | "tcp-ssl" | "http" | "https"
hoststring
portnumber
titlestring | undefined

InstancerConfig#

FieldType
challengeIntegrationIdstring
configRecord<string, unknown>
exposeExpose[]
timeoutMillisecondsnumber
extendableboolean | undefined

Expose#

FieldType
kind"tcp" | "tcp-ssl" | "http" | "https"
hostPrefixstring
containerNamestring
containerPortnumber
shouldDisplayboolean | undefined
titlestring | undefined

AdminBotConfig#

FieldType
codestring
inputsRecord<string, RegexRule>
revisionstring
timeoutMillisecondsnumber
requireInstancerInstancesRunningboolean | undefined

RegexRule#

FieldType
patternstring
flagsstring | undefined

Enum values#

EnumValues
InstanceStatusstopped, running, starting, stopping, errored
AdminBotJobStatusqueued, running, completed, failed
AdminTeamSortBycreatedAt, team, email, division, score, solves, status
SortOrderasc, desc
AdminTeamStatusactive, banned, admin
SubmissionKindflag, admin_bot
SubmissionSortBycreatedAt, challenge, team, ip, kind, result
SubmissionResultcorrect, incorrect, already_solved, queued, active_job, invalid_input, bad_instancer_state
SubmissionTeamStatusbanned, not_banned
ProtectedActionregister, recover, setEmail, instancerStart, instancerExtend, avatarUpload, adminBotSubmit
Esc

Start typing to search the docs.