Docs · Self-hosted track · API reference

DocsSelf-hosted track

API reference

Every endpoint a Self-hosted team can call, with its request, response and errors.

View as MarkdownThis page as plain text
llms.txtIndex of every docs page, for agents

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 URLhttps://frontieror-challenge.com/api/v1
AuthenticationAuthorization: Bearer fo_… with your personal API token. See Authentication.
FormatJSON with snake_case fields. Times are ISO 8601 in UTC.
Errors{"error": "…"}, with a message you can show as it is.
LimitsRequest 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:

client.py
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

StatusMessage
401Missing or invalid API token.
403Join or create a team first. (Only endpoints that need a team.)
500Something went wrong, try again.

Get your account

GET/meToken

Who the token belongs to, their team, the current stage and round, and the submissions left today. Use it to check a token.

Responses

200OKapplication/json
  • userobject
    • idstring
    • namestring
    • emailstring
  • teamobject · null

    null until you join or create a team.

    • idstring
    • namestring
    • trackenum

      main or self-hosted

  • stageobject · null

    The running stage, else the next one, else the last one.

    • idstring
    • namestring
    • statusenum

      upcoming, active or ended.

    • start_datestring · date-time
    • end_datestring · date-time
  • roundobject · null

    The current round of the stage: the open one, else the next one, else the last one. null if the stage has no rounds.

    • numberinteger

      1-based.

    • ofinteger

      How many rounds the stage has.

    • statusenum

      upcoming, open or closed. You can submit only while it is open.

    • start_datestring · date-time
    • end_datestring · date-time
    • self_hosted_window_sinteger · null

      How long a Self-hosted submission in this round stays open, in seconds. See Submission flow. null until the round opens.

  • submissions_left_todayinteger · null

    Resets at 00:00 UTC. null without a team or a stage.

RequestPython
me = api.get("/me").json()
print(me["team"], me["submissions_left_today"])
Response
{
  "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
}

List problems

GET/problemsToken

The 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

  • detailsflagoptional

    Add ?details=1 to include each problem's description, schemas and checker, as in Get a problem.

Responses

200OKapplication/json

An array of problems, empty before the round opens.

  • slugstring
  • namestring
  • categoryenum

    The leaderboard category: routing, production_inventory, scheduling, packing_partitioning, graph_quadratic or network_design_location

  • formulation_typeenum

    The leaderboard formulation: combinatorial, mixed_integer, quadratic, stochastic or robust_bilevel

  • objectiveenum

    minimize or maximize

RequestPython
problems = api.get("/problems").json()
slugs = [p["slug"] for p in problems]
200 OKResponse
[
  {
    "slug": "barnhart2000",
    "name": "Origin-Destination Integer Multicommodity Flow (ODIMCF)",
    "category": "network_design_location",
    "formulation_type": "combinatorial",
    "objective": "minimize"
  }
]

Get a problem

GET/problems/{slug}Token

One problem of the current stage with its statement and schemas: the content of its problem page.

Path parameters

  • slugstringrequired

Responses

200OKapplication/json
  • slugstring
  • namestring
  • categoryenum

    The leaderboard category: routing, production_inventory, scheduling, packing_partitioning, graph_quadratic or network_design_location

  • formulation_typeenum

    The leaderboard formulation: combinatorial, mixed_integer, quadratic, stochastic or robust_bilevel

  • objectiveenum

    minimize or maximize

  • descriptionstring

    The statement in Markdown, with TeX math.

  • instance_schemaobject

    An annotated example of an instance file. See Reading the schemas.

  • solution_schemaobject

    An annotated example of a solution file.

  • solution_json_schemaobject

    The solution schema as a JSON Schema, to validate solutions with any JSON Schema library. It checks the format only; feasibility is up to the checker.

  • checkerstring · null

    The source of the checker our evaluation runs, feasibility_check.py. null when the problem's checker is not published. See Checkers.

404Not found

No problem with this slug in the current stage.

RequestPython
problem = api.get("/problems/barnhart2000").json()
print(problem["solution_schema"])
Response
{
  "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": "…"
}

List public instances

GET/problems/{slug}/instancesToken

The problem's public instances, for development. Private instances are never listed.

Path parameters

  • slugstringrequired

Responses

200OKapplication/json

An array of instances, ordered by name.

  • idstring · uuid
  • namestring
  • time_limit_sinteger

    Seconds a solver gets for this instance.

404Not found

No problem with this slug in the current stage.

RequestPython
instances = api.get("/problems/barnhart2000/instances").json()
200 OKResponse
[
  { "id": "0f1e8c2a-…", "name": "tiny_instance", "time_limit_s": 60 }
]

