> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.milliseconds.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.milliseconds.ai/_mcp/server.

# Answer

`POST /v1/decision-machine-1/answer` pulls an answer out of the text you send. The answer is always a span of that text, never generated prose. Each result carries the span, its `start` and `end` character offsets, and a probability. When nothing in the text fits, the answer can come back `null`. Every request needs an API key. See [Authentication](/authentication).

## When to use it

* You need one stated value from a document, and you need to point at where it came from.
* You want the offsets, so you can highlight, redact, or link back to the source.
* You ask a few different questions of the same text in one call.
* Use [extract](/capabilities/extract) instead when you want a whole typed record with several fields in one shape.
* Use [entities](/capabilities/entities) instead when you want **every** span of a type, not the single best one.

## Three example decisions

1. "Who is the customer?" over an order confirmation returns the name and its offsets.
2. "When did the order ship?" over the same text returns the date span.
3. "What is the tracking number?" over a text without one returns a weak span, or `null`.

## Request

| Field       | Type      | Required                        | Meaning                         | Limits                                     |
| ----------- | --------- | ------------------------------- | ------------------------------- | ------------------------------------------ |
| `text`      | string    | one of `text` / `texts`         | The text to read                | 1 to 20,000 characters                     |
| `texts`     | string\[] | one of `text` / `texts`         | A batch of texts                | 1 to 32 items, each 1 to 20,000 characters |
| `question`  | string    | one of `question` / `questions` | The single question             | Minimum 1 character                        |
| `questions` | string\[] | one of `question` / `questions` | Several questions over one text | 1 to 32 items, each minimum 1 character    |

Send `text` or `texts`, and send `question` or `questions`. `question` and `questions` are mutually exclusive. Sending both, or sending neither, raises `invalid_request` with the message `body: provide question or questions, not both`.

**`curl`**

```bash title="curl"
curl -X POST https://api.milliseconds.ai/v1/decision-machine-1/answer \
  -H "content-type: application/json" \
  -H "authorization: Bearer test_sk-..." \
  -d '{
    "text": "Order 88214 shipped on 3 March 2026 from the Berlin warehouse. The customer, Maria Fischer, paid 249.00 EUR by credit card. Delivery is expected within five working days.",
    "question": "Who is the customer?"
  }'
```

**`Python`**

```python title="Python"
import requests

text = (
    "Order 88214 shipped on 3 March 2026 from the Berlin warehouse. "
    "The customer, Maria Fischer, paid 249.00 EUR by credit card. "
    "Delivery is expected within five working days."
)

response = requests.post(
    "https://api.milliseconds.ai/v1/decision-machine-1/answer",
    headers={"authorization": "Bearer test_sk-..."},
    json={"text": text, "question": "Who is the customer?"},
    timeout=30,
)
result = response.json()
print(result["answer"], result["start"], result["end"])
```

**`TypeScript`**

```typescript title="TypeScript"
const text =
  "Order 88214 shipped on 3 March 2026 from the Berlin warehouse. " +
  "The customer, Maria Fischer, paid 249.00 EUR by credit card. " +
  "Delivery is expected within five working days.";

const response = await fetch(
  "https://api.milliseconds.ai/v1/decision-machine-1/answer",
  {
    method: "POST",
    headers: { "content-type": "application/json", authorization: "Bearer test_sk-..." },
    body: JSON.stringify({ text, question: "Who is the customer?" }),
  },
);

const result = await response.json();
console.log(result.answer, result.start, result.end);
```

## Response

```json
{
  "question": "Who is the customer?",
  "answer": "Maria Fischer",
  "probability": 0.999,
  "start": 77,
  "end": 90
}
```

* `question` — an echo of the question you sent. It keeps results readable in a batch.
* `answer` — the span of your input text, or `null` when nothing fits. The service never writes new words.
* `probability` — the span confidence, between 0 and 1. It is `0` when `answer` is `null`.
* `start`, `end` — character offsets of the span in the text. `text.slice(start, end)` equals `answer`. Both are `null` when `answer` is `null`.

The call above took 0.40 s. Answer runs on the extractor in one pass, so it stays near 0.4 s whatever the question count.

## Reading the numbers

Send four questions over the same order text and the split shows at once.

```json
{
  "results": [
    {"question":"Who is the customer?","answer":"Maria Fischer","probability":1,"start":77,"end":90},
    {"question":"When did the order ship?","answer":"3 March 2026","probability":0.994,"start":23,"end":35},
    {"question":"How much did the customer pay?","answer":"249.00 EUR","probability":0.997,"start":97,"end":107},
    {"question":"What is the tracking number?","answer":"88214","probability":0.755,"start":6,"end":11}
  ]
}
```

