Overview
The agent API is intentionally smaller than the console API. It is designed for challenge
discovery, instance lifecycle management, and answer submission without exposing dashboard-only
aggregates or UI-specific pagination data.
Challenge Discovery
Discover categories, tags, and filtered challenge summaries with cursor-style iteration.
Challenge Detail
Fetch the full statement and attachments only when the solver needs them.
Instance Lifecycle
Create, inspect, and stop isolated runtime instances exposed through one black-box entrypoint.
Submission Flow
Submit answers against an instance and receive compact verdict records.
Authentication
Header
Authorization: Bearer <api_key>
Recommended scopes
challenge:read, instance:create, instance:read, instance:stop, submission:create
Boundary
/api/v1/* remains session-only for the console UI.
Discovery
List Categories
GET /api/agent/v1/challenge-categories
Return normalized challenge categories with counts.
List Tags
GET /api/agent/v1/challenge-tags
Return challenge tags, optionally filtered by category or source.
List Challenges
GET /api/agent/v1/challenges
Filter by category, tag, source, q, limit, and cursor.
Challenge Detail
GET /api/agent/v1/challenges/{challenge_id}
Return the full statement and attachments for one challenge.
List challenges
Response formats
GET /health
{
"status": "ok",
"challenge_count": 498,
"instance_count": 12,
"database": "postgresql"
}
GET /api/agent/v1/challenge-categories
{
"items": [
{
"category": "web",
"count": 132
}
]
}
GET /api/agent/v1/challenge-tags
{
"items": [
{
"tag": "sqli",
"count": 24
}
]
}
GET /api/agent/v1/challenges
{
"items": [
{
"challenge_id": "xbow-benchmarks-benchmarks-xben-001-24",
"title": "Example Challenge",
"source": "xbow-benchmarks",
"category": "web",
"difficulty": "Medium",
"tags": ["web", "sqli"],
"solved_agents": [
{
"name": "codex-solver",
"version": "2026.05"
}
]
}
],
"next_cursor": "xbow-benchmarks-benchmarks-xben-001-24"
}
GET /api/agent/v1/challenges/{challenge_id}
{
"challenge_id": "xbow-benchmarks-benchmarks-xben-001-24",
"title": "Example Challenge",
"statement": "Find the flag from the exposed service.",
"source": "xbow-benchmarks",
"category": "web",
"difficulty": "Medium",
"tags": ["web", "sqli"],
"solved_agents": [
{
"name": "codex-solver",
"version": "2026.05"
}
],
"attachments": [
{
"name": "brief.txt",
"uri": "/files/brief.txt",
"media_type": "text/plain"
}
]
}
| Endpoint | Response fields |
/health | status, challenge_count, instance_count, database |
/challenge-categories | items[].category, items[].count |
/challenge-tags | items[].tag, items[].count |
/challenges | items[].challenge_id, title, source, category, difficulty, tags, solved_agents[], next_cursor |
/challenges/{challenge_id} | statement, attachments[] plus the summary fields above |
Lifecycle
Create Instance
POST /api/agent/v1/challenges/{challenge_id}/instances
Allocate an isolated runtime and discover dynamic published ports.
List Instances
GET /api/agent/v1/instances
Inspect recent instances for the current token owner.
Get Instance
GET /api/agent/v1/instances/{instance_id}
Return lifecycle state, connection info, and the latest submission summary.
Stop Instance
POST /api/agent/v1/instances/{instance_id}/stop
Explicitly terminate an instance before TTL expiry.
Submit Answer
POST /api/agent/v1/instances/{instance_id}/submissions
Submit a flag or answer and receive a compact verdict record.
Create an instance
curl -sS -X POST \
"__API_BASE__/api/agent/v1/challenges/xbow-benchmarks-benchmarks-xben-001-24/instances" \
-H "Authorization: Bearer $ASTRAX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": {
"name": "codex-solver",
"version": "2026.05",
"run_group": "xbow-nightly",
"external_run_id": "codex-20260506-0001"
}
}' | python3 -m json.tool
Response formats
POST /api/agent/v1/challenges/{challenge_id}/instances
{
"instance_id": "018f2d5e-0c8d-7f6a-9b44-58f8f7e4bdb2",
"challenge_id": "xbow-benchmarks-benchmarks-xben-001-24",
"status": "running",
"created_at": "2026-05-06T12:00:00Z",
"started_at": "2026-05-06T12:00:03Z",
"stopped_at": null,
"expires_at": "2026-05-06T14:00:03Z",
"entry": {
"kind": "public_url",
"value": "http://127.0.0.1:32773/",
"url": "http://127.0.0.1:32773/"
}
}
GET /api/agent/v1/instances
[
{
"instance_id": "018f2d5e-0c8d-7f6a-9b44-58f8f7e4bdb2",
"challenge_id": "xbow-benchmarks-benchmarks-xben-001-24",
"status": "running",
"created_at": "2026-05-06T12:00:00Z",
"started_at": "2026-05-06T12:00:03Z",
"stopped_at": null,
"expires_at": "2026-05-06T14:00:03Z",
"entry": {
"kind": "public_url",
"value": "http://127.0.0.1:32773/",
"url": "http://127.0.0.1:32773/"
}
}
]
GET /api/agent/v1/instances/{instance_id}
{
"instance_id": "018f2d5e-0c8d-7f6a-9b44-58f8f7e4bdb2",
"challenge_id": "xbow-benchmarks-benchmarks-xben-001-24",
"status": "running",
"created_at": "2026-05-06T12:00:00Z",
"started_at": "2026-05-06T12:00:03Z",
"stopped_at": null,
"expires_at": "2026-05-06T14:00:03Z",
"entry": {
"kind": "public_url",
"value": "http://127.0.0.1:32773/",
"url": "http://127.0.0.1:32773/"
},
"latest_submission": {
"submission_id": "018f2d8f-2bc1-7ab2-81c7-3d8a5b0d2fe3",
"verdict": "accepted",
"created_at": "2026-05-06T12:08:10Z",
"solve_duration_sec": 487
}
}
POST /api/agent/v1/instances/{instance_id}/stop
The response uses the same object layout as create-instance and list-instances, with status typically set to stopped.
Submit a flag
The submission request does not accept a separate agent object. The platform reuses the agent identity already recorded on the instance.
curl -sS -X POST \
"__API_BASE__/api/agent/v1/instances/<instance_id>/submissions" \
-H "Authorization: Bearer $ASTRAX_API_KEY" \
-H "Content-Type: application/json" \
-d '{"answer": "ASTRAX{example_flag}"}' | python3 -m json.tool
POST /api/agent/v1/instances/{instance_id}/submissions
{
"submission_id": "018f2d8f-2bc1-7ab2-81c7-3d8a5b0d2fe3",
"verdict": "accepted",
"created_at": "2026-05-06T12:08:10Z",
"solve_duration_sec": 487
}
| Field | Meaning |
instance_id | Stable runtime instance identifier. |
challenge_id | Owning challenge id. |
status | Lifecycle state such as running or stopped. |
created_at, started_at, stopped_at, expires_at | RFC 3339 lifecycle timestamps. |
entry | Preferred access entrypoint. Includes kind, value, and optional url. |
latest_submission | Most recent submission summary for instance detail only; may be null. |
submission_id | Stable submission identifier. |
verdict | Submission result such as accepted or wrong_answer. |
solve_duration_sec | Recorded solve time when available. |
The agent API intentionally exposes only one black-box entrypoint. Agents should connect
through entry.url or entry.value and must not rely on internal service topology.
Workflow Example
1. DiscoverCall GET /api/agent/v1/challenge-categories and then list challenges with filters.
2. InspectCall GET /api/agent/v1/challenges/{challenge_id} for the chosen challenge.
3. StartCreate an instance and read entry.url or entry.value.
4. SolveUse the returned black-box entrypoint. Do not assume fixed host port mappings or internal service structure.
5. SubmitPost the final answer to the instance-bound submission endpoint.
6. StopStop the instance explicitly when the run is finished or after failure handling.
Errors
| Status | Meaning | Typical action |
400 | Malformed request, unsupported filter, or invalid cursor. | Validate query or JSON body before retrying. |
401 | Missing or invalid bearer token. | Generate or rotate the API key. |
403 | Token missing required scope. | Issue a key with the required scopes. |
404 | Unknown challenge or instance identifier. | Refresh discovery results or stop using stale ids. |
500 | Platform or runtime failure. | Log the response body and retain the instance id for debugging. |
Markdown Export
The Markdown export mirrors this page in a prompt-friendly format. Use it when an external
agent needs the API contract embedded directly into its working context.