# Docs

> The NPCompleter HTTP API. Post a model, poll for the race result, reveal the solution. No API key.

NPCompleter is an HTTP API with a web page on top. Everything the site does, you can do with curl. There is no API key and no account. All requests and responses are JSON.

## Post a problem

```
POST https://npcompleter.com/v1/problems
Content-Type: application/json

{"format": "cnf", "body": "p cnf 2 2\n1 2 0\n-1 0\n"}
```

Optional fields:

- `public`: `true` to make the body visible on the board. Default `false`. It does nothing else yet. Later it will let other solvers compete your price down.
- `source_ref`: a short tag of your own, such as the name of the script that posted it.
- `session`: an id of your own, up to 128 characters, that groups your requests in our usage counts. The bounty request takes it too. An `X-NPC-Session` header does the same on any request, GETs included; when both are sent, the body field wins.

A `201` response:

```
{
  "id": "k3x9q2m7a1bc",
  "token": "a 32-character secret",
  "status": "queued",
  "url": "https://npcompleter.com/p/k3x9q2m7a1bc",
  "poll": "https://npcompleter.com/v1/problems/k3x9q2m7a1bc"
}
```

**Keep the token.** It is the only way to see the problem's body and solution. We store only its hash, so we cannot recover it or send it to you again.

To post a file, let `jq` do the JSON escaping. Read the file through stdin (`jq -Rs`); passing it as an argument fails for files over about 128 KB:

```
jq -Rs '{format: "lp", body: .}' model.lp \
  | curl -s https://npcompleter.com/v1/problems -H 'content-type: application/json' -d @-
```

## Formats

| format | What it is | Racers |
|---|---|---|
| `lp` | CPLEX LP file (linear and mixed-integer programs) | HiGHS, SCIP |
| `mps` | MPS file, fixed or free (linear and mixed-integer programs) | HiGHS, SCIP |
| `cnf` | DIMACS CNF (Boolean satisfiability) | Kissat, CaDiCaL |
| `wcnf` | DIMACS WCNF (weighted MaxSAT) | RC2 |
| `smt2` | SMT-LIB 2 script with (check-sat) | Z3, cvc5 |
| `mzn` | MiniZinc model, data inlined | CP-SAT |
| `fzn` | FlatZinc model | CP-SAT |
| `cpsat` | OR-Tools CpModelProto, binary, base64-encoded | CP-SAT |
| `tsplib` | TSPLIB symmetric TSP instance | PyVRP, OR-Tools routing |
| `factor` | A positive integer up to 330 bits (demo) | SymPy |

The api parses every file before it stores anything. A file that does not parse gets a `400` with a message and, where it applies, a line number. Nothing is stored and it does not count against your daily limit. MiniZinc and FlatZinc get a shape check in the api and a full compile on the solver, so a type error there shows up as `status: "invalid"` a few seconds later.

## Check a file without posting

```
POST https://npcompleter.com/v1/validate
{"format": "lp", "body": "..."}
```

`200 {"size": {"vars": 3, "constraints": 3, "bytes": 212}}` when it parses, or:

```
400 {"error": {"code": "invalid", "message": "line 14: unknown section \"Subject To:\" (expected \"Subject To\")", "line": 14}}
```

Validation stores nothing and has no rate limit.

## Poll for the result

Request the `poll` URL every 2 seconds, and every 5 seconds once 30 seconds have passed, until `status` is `solved`, `unsolved` or `invalid`. A race takes at most 60 seconds once it starts. Send the owner token in the `X-NPC-Token` header, not in the URL, so it stays out of logs.

```
GET https://npcompleter.com/v1/problems/{id}
X-NPC-Token: {token}
```

```
curl -s https://npcompleter.com/v1/problems/{id} -H 'X-NPC-Token: {token}'
```

`?token=` in the URL still works for old links, but the header is the supported form.

The response is the problem's card:

```
{
  "id", "format", "size", "public", "status", "created_at", "attempt",
  "quality":  {"kind": "objective" | "answered" | "factored", "objective", "bound", "gap", "answered"} | null,
  "solve":    {"winner", "compute_ms", "racers": [{"name", "status", "wall_ms"}]} | null,
  "price":    {"usd", "free"} | null,
  "bounty_usd", "purged",
  "body",        with the token, or when public
  "solution",    with the token, when free or revealed
  "reveal_url"   with the token
}
```

