Docs·API reference

Execute

POST /v1/execute runs a program over a document, for example an answer's program after you edit it. No model call, no tokens billed.

HTTP
POST https://platform.xerj.ai/v1/execute
Authorization: Bearer $XERJ_API_KEY
Content-Type: application/json

Every answer comes with the program that produced it, in symbolic.program. Execute runs a program over a document with the same executor, without the model. Change a number format, point a quote at other characters, add a step, and see what the program gives. The program editor in the playground does the same.

No tokens are billed and nothing is charged from your balance. Each call counts against your requests per minute.

Request #

Field Type Required Description
document string yes The text the program reads. state and text are accepted as other names for it. Up to 1,000,000 characters; the model's token window does not apply, because the model does not read it.
program array or string yes The program as JSON, or the same as a JSON string of up to 20,000 characters. How to read and write one.
type string no The type the result must have: one of the field types, or auto (default: inferred from question, else text).
question string no The question the program answers. It comes back in the result, and it sets the type when type is auto.
options, id_kind, name, spec no The rest of the field, as in /v1/answers. A choice needs options.
ref_date string no YYYY-MM-DD: the date that “today” means, and the year for dates written without one.
model string no Default xerj-reader-1.

A quote instead of offsets #

A SPAN can give its text instead of its character offsets:

Quotes are turned into offsets before the program runs, and the response shows the program with offsets. A quote that is not in the document is 400 invalid_program.

Response #

The same fields as an answer, with these differences:

Field Description
id exe_…
object Always "execution".
question The question you sent, or "(edited program)".
confidence null, and answer.confidence too: no model wrote this program.
symbolic The program with offsets, and its run. There are no model fields (confidence, model, model_label, finished, decode_error, n_prompt_tokens, n_gen_tokens), and ms has only execute.
usage Always {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}.

A program that does not give a value is not an error. The response is a 200 whose status says why, such as UNKNOWN or UNSUPPORTED, with a reason.

Examples #

The document is the invoice of the Extract example. Every response is a real run; id, created and latency_ms are left out.

Run a program, with a quote #

curl
curl https://platform.xerj.ai/v1/execute \
  -H "Authorization: Bearer $XERJ_API_KEY" \
  -H "Content-Type: application/json" \
  -d @- <<'EOF'
{"document": "…the invoice…", "question": "What is the total amount due?", "type": "money",
 "program": [["SPAN", "d1", "48,200.00 EUR"], ["MONEY", "auto"]]}
EOF
Python
r = client.execute.create(
    document=invoice,
    program=[["SPAN", "d1", "48,200.00 EUR"], ["MONEY", "auto"]],
    type="money",
    question="What is the total amount due?",
)
print(r.status, r.value_text, r.symbolic.program)
JavaScript
const r = await client.execute.create({
  document: invoice,
  program: [["SPAN", "d1", "48,200.00 EUR"], ["MONEY", "auto"]],
  type: "money",
  question: "What is the total amount due?",
});
console.log(r.status, r.value_text, r.symbolic.program);

The complete response:

JSON
{
  "object": "execution",
  "model": "xerj-reader-1",
  "question": "What is the total amount due?",
  "type": "money",
  "status": "ANSWER",
  "value": {"amount": "48200.00", "currency": "EUR"},
  "value_text": "48200.00 EUR",
  "reason": null,
  "confidence": null,
  "evidence": [{"start": 459, "end": 472, "quote": "48,200.00 EUR"}],
  "answer": {"type": "value", "text": "48200.00 EUR", "start": null, "end": null, "confidence": null},
  "best_guess": null,
  "symbolic": {
    "program": [["SPAN", "d1", 459, 472], ["MONEY", "auto"]],
    "program_compact": "MONEY(“48,200.00 EUR”, \"auto\") = 48200.00 EUR",
    "spans": [{"doc": "d1", "start": 459, "end": 472, "quote": "48,200.00 EUR"}],
    "status": "ANSWER",
    "value": {"amount": "48200.00", "currency": "EUR"},
    "value_text": "48200.00 EUR",
    "reason": null,
    "evidence": [{"doc_id": "d1", "char_start": 459, "char_end": 472, "quote": "48,200.00 EUR", "exact": true, "path": "", "chain": []}],
    "checks": [],
    "coverage": null,
    "withheld_value": null,
    "candidates": null,
    "typecheck": "Money",
    "field": {"name": "answer", "instruction": "What is the total amount due?", "spec": {"type": "money"}},
    "type": "money",
    "type_inferred": false,
    "ms": {"execute": 0}
  },
  "usage": {"input_tokens": 0, "output_tokens": 0, "total_tokens": 0}
}

The quote became the offsets 459, 472.

Edit a program #

The same program with the number format "nl-NL" instead of "auto", sent as a JSON string:

JSON
{"document": "…the invoice…", "question": "What is the total amount due?", "type": "money",
 "program": "[[\"SPAN\", \"d1\", \"48,200.00 EUR\"], [\"MONEY\", \"nl-NL\"]]"}
Text
MONEY(“48,200.00 EUR”, "nl-NL") → UNKNOWN ('48,200.00  ' is not a nl-NL number)

status is UNKNOWN and value is null: in that format 48,200.00 is not a number, so the executor gives no value rather than a wrong one. A field named total once got this exact program from the model; see field names.

A computed value #

JSON
{"document": "…the invoice…", "type": "number",
 "program": ["SUB", [["SPAN", "d1", "30 November 2025"], ["DATE", "auto"]],
                    [["SPAN", "d1", "14 October 2025"], ["DATE", "auto"]]]}
Text
SUB(DATE(“30 November 2025”, "auto"), DATE(“14 October 2025”, "auto")) = 47

value is "47", and evidence holds both dates: 30 November 2025 at 75–91 and 14 October 2025 at 49–64.

The wrong type #

A quote alone is text. Asked for money, the program is refused with a reason:

JSON
{"document": "…the invoice…", "type": "money", "program": ["SPAN", "d1", "PO-5512"]}
Text
“PO-5512” → UNSUPPORTED (program returns Text, field is money)

Errors #

Status Code When
400 missing_program program is missing.
400 invalid_program program is not valid JSON, is longer than 20,000 characters, or quotes text that is not in the document. The message says which, for example SPAN: quoted text 'no such text' not found in d1 (occurrence 1).
400 missing_document, document_too_long document is missing, empty, or longer than 1,000,000 characters.
400 invalid_type type is not one of the field types.
400 invalid_fields options, id_kind, name or spec is malformed; a choice without two options has param options.
400 missing_question question is not a string.
400 invalid_ref_date, invalid_json As in /v1/answers.
401 missing_api_key, invalid_api_key, revoked_api_key See errors.
403 access_not_active The account's access is not active yet.
404 model_not_found The model does not exist.
429 requests_per_minute See rate limits.
503 queue_timeout The service is starting. Retry after retry-after seconds.

There is no 402: execute bills no tokens, so it runs at any balance.