Download a public instance

GET/problems/{slug}/instances/{id}Token

The instance file itself, in the problem's instance schema, sent as an attachment named <slug>-<name>.json.

Path parameters

Responses

200OKapplication/json

The instance file.

404Not found

This problem has no public instance with this id.

RequestPython
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

POST/self-hosted/submissionsToken · Self-hosted team

Opens 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

201Createdapplication/json
  • idstring · uuid
  • created_atstring · date-time
  • expires_atstring · date-time

    When the window closes.

  • instancesobject[]

    Every instance of the session, ordered by problem, then name.

    • idstring · uuid
    • namestring
    • problem_slugstring
    • time_limit_sinteger
    • started_atstring · date-time · null

      When you started it.

    • upload_deadlinestring · date-time · null

      Its time limit plus 60 seconds after the start.

    • submitted_atstring · date-time · null

      When its solution was uploaded.

403Forbidden

You have no team, or your team is on the Main track.

409Conflict

No round is open, the round has no Self-hosted instances yet, or your team already has an open submission: “Your team already has an open submission. Finish it before starting another.”

429Too many requests

Your team has used today's submissions: one per UTC day, 4 during the testing stage.

RequestPython
submission = api.post("/self-hosted/submissions").json()
base = f"/self-hosted/submissions/{submission['id']}"
201 CreatedResponse
{
  "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

GET/self-hosted/submissions/currentToken · Self-hosted team

Your team's open submission, to resume a session. Same fields as Open a submission, with the progress of each instance.

Responses

200OKapplication/json

The open submission.

404Not found

Your team has no open submission.

RequestPython
r = api.get("/self-hosted/submissions/current")
submission = r.json() if r.status_code == 200 else None

Start an instance

POST/self-hosted/submissions/{id}/instances/{instanceId}Token · Self-hosted team

Starts 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 · uuidrequired

    The submission.

  • instanceIdstring · uuidrequired

    From the submission's instances.

Responses

200OKapplication/json

The instance file, sent as an attachment named <slug>-<name>.json.

  • Upload-Deadlineheader · date-time

    When the solution must be uploaded by: the start plus the time limit plus 60 seconds.

404Not found

The submission or the instance does not exist, or the instance is not part of the submission.

409Conflict
  • This submission has closed.
  • The time for this instance is over.
  • Start this instance first. (A GET before the first POST.)
  • Not enough time left: the submission closes before this instance's time limit would run out.
RequestPython
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

PUT/self-hosted/submissions/{id}/instances/{instanceId}/solutionToken · Self-hosted team

Uploads 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 · uuidrequired

    The submission.

  • instanceIdstring · uuidrequired

Responses

200OKapplication/json
  • submission_closedboolean

    true when this was the last instance: the submission is closed and queued for evaluation.

400Bad request

The request body is empty.

404Not found

The submission or the instance does not exist.

409Conflict
  • The file is not valid JSON.
  • The solution must be a JSON object.
  • The solution has no numeric objective_value.
  • This submission has closed.
  • Start this instance before uploading a solution.
  • A solution for this instance has already been uploaded.
  • The upload deadline for this instance passed at time UTC.
413Payload too large

The body is larger than 4 MB.

RequestPython
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")
Response
{ "submission_closed": false }

Finish a submission

POST/self-hosted/submissions/{id}/finishToken · Self-hosted team

Closes the submission before its window runs out. Instances without a solution score 0.

Responses

200OKapplication/json
  • queuedboolean

    true when it was queued for evaluation; false when nothing was uploaded, so it is completed with a score of 0.

404Not found

The submission does not exist.

409Conflict

This submission has already closed.

RequestPython
api.post(f"{base}/finish").json()

Get a submission

GET/submissions/{id}Token · team member

One of your team's submissions with its status and results. Poll it until status is completed or failed.

Path parameters

  • idstring · uuidrequired

Responses

200OKapplication/json
  • idstring · uuid
  • trackenum

    self-hosted

  • statusenum

    started (open), pending (queued), running, completed or failed.

  • scorenumber · null

    The submission's score once completed.

  • errorstring · null

    Why a failed submission could not be evaluated.

  • created_atstring · date-time
  • updated_atstring · date-time
  • environmentnull

    Only for the Main track.

  • problemsobject[]
    • slugstring
    • namestring
    • scorenumber · null

      The problem's score.

    • instancesobject[]
      • namestring
      • setenum

        private

      • scorenumber · null
      • errorstring · null

        Why the instance scored 0, such as “No solution submitted”. null for a feasible solution.

404Not found

Your team has no submission with this id.

RequestPython
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"])