API Reference
Every action available in the web interface is also available via the HTTP API.
The base URL is https://api.solver-arena.com. All endpoints
accept and return JSON unless otherwise noted.
Introduction
Using the API follows a simple flow. Here are the main steps:
- List available solvers with
GET /api/problems/solvers. Pass your file's extension to filter to compatible solvers only, for example?format=.mps. Note the solver IDs you want to include in your run. - Check the credit cost with
GET /api/problems/credit-cost?preset=standardbefore submitting. Thequickpreset is always free. All other presets cost 1 credit per run, regardless of file size or solver count. - Submit your problem with
POST /api/problems/submit. Upload your file as multipart form data along with the solver list and a preset. The response contains ajob_id. - Poll status with
GET /api/problems/{job_id}/statusevery 1 to 2 seconds until the state isSUCCESS,FAILURE, orINTERRUPTED. - Fetch results with
GET /api/problems/{job_id}/results. You can also call this during a run to get partial results as solvers finish. - Download a ZIP with
GET /api/problems/{job_id}/results/{solver}/downloadfor each solver. The archive contains the full solution, solver log, and the exact parameters used, suitable for archiving and reproducibility.
All benchmark submissions require authentication. Sign in at /settings to generate an API key, then include it in every request to /submit and /history.
Authentication
Two methods are accepted. The server checks them in order and uses the first that matches.
API key (recommended for scripts and automation)
- Sign in to your account and go to /settings.
- Click Generate API key. The key is shown exactly once: copy it immediately.
- Pass it as a Bearer token in the
Authorizationheader of every authenticated request.
# Authenticate with an API key
$ curl -X POST "https://api.solver-arena.com/api/problems/submit" \
-H "Authorization: Bearer sa_<your_key>" \
-F "[email protected]" \
-F 'solvers=["highs","cbc"]' \
-F "preset=standard" Session cookie (browser use)
When you sign in through the web interface, the server sets an auth_token cookie. Browsers send it automatically. For fetch calls from your own frontend,
the cookie is sufficient and no extra header is needed.
| Endpoint | Auth required |
|---|---|
POST /api/problems/submit | Yes |
GET /api/problems/history | Yes |
GET /api/problems/{job_id}/status | No |
GET /api/problems/{job_id}/results | No |
GET /api/problems/{job_id}/results/{solver}/download | No |
POST /api/problems/{job_id}/cancel | No |
| All other read endpoints | No |
Returns solvers currently installed and available. Filter by file format with the format query parameter.
| Parameter | Type | Description |
|---|---|---|
format | query, optional | File extension including dot, e.g. .mps, .lp, .nl. Omit to return all solvers. |
$ curl "https://api.solver-arena.com/api/problems/solvers?format=.mps"
{
"solvers": [
{ "id": "highs", "name": "HiGHS", "version": "1.13.1", "supported_formats": [".lp", ".mps"] },
{ "id": "cbc", "name": "CBC", "version": "2.10.11", "supported_formats": [".lp", ".mps"] },
{ "id": "glpk", "name": "GLPK", "version": "5.0", "supported_formats": [".lp", ".mps"] },
{ "id": "scip", "name": "SCIP", "version": "9.1.0", "supported_formats": [".lp", ".mps"] }
]
}Returns all available presets with labels and descriptions.
$ curl "https://api.solver-arena.com/api/problems/presets"Returns a JSON parameter template pre-filled with a preset's values for the requested
solvers. Download it, edit it, and pass it as custom_params to /submit.
| Parameter | Type | Description |
|---|---|---|
solvers | query, required | Comma-separated solver IDs, e.g. highs,cbc |
preset | query, optional | Preset to pre-fill values from. Defaults to standard. |
$ curl "https://api.solver-arena.com/api/problems/params-template?solvers=highs,cbc&preset=standard" \
-o params_template.jsonParse an optimization problem file and return model statistics and suggested solver parameters.
Stateless: nothing is written to the database. Only .lp and .mps files
are supported; .nl files return supported: false.
| Field | Type | Description |
|---|---|---|
file | form, required | Problem file to analyze (.mps or .lp), max 50 MB. |
$ curl -X POST "https://api.solver-arena.com/api/problems/analyze" \
-F "[email protected]"
{
"supported": true,
"problem_type": "MIP",
"num_variables": 240,
"num_continuous": 120,
"num_integer": 100,
"num_binary": 20,
"num_constraints": 180,
"num_nonzeros": 1440,
"sparsity": 0.9667,
"hints": ["MIP detected: SCIP or HiGHS recommended"],
"suggested_params": {
"highs": { "mip_rel_gap": 0.001 },
"scip": { "limits/gap": 0.001 }
}
}Returns the credit cost for a given run configuration before submitting. The quick preset always returns cost: 0. All other presets cost
1 credit per run, regardless of file size or solver count.
| Parameter | Type | Description |
|---|---|---|
preset | query, optional | Preset ID: quick, standard, or thorough. Defaults to standard. |
$ curl "https://api.solver-arena.com/api/problems/credit-cost?preset=standard"
{ "cost": 1, "free": false }Upload a problem file and queue it for benchmarking. Requires authentication. Returns a job_id to poll. Credits are deducted immediately for files 100 KB and above
(1 credit per solver). Returns HTTP 402 if the user does not have enough credits, and
HTTP 413 if the file exceeds 50 MB.
| Field | Type | Description |
|---|---|---|
file | form, required | Problem file (.mps, .lp, or .nl), max 50 MB. |
solvers | form, optional | JSON array of solver IDs to run, e.g. ["highs","cbc"]. Defaults to all compatible solvers. |
preset | form, optional | Preset ID. Defaults to standard. Ignored if custom_params is provided. |
custom_params | form, optional | JSON object mapping solver ID to parameter dict. Overrides preset entirely. |
# Using a preset
$ curl -X POST "https://api.solver-arena.com/api/problems/submit" \
-H "Authorization: Bearer sa_<your_key>" \
-F "[email protected]" \
-F 'solvers=["highs","cbc","scip"]' \
-F "preset=standard"
{ "job_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
# Using custom parameters
$ curl -X POST "https://api.solver-arena.com/api/problems/submit" \
-H "Authorization: Bearer sa_<your_key>" \
-F "[email protected]" \
-F 'custom_params={"highs":{"time_limit":60,"mip_rel_gap":0.01},"cbc":{"max_seconds":60}}'Poll the status of a job. Recommended polling interval: 1 to 2 seconds.
$ curl "https://api.solver-arena.com/api/problems/3fa85f64-.../status"
{ "state": "STARTED" } | State | Meaning |
|---|---|
PENDING | Job queued, not yet started |
STARTED | Solvers running |
SUCCESS | All solvers finished, fetch results |
INTERRUPTED | Job was cancelled mid-run, partial results available |
FAILURE | Job failed unexpectedly |
Retrieve results. Available as soon as at least one solver has finished: you can poll
this during STARTED state for live partial results.
$ curl "https://api.solver-arena.com/api/problems/3fa85f64-.../results"
{
"job_id": "3fa85f64-...",
"results": {
"highs": {
"status": "optimal",
"objective": 48291.4,
"wall_time": 0.312,
"iterations": 1847,
"gap": 0.0,
"error": null
},
"cbc": {
"status": "optimal",
"objective": 48291.4,
"wall_time": 2.847,
"iterations": 5102,
"gap": 0.0,
"error": null
}
}
} | Status value | Meaning |
|---|---|
optimal | Optimal solution found |
infeasible | Problem has no feasible solution |
unbounded | Objective is unbounded |
unknown | Solver stopped (time/gap limit) with a feasible point |
failed | Solver crashed or returned an error |
Download a ZIP archive for one solver containing:
results.json: objective, status, variables, constraintsmetadata.json: preset, exact solver parameters applied, timestampssolver_log.txt: raw solver output
$ curl "https://api.solver-arena.com/api/problems/3fa85f64-.../results/highs/download" \
-o highs_3fa85f64.zipCancel a running job. Solvers that have already finished retain their results.
$ curl -X POST "https://api.solver-arena.com/api/problems/3fa85f64-.../cancel"
{ "cancelled": true }Returns the authenticated user's job history, newest first, paginated. Requires authentication via API key or session cookie.
| Parameter | Type | Description |
|---|---|---|
page | query, optional | Page number, starting at 1. Defaults to 1. Page size is 20. |
$ curl "https://api.solver-arena.com/api/problems/history?page=1" \
-H "Authorization: Bearer sa_<your_key>"
{
"jobs": [
{
"id": "3fa85f64-...",
"original_filename": "problem.mps",
"status": "finished",
"preset": "standard",
"credits_used": 3,
"created_at": "2025-01-15T10:23:00",
"finished_at": "2025-01-15T10:23:45",
"solver_names": ["highs", "cbc", "scip"]
}
],
"total": 42,
"page": 1,
"page_size": 20
}Python example
A complete end-to-end script using the requests library:
import time
import requests
BASE = "https://api.solver-arena.com/api/problems"
API_KEY = "sa_<your_key>" # from /settings
session = requests.Session()
session.headers["Authorization"] = f"Bearer {API_KEY}"
# 1. Submit
with open("problem.mps", "rb") as f:
resp = session.post(
f"{BASE}/submit",
files={"file": f},
data={"solvers": '["highs","cbc","scip"]', "preset": "standard"},
)
resp.raise_for_status()
job_id = resp.json()["job_id"]
print(f"Job submitted: {job_id}")
# 2. Poll until done
while True:
state = session.get(f"{BASE}/{job_id}/status").json()["state"]
print(f" {state}")
if state in ("SUCCESS", "FAILURE", "INTERRUPTED"):
break
time.sleep(1.5)
# 3. Print results
results = session.get(f"{BASE}/{job_id}/results").json()["results"]
for solver, r in sorted(results.items(), key=lambda x: x[1]["wall_time"]):
print(f"{solver:8s} {r['status']:10s} obj={r['objective']} t={r['wall_time']:.3f}s")
# 4. Download ZIP for the fastest solver
winner = min(results, key=lambda s: results[s]["wall_time"])
zip_bytes = session.get(f"{BASE}/{job_id}/results/{winner}/download").content
with open(f"{winner}_result.zip", "wb") as f:
f.write(zip_bytes)
print(f"Downloaded {winner}_result.zip")