Evenbead docs

Batch writes and batch entry

Record many expenses, checks, bills, invoices, journal entries or bank-line codings in one call, or type many expenses, checks, bills or invoices into one grid in the app. Every item is governed, checked and audited exactly as if it were sent on its own. (Dated 2026-10-18; ADR-0201.)

The endpoint: POST /v1/batches

curl -X POST https://api.evenbead.com/v1/batches \
  -H "Authorization: Bearer $EVENBEAD_KEY" -H "X-Agent-Model: your-model@version" \
  -H "Idempotency-Key: oct-close-batch-0001" -H "Content-Type: application/json" \
  -d '{
    "mode": "per_item",
    "items": [
      { "type": "expense", "idempotency_key": "oct-fuel-0003",
        "body": { "payment_account": "2100", "doc_date": "2026-10-03", "memo": "Fuel", "lines": [{ "account": "6400", "amount_cents": 5210 }] } },
      { "type": "check", "body": { "payment_account": "1000", "doc_date": "2026-10-01", "number": "1043", "lines": [{ "account": "6700", "amount_cents": 180000 }] } },
      { "type": "bank_line_coding", "bank_line_id": "6f0c…", "body": { "account": "6300" } }
    ]
  }'
FieldMeaning
items1 to 50 items, run in order.
items[].typeexpense, check, bill, invoice, journal_entry or bank_line_coding: the single operations createExpense, createCheck, createBill, createInvoice, proposeJournalEntry and categorizeBankLine.
items[].bodyThat operation's request body, exactly as it takes it, without dry_run.
items[].bank_line_idbank_line_coding only: the line (the single operation's path id).
items[].idempotency_keyOptional. The item's own key; omitted, it is <batch Idempotency-Key>.<index>.
modeper_item (default) or atomic.
dry_runtrue previews every item; nothing is written.

The answer (200) lists every item in order: status (created, proposed, refused; on a dry run would_create, would_propose, refused), the single operation's http_status and response body (result), replayed, and for a refusal the operation's own error. outcome is completed, partial, refused or previewed; counts adds them up.

The rules

  • Same governance as one by one. Each item runs through its own operation: its validation, scope, the posting policy in the database (your threshold, confidence floor, first-time vendors, sensitive accounts, period locks, an AI app's account scope and daily cap). An agent's expenses, checks, bills, invoices and journal entries are proposals a person approves; a bank coding posts only when a fact the database checks backs it (a person's rule, a vendor history the company allows) within your limit. There is no bulk bypass.
  • Aggregate caps count every item. A connected AI app's daily cap sees the batch's earlier items: the item that would cross it waits for a person (over_daily_cap).
  • Partial success. In per_item mode a refused item writes nothing and the others are kept. In atomic mode one refusal refuses the batch: 422 batch_refused, every item's verdict in error.details.items, nothing written.
  • Approvals are never batch items. Approve proposals with the review queue's operations (people decide).
  • Idempotency, twice. The batch's Idempotency-Key replays the whole answer (the same key with other items is 409). Each item's key is the single operation's key: resending an item, in another batch or alone, replays it instead of recording it again; the same key with a different body refuses that item with idempotency_conflict. A refused item stores nothing, so fix it and resend it under its key.
  • Rate limits. A batch counts as one request per item against the key's and the company's per-minute limits (60, 300 or 1,200 by plan). A batch larger than the key's per-minute budget is refused with batch_refused and max_items.
  • Audit. Each item's events carry meta.batch (id, index); a batch.item event records each verdict and what it made, and a batch.completed event the counts.

The MCP tool: create_batch

The same operation as a tool. Arguments: items (each {type, body, idempotency_key?, bank_line_id?}; body is the single tool's arguments without idempotency_key and dry_run), mode, dry_run, and the batch's idempotency_key. Errors come back as tool results with isError: true and the API's error body.

Batch entry in the app

Open Expenses, Bills or Invoices, then More, Enter many at once (or go to /app/batch). Pick the kind on the tabs, then type one per row: date, payee, vendor or customer (suggestions as you type), number, due date, account, amount and memo. Empty rows are skipped; Add 10 rows goes up to 50.

  • Review checks every row against your books without saving: each row says "Ready to save", "It will wait for approval", or what to fix.
  • Save records the good rows. Saved rows leave the grid and are listed with links; refused rows stay where you typed them, with the reason. Saving the same grid twice never records a row twice.
  • Keyboard. Tab moves across a row, Enter moves down a column, and a new row's date starts as the row above's. The total follows the amounts.
  • On a phone each row is a card with its labels.