Browse docs

Journal entries

A journal entry records one transaction as a set of balanced debit/credit lines. This is the primary write operation in AI Accounting.

Anatomy of an entry

FieldNotes
dateThe accounting date (required).
descriptionHuman-readable summary, 1–500 chars (required).
referenceOptional external reference (e.g. invoice number).
lines2 or more lines (required). Each line identifies its account by account_id (UUID) or account (code/name, resolved server-side) — exactly one — plus a debit or credit amount.
auto_postIf true, the entry posts immediately; otherwise it's saved as a draft.
metadataOptional free-form JSON.

Each line may also carry a currency and exchange_rate for multi-currency entries.

Rules enforced by the engine: at least two lines; every line is a debit XOR a credit (greater than zero); and total debits must equal total credits.

Lifecycle: draft → post → reverse

Created without auto_post, an entry is a draft. It exists but does not affect balances or reports yet, so agents can stage work for review.

The corresponding API operations:

  • POST /journal-entries — create (draft, or posted with auto_post)
  • POST /journal-entries/{id}/post — post a draft
  • POST /journal-entries/{id}/reverse — reverse a posted entry

See them in the API reference. The post endpoints accept an Idempotency-Key — a retried post returns the original posted entry rather than failing because the entry is already posted.

Batch and bulk operations

  • Create in bulk: POST /journal-entries/batch accepts up to 100 entries in one request. The response is compact by default{ created_count, failed_count, errors[] }, with per-entry errors by index — and ?include_entries=true echoes the full created entries.
  • Post by id list: POST /journal-entries/batch/post posts up to 100 draft ids (same compact shape, include_entries opt-in).
  • Post by filter: POST /journal-entries/post-by-filter posts all draft entries matching a date / reference / source filter in one call — no id list, no 100 cap, safe to re-run. Ideal for committing a reviewed import.
  • Count first: GET /journal-entries/count sizes a filter (e.g. how many drafts) without fetching rows.

For bulk loads from a CSV file, CSV import is strictly better — it passes the file through unchanged, groups rows into entries, and de-duplicates re-uploads so retries are safe.

Audit trail

Posting and reversal are append-only. Posted entries are immutable; corrections happen through reversals, never edits or deletes. This immutable audit trail is what makes balances and reports trustworthy and reproducible.

Next