The first three questions are answered by the text. Each one returns a clean span above 0.99. Read those as safe to write into a record.

The fourth question has no answer in the text. There is no tracking number. The model still returns the closest number-like span, the order number, at 0.755. The probability is the signal, not the presence of a span.

Set your bar per action. Spans at or above 0.95 are safe to store. Spans between 0.7 and 0.95 belong in a review queue. Below 0.7, drop the result. Raise every band when a wrong value costs money. [Thresholds and confidence routing](/concepts/thresholds) sets the bands per action.

> **Warning**
>
> A `null` answer is not guaranteed for an unanswerable question. This real capture returned `null`, from a different text: `{"question":"What is the CEO salary?","answer":null,"probability":0,"start":null,"end":null}`. Treat a low probability and a `null` as the same outcome in your code.

To confirm a value before you write it anywhere, pass it to [verify](/capabilities/verify). The [Extract, then verify](/patterns/extract-then-verify) pattern wires the two together.

## Batching

Two keys batch, and they behave differently.

`questions` sends several questions over one text. All questions go into a single call, so the cost in time is close to zero: 3 questions measured 0.40 s, the same as 1. The response is always the batch envelope.

```json
{"text": "<one text>", "questions": ["Who is the customer?", "When did the order ship?"]}
```

`texts` sends one question over several texts. Each text is a separate call. Results come back in input order. This request sends the order text and a second order:

```json
{
  "texts": [
    "Order 88214 shipped on 3 March 2026 from the Berlin warehouse. The customer, Maria Fischer, paid 249.00 EUR by credit card. Delivery is expected within five working days.",
    "Order 88215 shipped on 4 March 2026 from the Lyon warehouse. The customer, Paul Dubois, paid 99.00 EUR by credit card."
  ],
  "question": "Which warehouse shipped the order?"
}
```

```json
{
  "results": [
    {"question":"Which warehouse shipped the order?","answer":"Berlin warehouse","probability":0.983,"start":45,"end":61},
    {"question":"Which warehouse shipped the order?","answer":"Lyon warehouse","probability":0.93,"start":45,"end":59}
  ]
}
```

Offsets always point into their own text. The second result's `start` of 45 indexes the second string, not the first.

> **Note**
>
> Combining `texts` with `questions` nests the envelope: `{"results":[{"results":[...]},{"results":[...]}]}`. The outer array follows `texts` order, the inner array follows `questions` order. [Batching](/capabilities/batching) covers the shape for every capability.

## Limits and gotchas

* `text` takes up to 20,000 characters. `texts` takes up to 32 items. `questions` takes up to 32 items.
* Always send `text`, `texts` or `image`. A body with a question and none of the three returns `400` with `body: provide text, texts or image`.
* Answers are extractive. Ask for a value the text states. A question such as "Is this order late?" has no span to return; use [yes-no](/capabilities/yes-no) for a verdict.
* Write the question as a full question about the case. Vague questions pull vague spans, as the tracking number result shows.
* Texts over 2,000 characters are chunked. The offsets you get back still point into the text you sent. Cost scales with the length of the text and the questions you send, at \$0.04 per million input tokens. See [Pricing](/reference/pricing). See [Long text and chunking](/concepts/long-text).
* The extractor is multilingual, so non-English text works here. See [Languages](/concepts/languages).
* A `529 overloaded` response means every inference slot stayed busy. Retry with backoff. [Errors](/reference/errors) lists every code.

## Images

Send `image` instead of `text` to run this capability over a photograph or a scanned page. `image` is
a `data:image/jpeg;base64,` URL or bare base64 of a JPEG, PNG or WebP, at most 5 MB decoded. `detail`
picks the resolution: `low` is 512 px, `medium` is 768 px and is the default, `high` is 1024 px.

```bash
curl -X POST https://api.milliseconds.ai/v1/decision-machine-1/answer \
  -H "content-type: application/json" \
  -H "authorization: Bearer test_sk-..." \
  -d '{
    "image": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
    "detail": "low",
    "question": "What is the total?"
  }'
```

On an image the answer comes from the pixels, so there are no character offsets: `start` and `end`
are `null`. `answer` and `probability` read as they do on text. With `questions`, the image bills
once for the whole request and each question runs its own generation.

`image` works with `text`, never with `texts`. The image bills a fixed number of tokens:
1,500 for `low`, 3,000 for `medium`, 6,000 for `high`. The rest of the body bills as today. See [Images](/concepts/images).

## Next

#### [Extract](/capabilities/extract)

Fill a whole JSON Schema in one call instead of asking question by question.

#### [Writing good statements and labels](/concepts/writing-good-questions)

Question wording moves the span. This page shows what to write.

#### [Extract, then verify](/patterns/extract-then-verify)

Check a pulled value against the source before you store it.