`status` moves `queued`, then `solving`, then one of `solved`, `unsolved` or `invalid`. `error` explains `invalid` and `unsolved`: with the token it is the solver's full message; without it (and on the board) it is a short code such as `invalid: parse error` or `unsolved: time cap`, because solver messages can quote a private body. `reason` always holds that code.

Each racer's `status` is one of `solved`, `infeasible`, `unbounded`, `timeout`, `stopped` or `error`. `stopped` means the racer was cancelled because another racer proved its answer first; it is not a failure. `timeout` means the racer was still running at the 60-second cap.

## Reveal a solution

If `price.free` is true, the solution is already in the response. Otherwise open `reveal_url` in a browser. Reveal is a web page on purpose: it asks a person for an email address and a confirmation, and it is not part of the API or the MCP tools.

## Set a bounty

When a problem is `queued`, `solving` or `unsolved`, its owner can attach a bounty: the amount you would pay for a solution.

```
POST https://npcompleter.com/v1/problems/{id}/bounty
X-NPC-Token: {token}
{"amount_usd": 50, "email": "you@example.com"}
```

The response is `{"bounty_usd": 50}`, the running total. The bounty is recorded and nothing is charged.

## The board

```
GET https://npcompleter.com/v1/problems?limit=50&cursor=...
```

Newest first. Public cards only: format, size, status, the race and the bounty. Bodies appear only for problems marked public.

## Errors

Every error is `{"error": {"code": "...", "message": "..."}}`.

- `400`: the file did not parse (`code: "invalid"`, with `line` when known), or the format is unknown.
- `413`: the body is over 1 MB (1,000,000 bytes).
- `429`: more than 20 posts today from your IP address. Validation is not counted.

## MCP

There is an MCP server at `https://npcompleter.com/mcp` (Streamable HTTP, no auth) with four tools: `list_formats`, `solve`, `get_problem` and `set_bounty`. `solve` waits up to 90 seconds for the race and returns the card and a reveal link. To add it to Claude Code:

```
claude mcp add --transport http npcompleter https://npcompleter.com/mcp
```

## For agents

For a coding agent whose CP-SAT, MIP or SAT solve timed out or returned UNKNOWN. Export the model from the object you already have (`model.ExportToFile("model.pb")`, `prob.writeLP("model.lp")`, `cnf.to_file("model.cnf")`) and use one of the options below. Then show your human the `reveal_url`. Never promise an optimal answer: the race runs for at most 60 seconds.

curl, reading the file through stdin so large files work:

```
jq -Rs '{format: "lp", body: .}' model.lp | curl -s https://npcompleter.com/v1/problems -H 'content-type: application/json' -d @-
```

Python (`pip install npcompleter`), which takes the model object directly:

```
from npcompleter import Client
p = Client().post_cpsat(model)    # or post_pulp(prob), post_pysat(cnf)
print(p.wait().status, p.quality, p.reveal_url)
```

MCP, for Claude Code:

```
claude mcp add -t http npcompleter https://npcompleter.com/mcp
```

The Claude Code skill, which tells the agent when to use all of this:

```
claude plugin marketplace add ArthurRab/NPCompleter
claude plugin install npcompleter@npcompleter
```

Problems are private by default, private data is deleted 30 days after it was last viewed, and each body can be up to 1 MB.

## Machine-readable

- `https://npcompleter.com/v1/formats`: formats, limits and racers.
- `https://npcompleter.com/openapi.json`: this API as OpenAPI.
- `https://npcompleter.com/llms.txt`: a short index for language models.
- Every page on this site has a Markdown version at the same path with `.md` added, for example `https://npcompleter.com/docs.md`. A problem's page, `https://npcompleter.com/p/{id}.md`, gives its card as Markdown: format, size, status, the race, the price and how to reveal.

---

API: https://npcompleter.com/v1/formats · https://npcompleter.com/openapi.json · https://npcompleter.com/llms.txt

- [Home](https://npcompleter.com/index.md)
- [Board](https://npcompleter.com/board.md)
- [Docs](https://npcompleter.com/docs.md)
- [Solvers](https://npcompleter.com/solvers.md)
- [About](https://npcompleter.com/about.md)
- [Privacy](https://npcompleter.com/privacy.md)
- [Terms](https://npcompleter.com/terms.md)
