Authentication
All API requests must include an API key in the Authorization header:
Authorization: Bearer rl_<your-key>
API keys are created and managed by admins at /admin/api-keys. Each key has one or more scopes that restrict what it can access. Keys are hashed server-side and shown only once at creation.
Scopes
| Scope | Access granted |
|---|---|
machines | Read machine list, individual machine details, and health status |
challenges | Read challenge metadata (id, name, difficulty) |
test-results | Read lab health check results for all machines |
users | Read user list with points and credit totals (no sensitive data) |
messaging | Send broadcast messages and direct messages to users |
Errors
All errors return JSON with an error field:
{ "error": "Missing Authorization: Bearer <key>" }
| Status | Meaning |
|---|---|
401 | Missing or invalid API key |
403 | Key does not have the required scope |
404 | Resource not found |
400 | Bad request — missing required fields |
Machines
Requires scope: machines
/api/v1/machines
Returns all machines with health status.
Example response
[
{
"id": "http-lab",
"name": "Bastion",
"difficulty": "Easy",
"difficultyRating": 1,
"ports": [{ "service": "HTTP", "port": 80 }],
"ipAddress": "45.56.112.197",
"active": true,
"isTimed": false,
"launchAt": null,
"health": {
"online": true,
"latencyMs": 12,
"checkedAt": "2026-05-07T20:00:00.000Z"
}
}
]
/api/v1/machines/:id
Returns a single machine by its id slug.
GET /api/v1/machines/hexvault-lab
Challenges
Requires scope: challenges
/api/v1/challenges
Lightweight list of all challenges (id, name, difficulty, active status). Alias for machines with reduced fields.
Example response
[
{ "id": "http-lab", "name": "Bastion", "difficulty": "Easy", "difficultyRating": 1, "active": true }
]
Test Results
Requires scope: test-results
/api/v1/test-results
Returns the latest health check result for every lab, sorted newest first.
Example response
[
{
"challengeId": "http-lab",
"online": true,
"latencyMs": 8,
"port": 80,
"errorMsg": null,
"checkedAt": "2026-05-07T21:00:00.000Z"
}
]
/api/v1/test-results/:id
Returns the health record for a single machine by its id slug.
GET /api/v1/test-results/hexvault-lab
Users
Requires scope: users
/api/v1/users
Returns all users with public stats. No passwords, tokens, or emails are ever exposed.
Example response
[
{
"id": "abc123",
"username": "xssrat",
"isPremium": true,
"credits": 850,
"totalPoints": 850,
"joinedAt": "2025-01-15T10:00:00.000Z"
}
]
Messaging
Requires scope: messaging
/api/v1/messaging/broadcast
Sends a broadcast message to all users' inboxes.
Request body (JSON)
{
"subject": "Points have been updated",
"body": "We've retroactively applied difficulty multipliers to all submissions..."
}
Example response 201
{
"id": "abc123",
"subject": "Points have been updated",
"body": "We've retroactively applied ...",
"createdAt": "2026-05-07T20:30:00.000Z"
}
/api/v1/messaging/dm
Sends a direct message to a specific user.
Request body (JSON)
{
"username": "xssrat",
"subject": "Your points were adjusted",
"body": "Hi! Your submission points have been updated..."
}
Example response 201
{
"id": "xyz789",
"toUsername": "xssrat",
"subject": "Your points were adjusted",
"createdAt": "2026-05-07T20:30:00.000Z"
}
curl examples
# Broadcast
curl -X POST https://ratctf.thexssrat.com/api/v1/messaging/broadcast \
-H "Authorization: Bearer rl_your_key_here" \
-H "Content-Type: application/json" \
-d '{"subject":"Points updated","body":"Difficulty multipliers have been applied retroactively to all flag submissions. Your point totals may have changed."}'
# DM a specific user
curl -X POST https://ratctf.thexssrat.com/api/v1/messaging/dm \
-H "Authorization: Bearer rl_your_key_here" \
-H "Content-Type: application/json" \
-d '{"username":"xssrat","subject":"Your points were adjusted","body":"Hi! ..."}'