# Batch requests

Send many texts in one HTTP call. Each item is answered, billed and logged exactly like a single request, so a batch costs the same as sending the items one by one. It saves round trips, not money.

Endpoints

```http
POST https://layahost.com/v1/decide/batch
POST https://layahost.com/v1/systemone/batch
```

## The same decision for many texts

`/v1/decide/batch` takes the body of [POST /v1/decide](https://layahost.com/docs/decide), with `texts` (a list of up to 64 strings) instead of `text`. The template or question applies to every text.

POST /v1/decide/batch

```bash
curl https://layahost.com/v1/decide/batch \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template": "spam",
    "texts": [
      "Congratulations! You won a free iPhone, claim it at bit.ly/xyz",
      "Hi, I was charged twice for my subscription this month."
    ]
  }'
```

POST /v1/decide/batch

```python
import os
import requests

res = requests.post(
    "https://layahost.com/v1/decide/batch",
    headers={"Authorization": f"Bearer {os.environ['LAYAHOST_API_KEY']}"},
    json={"template": "spam", "texts": messages},
    timeout=30,
)
res.raise_for_status()
for item in res.json()["results"]:
    if item["status"] == 200:
        print(item["index"], item["decision"], item["confidence"])
    else:
        print(item["index"], "failed:", item["detail"])
```

POST /v1/decide/batch

```javascript
const res = await fetch("https://layahost.com/v1/decide/batch", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LAYAHOST_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ template: "spam", texts: messages }),
});

const { results, usage } = await res.json();
for (const item of results) {
  console.log(item.index, item.status === 200 ? item.decision : item.detail);
}
```

Response · 200

```json
{
  "results": [
    {
      "index": 0,
      "status": 200,
      "decision": "spam",
      "confidence": 0.3328,
      "probabilities": { "spam": 0.8258, "legit": 0.1742 },
      "template": "spam",
      "model": "laya-english",
      "usage": { "decisions": 1, "input_tokens": 77, "cost_micros": 5, "cost_usd": 5.0e-6 },
      "latency_ms": 325.72,
      "request_id": "req_yyc8n70ajnyo5rwgkhcwmceb_0"
    },
    {
      "index": 1,
      "status": 200,
      "decision": "legit",
      "confidence": 0.0806,
      "probabilities": { "legit": 0.6656, "spam": 0.3344 },
      "template": "spam",
      "model": "laya-english",
      "usage": { "decisions": 1, "input_tokens": 72, "cost_micros": 5, "cost_usd": 5.0e-6 },
      "latency_ms": 231.02,
      "request_id": "req_yyc8n70ajnyo5rwgkhcwmceb_1"
    }
  ],
  "usage": { "decisions": 2, "failed": 0, "cost_micros": 10, "cost_usd": 1.0e-5 },
  "request_id": "req_yyc8n70ajnyo5rwgkhcwmceb"
}
```

Each item in `results` is the [/v1/decide response](https://layahost.com/docs/decide) plus its `index` and `status`. Results are in the order of `texts`.

## Many Jev requests at once

`/v1/systemone/batch` takes `requests`, a list of up to 64 ordinary [/v1/systemone](https://layahost.com/docs/systemone) bodies, each with its own text, model and questions. At most 256 questions in total per batch.

POST /v1/systemone/batch

```bash
curl https://layahost.com/v1/systemone/batch \
  -H "Authorization: Bearer $LAYAHOST_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "requests": [
      {"state": "Our checkout is down!", "model": "jev-latest",
       "questions": {"urgent": {"type": "noul", "instructions": "Is this urgent?"}}},
      {"state": "Love the new dashboard.", "model": "jev-latest",
       "questions": {"urgent": {"type": "noul", "instructions": "Is this urgent?"}}}
    ]
  }'
```

Response · 200

```json
{
  "responses": [
    {
      "index": 0,
      "status": 200,
      "body": {
        "model": "laya-english",
        "answers": { "urgent": { "type": "noul", "noul": 0.733, "confidence": 0.733 } },
        "usage": { "input_tokens": 35, "output_tokens": 0 },
        "meta": { "request_id": "req_halhpd064uorzjutdn2mwwpo_0", "decisions": 1, "cost_micros": 5, "cost_usd": 5.0e-6, "latency_ms": 85.52 }
      }
    },
    {
      "index": 1,
      "status": 200,
      "body": {
        "model": "laya-english",
        "answers": { "urgent": { "type": "noul", "noul": 0.0392, "confidence": 0.9608 } },
        "usage": { "input_tokens": 35, "output_tokens": 0 },
        "meta": { "request_id": "req_halhpd064uorzjutdn2mwwpo_1", "decisions": 1, "cost_micros": 5, "cost_usd": 5.0e-6, "latency_ms": 73.45 }
      }
    }
  ],
  "request_id": "req_halhpd064uorzjutdn2mwwpo"
}
```

Each `body` is exactly what `/v1/systemone` would have returned for that request, success or error.

## Partial failures and billing

- A batch answers `200` once its envelope is valid, even if some items fail. Check each item's `status`.
- A bad item gets its own `422` and does not stop the rest. It is not billed.
- Items run in order and are charged one by one. If your credit runs out halfway, the remaining items get `402` and are not billed.
- An invalid envelope (no list, too many items, an unknown template) gets `422` for the whole batch and nothing runs.
- Every item appears in [Logs](https://layahost.com/logs) with the batch request ID plus `_0`, `_1` and so on.
- A batch counts as one request against your [rate limit](https://layahost.com/docs/rate-limits).

Items are answered one after another, so a full batch takes about as long as its items added up: typically 2 to 5 seconds for 64 short texts. Set your HTTP timeout to at least 30 seconds.
