Integrations
Client config, analytics, CTFtime, instancer, and admin bot participant routes.
Integration routes help the web app and external services coordinate with rCTF. They cover public runtime config, analytics script delivery, CTFtime handoff, per team challenge instances, and participant admin bot jobs.
The admin bot worker service routes use a separate service token and are documented in Admin.
Version choice#
Client config is available in both V1 and V2. Newer clients usually want V2 because it includes the current analytics, captcha, logo, archive, and instancer fields. The remaining integration routes are version specific.
Timeline behavior#
Instance and participant admin bot routes open after the CTF starts. Admins with challsRead can read through that start gate when they need to review challenges before the event begins.
GET Client config
GET /api/[v2,v1]/integrations/client/config
- Auth
- Public
- Gate
- None
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route provides the public runtime settings used by the web app. It includes display settings, event timing, registration state, division names, and public provider settings.
V2 includes the current captcha and analytics fields, logo URLs, archive state, and instancer availability. V1 remains available for older clients and includes the older globalSiteTag and recaptcha fields.
Response fields
meta.descriptionstringmeta.imageUrlstringhomeContentstringsponsors[].namestringsponsors[].iconstringsponsors[].descriptionstringsponsors[].urlstring | undefinedflagFormatPlaceholderstringanalytics.providerstringanalytics.publicOptionsRecord<string, string>ctfNamestringdivisionsRecord<string, string>defaultDivisionstring | null | undefinedoriginstringstartTimenumberendTimenumberuserMembersbooleanfaviconUrlstring | nulllogoLightUrlstring | nulllogoDarkUrlstring | nullemailEnabledbooleanregistrationsEnabledboolean | nullctftime.clientIdtransforminstancerEnabledbooleanisArchivedbooleancaptcha.providerstringcaptcha.publicOptionsRecord<string, string>captcha.protectedEndpointsRecord<"register" | "recover" | "setEmail" | "instancerStart" | "instancerExtend" | "avatarUpload" | "adminBotSubmit", boolean>Response fields
meta.descriptionstringmeta.imageUrlstringhomeContentstringsponsors[].namestringsponsors[].iconstringsponsors[].descriptionstringsponsors[].urlstring | undefinedglobalSiteTagstring | null | undefinedctfNamestringdivisionsRecord<string, string>defaultDivisionstring | null | undefinedoriginstringstartTimenumberendTimenumberuserMembersbooleanfaviconUrlstring | nullemailEnabledbooleanregistrationsEnabledboolean | nullctftime.clientIdtransformrecaptcha.siteKeystringrecaptcha.protectedActionsstring[]GET Analytics script
GET /api/v2/integrations/analytics/script
- Auth
- Public
- Gate
- None
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route proxies the active analytics provider script when analytics are configured. It is intentionally not part of @rctf/types, because it returns JavaScript rather than an rCTF response body.
Response#
The response body is the provider JavaScript. The API keeps the fetched script in memory for one hour.
When analytics are not configured, the route responds with 404. Upstream fetch failures respond with 502.
GET Instance status
GET /api/v2/integrations/challs/:id/instance
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route gives the authenticated team’s current instance state for a challenge. It is used to show whether the instance is stopped, starting, running, stopping, or in an error state.
When no instancer provider is configured, or when the challenge has no instancer settings, the route returns 404 badEndpoint. Provider errors return 400 badInstancerError with a provider message.
Path parameters
id requiredstringResponse fields
status"stopped" | "running" | "starting" | "stopping" | "errored"timeLeftMillisecondsnumber | nullendpoints[].kind"tcp" | "tcp-ssl" | "http" | "https"endpoints[].hoststringendpoints[].portnumberendpoints[].titlestring | undefinedendpoints are returned in the order configured for the challenge. Endpoint kinds include tcp, tcp-ssl, http, and https.
PUT Start an instance
PUT /api/v2/integrations/challs/:id/instance
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- instancerStart
- Rate limit
- No rate limit
This route asks the instancer provider to start an instance for the authenticated team. If the provider needs time to finish provisioning, the response can report starting before a later status request reports running.
Captcha is checked only when the deployment protects instancerStart.
Path parameters
id requiredstringRequest body
captchaCodestringResponse fields
status"stopped" | "running" | "starting" | "stopping" | "errored"timeLeftMillisecondsnumber | nullendpoints[].kind"tcp" | "tcp-ssl" | "http" | "https"endpoints[].hoststringendpoints[].portnumberendpoints[].titlestring | undefinedPATCH Extend an instance
PATCH /api/v2/integrations/challs/:id/instance
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- instancerExtend
- Rate limit
- No rate limit
This route asks the instancer provider to extend the authenticated team’s running instance. The returned status includes the updated remaining time when the provider reports one.
Captcha is checked only when the deployment protects instancerExtend.
Path parameters
id requiredstringRequest body
captchaCodestringResponse fields
status"stopped" | "running" | "starting" | "stopping" | "errored"timeLeftMillisecondsnumber | nullendpoints[].kind"tcp" | "tcp-ssl" | "http" | "https"endpoints[].hoststringendpoints[].portnumberendpoints[].titlestring | undefinedDELETE Stop an instance
DELETE /api/v2/integrations/challs/:id/instance
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route asks the instancer provider to stop the authenticated team’s instance. The response reports the latest state returned by the provider.
Path parameters
id requiredstringResponse fields
status"stopped" | "running" | "starting" | "stopping" | "errored"timeLeftMillisecondsnumber | nullendpoints[].kind"tcp" | "tcp-ssl" | "http" | "https"endpoints[].hoststringendpoints[].portnumberendpoints[].titlestring | undefinedGET Admin bot config
GET /api/v2/integrations/challs/:id/admin-bot/config
- Auth
- Public
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route gives participants the released admin bot challenge source and the file extension for that source. Challenge authors can use this to show the exact code participants will write against.
Path parameters
id requiredstringResponse fields
sourceCodestringfileExtensionstringPOST Submit admin bot job
POST /api/v2/integrations/challs/:id/admin-bot
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- adminBotSubmit
- Rate limit
- Burst
1, refill window10000ms per user and challenge.
This route submits an admin bot job for the authenticated team. Participants send values for the input names configured on the challenge.
Only one queued or running job is allowed per user and challenge. When the challenge depends on a running instance, the route returns 400 badInstancerState if the instance is missing, stopped, or expires before the admin bot timeout.
Path parameters
id requiredstringRequest body
inputs requiredrecordcaptchaCodestringResponse fields
jobIdstringGET Admin bot job status
GET /api/v2/integrations/challs/:id/admin-bot/status
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route gives the authenticated team’s active admin bot job for a challenge. The job field is null when there is no queued or running job.
Path parameters
id requiredstringResponse fields
job.idstringjob.status"queued" | "running" | "completed" | "failed"job.createdAtstringjob.queuePositionnumber | nulljob.logsstring | nullGET Admin bot job history
GET /api/v2/integrations/challs/:id/admin-bot/history
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route gives the retained completed and failed admin bot jobs for the authenticated team on a challenge. It is useful for showing recent submissions without including the full log body in the list.
Path parameters
id requiredstringResponse fields
jobs[].idstringjobs[].status"queued" | "running" | "completed" | "failed"jobs[].createdAtstringjobs[].hasLogsbooleanGET Admin bot job logs
GET /api/v2/integrations/challs/:id/admin-bot/jobs/:jobId/logs
- Auth
- Required
- Gate
- Started (bypass challsRead)
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This route gives the retained logs for a completed or failed admin bot job. The logs field is null when logs are not available.
Path parameters
id requiredstringjobId requiredstringResponse fields
logsstring | nullPOST CTFtime callback
POST /api/v1/integrations/ctftime/callback
- Auth
- Public
- Gate
- None
- Permissions
- No extra permissions
- Captcha
- No captcha
- Rate limit
- No rate limit
This V1 route exchanges a CTFtime OAuth code for a short lived CTFtime auth token. That token can then be used with registration, verification, login, or account linking flows.
Request body
ctftimeCode requiredstringResponse fields
ctftimeTokenstringctftimeNamestringctftimeIdtransformGET CTFtime leaderboard
GET /api/v1/integrations/ctftime/leaderboard
- Auth
- Required
- Gate
- None
- Permissions
- leaderboardRead
- Captcha
- No captcha
- Rate limit
- No rate limit
This V1 route provides the leaderboard export expected by CTFtime. It is the rare typed route that returns the body directly instead of using the rCTF response wrapper.
Response#
The response body is the raw CTFtime leaderboard.
{ "standings": [ { "pos": 1, "team": "otter-sec", "score": 1200 } ]}