Run a whole Self-hosted session from a script. The starter repository uses these same endpoints, and that page has a complete client. To give this reference to an agent, use Copy page or the Markdown version from the menu next to the title.
Basics
| Base URL | https://frontieror-challenge.com/api/v1 |
| Authentication | Authorization: Bearer fo_… with your personal API token. See Authentication. |
| Format | JSON with snake_case fields. Times are ISO 8601 in UTC. |
| Errors | {"error": "…"}, with a message you can show as it is. |
| Limits | Request bodies up to 4 MB. Submissions count toward your team's daily limit: one per UTC day, 4 during the testing stage. |
The examples use httpx, which the starter uses too. Create the client once:
import os
import httpx
api = httpx.Client(
base_url="https://frontieror-challenge.com/api/v1",
headers={"Authorization": f"Bearer {os.environ['FRONTIEROR_TOKEN']}"},
timeout=60,
)
Errors every endpoint can return
| Status | Message |
|---|---|
| 401 | Missing or invalid API token. |
| 403 | Join or create a team first. (Only endpoints that need a team.) |
| 500 | Something went wrong, try again. |
Get your account
/ meTokenWho the token belongs to, their team, the current stage and round, and the submissions left today. Use it to check a token.
Responses
me = api.get("/me").json()
print(me["team"], me["submissions_left_today"])
{
"user": { "id": "5b0f…", "name": "Ada Lovelace", "email": "ada@example.com" },
"team": { "id": "c2a1…", "name": "Column Generators", "track": "main" },
"stage": {
"id": "91de…",
"name": "Stage 1",
"status": "active",
"start_date": "2027-01-04T05:00:00.000Z",
"end_date": "2027-02-01T05:00:00.000Z"
},
"round": {
"number": 2,
"of": 4,
"status": "open",
"start_date": "2027-01-11T05:00:00.000Z",
"end_date": "2027-01-18T05:00:00.000Z",
"self_hosted_window_s": 5100
},
"submissions_left_today": 3
}
{ "error": "Missing or invalid API token." }
List problems
/ problemsTokenThe problems of the current round, once it has opened: the ones a submission covers. Their slugs are the names your solvers go by.
Query parameters
detailsflagoptionalAdd
?details=1to include each problem's description, schemas and checker, as in Get a problem.
Responses
problems = api.get("/problems").json()
slugs = [p["slug"] for p in problems]
[
{
"slug": "barnhart2000",
"name": "Origin-Destination Integer Multicommodity Flow (ODIMCF)",
"category": "network_design_location",
"formulation_type": "combinatorial",
"objective": "minimize"
}
]
Get a problem
/ problems/ {slug}TokenOne problem of the current stage with its statement and schemas: the content of its problem page.
Path parameters
slugstringrequired
Responses
problem = api.get("/problems/barnhart2000").json()
print(problem["solution_schema"])
{
"slug": "barnhart2000",
"name": "Origin-Destination Integer Multicommodity Flow (ODIMCF)",
"category": "network_design_location",
"formulation_type": "combinatorial",
"objective": "minimize",
"description": "…",
"instance_schema": { "network": { … }, "commodities": { … } },
"solution_schema": {
"objective_value": "<float> Total cost of rejected commodities across the entire routing plan.",
"commodities": [ … ]
},
"checker": "…"
}
{ "error": "No problem with this slug in the current stage." }
List public instances
/ problems/ {slug}/ instancesTokenThe problem's public instances, for development. Private instances are never listed.
Path parameters
slugstringrequired
Responses
instances = api.get("/problems/barnhart2000/instances").json()
[
{ "id": "0f1e8c2a-…", "name": "tiny_instance", "time_limit_s": 60 }
]
Download a public instance
/ problems/ {slug}/ instances/ {id}TokenThe instance file itself, in the problem's instance schema, sent as an attachment named <slug>-<name>.json.
Path parameters
slugstringrequiredidstring · uuidrequiredFrom List public instances.
Responses
from pathlib import Path
for instance in instances:
data = api.get(f"/problems/barnhart2000/instances/{instance['id']}").content
Path(f"{instance['name']}.json").write_bytes(data)
Open a submission
/ self-hosted/ submissionsToken · Self-hosted teamOpens a submission and starts its window, which is sized to the round's instances. See Submission flow. It uses one of the day's submissions. There is no request body.
Responses
submission = api.post("/self-hosted/submissions").json()
base = f"/self-hosted/submissions/{submission['id']}"
{
"id": "7a1c0e52-…",
"created_at": "2027-01-13T09:00:00.000Z",
"expires_at": "2027-01-13T10:00:00.000Z",
"instances": [
{
"id": "c4d9…",
"name": "large_instance_2",
"problem_slug": "barnhart2000",
"time_limit_s": 60,
"started_at": null,
"upload_deadline": null,
"submitted_at": null
}
]
}
Get the open submission
/ self-hosted/ submissions/ currentToken · Self-hosted teamYour team's open submission, to resume a session. Same fields as Open a submission, with the progress of each instance.
Responses
r = api.get("/self-hosted/submissions/current")
submission = r.json() if r.status_code == 200 else None
Start an instance
/ self-hosted/ submissions/ {id}/ instances/ {instanceId}Token · Self-hosted teamStarts the instance's clock on the first call and returns the instance file. Later calls, and GET on the same path, download it again until its deadline.
Path parameters
idstring · uuidrequiredThe submission.
instanceIdstring · uuidrequiredFrom the submission's
instances.
Responses
from datetime import datetime
r = api.post(f"{base}/instances/{instance_id}")
instance = r.json()
deadline = datetime.fromisoformat(r.headers["Upload-Deadline"])
Upload a solution
/ self-hosted/ submissions/ {id}/ instances/ {instanceId}/ solutionToken · Self-hosted teamUploads the instance's solution, once, before its deadline. The body is the solution file itself, at most 4 MB. See Submission format.
Path parameters
idstring · uuidrequiredThe submission.
instanceIdstring · uuidrequired
Responses
r = api.put(f"{base}/instances/{instance_id}/solution", json=solution)
if r.is_error:
print(r.json()["error"])
elif r.json()["submission_closed"]:
print("All instances uploaded")
{ "submission_closed": false }
{ "error": "A solution for this instance has already been uploaded." }
Finish a submission
/ self-hosted/ submissions/ {id}/ finishToken · Self-hosted teamCloses the submission before its window runs out. Instances without a solution score 0.
Responses
api.post(f"{base}/finish").json()
Get a submission
/ submissions/ {id}Token · team memberOne of your team's submissions with its status and results. Poll it until status is completed or failed.
Path parameters
idstring · uuidrequired
Responses
import time
while True:
s = api.get(f"/submissions/{submission['id']}").json()
if s["status"] in ("completed", "failed"):
break
time.sleep(10)
print(s["score"])