> 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.

# Input

Every capability endpoint reads the same three input fields. Send `text` for one input, `texts` for a batch, or `image` for a picture. The rest of the body names the decision: `statement`, `labels`, `scale`, `question`, `schema`, `types`, or `field` with `value`.

Every request needs an API key. See [Authentication](/authentication).

## The three input fields

**`text`** `string`

One input, 1 to 20,000 characters. Send this field or `texts`, never both.

---

**`texts`** `string[]`

A batch of 1 to 32 inputs. Each item takes the same 1 to 20,000 character limit.

---

**`image`** `string`

One image, as base64 or a data URL. Send it instead of `text`, or with `text`. Never with `texts`.
See [Images](/concepts/images).

---

Every request carries one of these fields.

> **Warning**
>
> Send exactly one of `text`, `texts` or `image`. An `image` may travel with a `text` that gives it
> context. `text` with `texts` returns `400` `body: provide text, texts or image`. `image` with
> `texts` returns `400` `image_with_texts`. None of the three returns `400`.

## One text

#### curl

```bash
curl -s https://api.milliseconds.ai/v1/decision-machine-1/classify \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer test_sk-...' \
  -d '{
    "text": "My card was charged twice this month.",
    "labels": {
      "billing": "A problem with payment, invoices or charges",
      "shipping": "A question about delivery or address changes",
      "bug": "A defect in the product"
    }
  }'
```

#### Python

```python
import requests

labels = {
    "billing": "A problem with payment, invoices or charges",
    "shipping": "A question about delivery or address changes",
    "bug": "A defect in the product",
}

r = requests.post(
    "https://api.milliseconds.ai/v1/decision-machine-1/classify",
    headers={"authorization": "Bearer test_sk-..."},
    json={"text": "My card was charged twice this month.", "labels": labels},
)
print(r.json())
```

#### TypeScript

```typescript
const labels = {
  billing: "A problem with payment, invoices or charges",
  shipping: "A question about delivery or address changes",
  bug: "A defect in the product",
};

const res = await fetch(
  "https://api.milliseconds.ai/v1/decision-machine-1/classify",
  {
    method: "POST",
    headers: { "content-type": "application/json", authorization: "Bearer test_sk-..." },
    body: JSON.stringify({
      text: "My card was charged twice this month.",
      labels,
    }),
  },
);
console.log(await res.json());
```

## Shape JSON records into text

The models read prose, not objects. Flatten a record into short labelled lines before you send it. Keep the field names that carry meaning. Drop ids, timestamps, and internal flags that no decision uses.

**`A ticket record, flattened`**

```text title="A ticket record, flattened"
Subject: Double charge on my plan
From: dana@example.com
Plan: Team annual
Message: My card was charged twice this month and support has not replied.
```

Three rules keep the input clean:

1. Put one field on one line, as `Name: value`.
2. Write values as they read to a person: `Team annual`, not `plan_id=3`.
3. Keep the whole record under 2,000 characters when you can. The service chunks longer text.

Every character you send counts toward the character limit. The response header `x-input-tokens` reports the input tokens billed for this call. Cost grows with everything you send: the text plus the labels, statements, questions, or schema, at \$0.04 per million input tokens. See [Pricing](/reference/pricing).

## Batching with texts

Send up to 32 inputs in `texts`. The response is always the batch envelope `{"results": [...]}`, with one entry per input, in the order you sent them. Match results to inputs by index.

#### curl

```bash
curl -s -D - https://api.milliseconds.ai/v1/decision-machine-1/classify \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer test_sk-...' \
  -d '{
    "texts": [
      "My card was charged twice this month.",
      "Can you change the delivery address?"
    ],
    "labels": {
      "billing": "A problem with payment, invoices or charges",
      "shipping": "A question about delivery or address changes",
      "bug": "A defect in the product"
    }
  }'
```

#### Response

```json
{
  "results": [
    {"label":"billing","probability":0.989,"confidence":0.946,"scores":{"billing":0.989,"shipping":0,"bug":0.011}},
    {"label":"shipping","probability":1,"confidence":1,"scores":{"billing":0,"shipping":1,"bug":0}}
  ]
}
```

That call reported `x-input-chars: 73`, the number of input characters, and `x-input-tokens: 18`, the input tokens billed for this call. The chars header counts the sum over all items in the batch.

> **Note**
>
> Each text in `texts` costs one inference call. Batched statements or questions go into one call and add only their own length to the billed input. You pay \$0.04 per million input tokens and \$0 per output token. See [Pricing](/reference/pricing).

### Nested batches

On `yes-no` and `answer` you can batch both axes. `texts` with `statements`, or `texts` with `questions`, nests the envelope: an outer result per text, an inner result per statement or question.

#### curl

```bash
curl -s https://api.milliseconds.ai/v1/decision-machine-1/yes-no \
  -H 'content-type: application/json' \
  -H 'authorization: Bearer test_sk-...' \
  -d '{
    "texts": [
      "My card was charged twice this month and support has not replied.",
      "Can you change the delivery address?"
    ],
    "statements": [
      "The message reports a billing problem.",
      "The message needs a human reply today."
    ]
  }'
```

#### Response

```json
{
  "results": [
    {"results": [
      {"statement":"The message reports a billing problem.","answer":true,"probability":1},
      {"statement":"The message needs a human reply today.","answer":false,"probability":0.086}
    ]},
    {"results": [
      {"statement":"The message reports a billing problem.","answer":false,"probability":0.004},
      {"statement":"The message needs a human reply today.","answer":false,"probability":0.06}
    ]}
  ]
}
```

Two texts by two statements take 0.49 s.

Read it as `results[textIndex].results[statementIndex]`. Both axes keep input order.

## Input limits

| Field                      | Limit             | Error on breach                                             |
| -------------------------- | ----------------- | ----------------------------------------------------------- |
| `text`                     | 20,000 characters | `text: Too big: expected string to have <=20000 characters` |
| `texts`                    | 32 items          | `texts: Too big: expected array to have <=32 items`         |
| `statements` / `questions` | 32 items          | `statements: Too big: expected array to have <=32 items`    |
| `labels` (array form)      | 2 to 64           | `labels: Too small: expected array to have >=2 items`       |
| `scale`                    | 2 to 10 levels    | `scale: Too big: expected array to have <=10 items`         |

Split anything over 20,000 characters yourself. The service chunks any text over 2,000 characters, and the merge rule differs per capability.

## Next

* [Long text and chunking](/concepts/long-text) — what happens above 2,000 characters.
* [Batching](/capabilities/batching) — result ordering and how batches spread across inference slots.
* [Decisions and probabilities](/concepts/decisions-and-probabilities) — what comes back per capability.