Ceris

One curl, no account.

POST an optimization model, get a JSON solution back. No API key, no signup, no SDK required.

01Quick
start

Send a model.

curl -X POST https://api.ceris.fyi/v1/solve \
  -F [email protected]
Upload a .lp or .mps file
curl -X POST https://api.ceris.fyi/v1/solve \
  -H "Content-Type: application/json" \
  -d '{"model": "Maximize\n obj: 3 x + 2 y\nSubject To\n c1: x + y <= 4\nEnd\n", "format": "lp"}'
Or send the model text as JSON

Or paste a model in your browser — same endpoint.

02Python
pip install ceris

import ceris
result = ceris.solve("model.lp")   # or pass LP text directly
print(result.status)               # "optimal"
print(result.objective_value)
print(result.solution)             # {"x": 4.0, "y": 0.0}
pip install ceris
03Response

Every solve returns this envelope.

{
  "computation_id": "ceris_29f8a3b1",
  "status": "optimal",              // optimal | infeasible | unbounded
                                    // | time_limit | model_error
  "objective_value": 146.0,
  "solution": { "x1": 1.0, "x2": 0.0 },
  "solve_time_ms": 32,
  "solver": { "name": "highs", "version": "1.12.0" },
  "limits": { "time_limit_s": 60, "hit_limit": false },
  "audit": {
    "input_sha256": "a1b2c3...",    // sha256 of the raw model bytes
    "output_sha256": "d4e5f6...",   // sha256 of canonical JSON of
                                    // {status, objective_value, solution, solver}
                                    // (keys sorted, no whitespace)
    "timestamp": "2026-08-18T14:23:01Z",
    "signature": {                  // Ed25519 over the canonical JSON of
      "algorithm": "ed25519",       // {computation_id, input_sha256,
      "key_id": "2026-08-k1",       //  output_sha256, solver_version,
      "value": "9f31c2...",         //  timestamp}
      "public_key_url": "https://ceris.fyi/.well-known/ceris-signing-key"
    }
  }
}
Response contract

Verify a receipt without trusting Ceris: recompute the two hashes from your copy of the model and result, then check the Ed25519 signature against the published public key. Ceris never stores your model — you hold the evidence, the signature holds the attestation.

04When it
doesn’t solve

Errors tell you where to look.

Infeasible models come back with the conflicting constraints named (HiGHS IIS):

{
  "status": "infeasible",
  "iis": {
    "constraints": ["c_low", "c_high"],
    "variable_bounds": [],
    "message": "Constraints 'c_low' and 'c_high' cannot all be satisfied together."
  },
  ...
}
Infeasible — conflict analysis included

Models that fail to parse return HTTP 422 with a best-effort location:

{
  "status": "model_error",          // returned with HTTP 422
  "error": {
    "message": "Parser error reading model. First suspicious content at line 4: \"c1: x >= @@ 4\"",
    "line": 4                       // best-effort; null when we can't localize it
  },
  ...
}
Parse error — line number when we can find one
05Limits
Solver         HiGHS (LP + MIP). More solvers coming.
Time limit     60 seconds per solve, enforced in the solver
Model size     100,000 non-zeros max
Request size   5 MB max
Rate limit     ~10 solves per minute per IP
Formats        LP and MPS (file upload or JSON text)
Price          Free while in beta
v1 limits, stated plainly
06Example
models

Three models to start from.

\ Diet: minimize cost meeting nutrition minimums
Minimize
 cost: 2.5 bread + 4 milk + 8 cheese + 6 potato
Subject To
 calories: 90 bread + 120 milk + 100 cheese + 150 potato >= 2000
 protein: 4 bread + 8 milk + 7 cheese + 2 potato >= 55
 calcium: 15 bread + 300 milk + 200 cheese + 10 potato >= 800
Bounds
 bread <= 10
 milk <= 8
 cheese <= 4
 potato <= 8
End
Diet LPCheapest food mix that meets nutrition minimums
\ 0/1 knapsack: pick items maximizing value, weight <= 15
Maximize
 value: 10 tent + 7 stove + 5 water + 4 rope + 3 map
Subject To
 weight: 9 tent + 6 stove + 4 water + 3 rope + 1 map <= 15
Binary
 tent stove water rope map
End
Knapsack MIPPack the most valuable gear under a 15 kg limit
\ Assignment: 3 workers x 3 tasks, minimize total cost
Minimize
 cost: 4 a_cut + 2 a_weld + 8 a_paint + 6 b_cut + 3 b_weld + 7 b_paint + 5 c_cut + 9 c_weld + 4 c_paint
Subject To
 worker_a: a_cut + a_weld + a_paint = 1
 worker_b: b_cut + b_weld + b_paint = 1
 worker_c: c_cut + c_weld + c_paint = 1
 task_cut: a_cut + b_cut + c_cut = 1
 task_weld: a_weld + b_weld + c_weld = 1
 task_paint: a_paint + b_paint + c_paint = 1
Binary
 a_cut a_weld a_paint b_cut b_weld b_paint c_cut c_weld c_paint
End
AssignmentMatch 3 workers to 3 tasks at minimum cost
07Not
yet

What this doesn’t do yet.

No auth, accounts, or saved jobs — every solve is stateless and anonymous.

No async jobs or webhooks — models needing more than 60 seconds will time out.

No Gurobi, CPLEX, or OR-Tools yet — HiGHS only. Commercial solvers are planned for the paid tier.

No signed audit packets yet — you get input/output hashes; signatures are coming.