Skip to content

Post many entries as one unit, checked against the count and totals the caller asserts

POST
/v1/entities/{entity_id}/batches
curl --request POST \
--url https://example.com/v1/entities/example/batches \
--header 'Content-Type: application/json' \
--data '{ "reason": "example", "entries": [ { "legs": [ { "account": "example", "commodity": "example", "amount": "-12.00", "memo": "example", "tax_code": "example" } ], "dt": "example", "narration": "example", "reason": "example", "origin": "example", "code": "", "comment": "", "tags": [ [ "example" ] ], "id": "example" } ], "asserted": { "count": 1, "totals": [ { "commodity": "example", "debits_micros": "1200000", "credits_micros": "1200000" } ] } }'

Post a converted set of entries, and learn before anything commits whether it is the set you sent.

The caller asserts how many entries the batch contains and what each commodity’s debits and credits come to in micros. Both sides are asked for even though a balanced batch makes them equal. The caller computes them from its own source, so a figure transposed on one side disagrees with the other instead of cancelling out.

A refusal is whole and leaves nothing behind, whether the cause is a broken assertion, an unknown account in the nine-hundredth entry or a date in a closed period. 422 unbalanced names every commodity whose asserted totals disagree with what was posted, with both numbers. 422 validation covers the count and the maximum batch size (published as limits.max_batch_entries in /capabilities). A refusal about one entry names that entry: batch_index, its date and narration, its entry_id when the caller supplied one, and a path such as entries[900].legs[0].account. A retry under the same Idempotency-Key replays the original reply instead of posting the batch twice.

The whole batch is recorded as one operations row (intent: the assertion; result: the entries written), alongside the ordinary audit action each entry keeps.

entity_id
required
Entity Id

The entity this path is relative to

string

The entity this path is relative to

Media typeapplication/json
BatchSubmission

N entries, posted as one unit that is applied whole or refused whole.

This is the write for a conversion: a year of entries an agent has converted from a journal, a spreadsheet or another system’s export. A loop of single POST /entries calls posts the same rows but proves nothing about the set. A dropped entry, a retry that posted twice, or a connection lost two thirds of the way through each leave books that are internally consistent and simply wrong. A batch carries the caller’s own count and per-commodity totals, and either matches them or leaves nothing behind.

object
reason
required
Reason

Why this batch is being loaded; kept in the record

string
>= 1 characters
entries
required
Entries

The entries, in the order they are to be posted

Array<object>
>= 1 items
BatchEntry

One entry of a batch, in the same shape POST /entries takes.

The only difference is that reason is optional, because the batch has one and repeating it on every entry of a converted year would be a thousand copies of one sentence. An entry with something more specific to say carries its own, recorded verbatim on that entry’s audit action.

object
legs
required
Legs

Every leg of the entry; they net to zero per commodity

Array<object>
>= 2 items
EntryLeg

One leg of a manual journal entry: an account, a currency and a signed amount.

Unlike a line booking’s legs, these are the whole entry. No cash leg is supplied for you, because there is no statement line behind this entry. Two legs or more, netting to zero per commodity.

object
account
required
Account

Account path (preferred) or stable account id

string
>= 1 characters <= 255 characters
commodity
required
Commodity
string
>= 1 characters <= 64 characters
amount
required
Amount

Signed decimal amount in whole commodity units; never a JSON number

string
memo
Any of:
string
<= 4096 characters
tax_code
Any of:
string
<= 255 characters
dt
required
Dt

The entry date, YYYY-MM-DD

string
narration
required
Narration

What this entry reads as in the books

string
>= 1 characters <= 4096 characters
reason
Any of:
string
origin
Any of:
string
code
Code

Hledger tcode, e.g. a document number

string
"" <= 255 characters
comment
Comment

Hledger tcomment, kept verbatim

string
"" <= 4096 characters
tags
Any of:
Array<Array<string>>
id
Any of:
string
asserted
required
BatchAssertion

What the caller says this batch contains: the caller’s claim, not the ledger’s derivation.

The ledger never sees the journal, spreadsheet or export the entries were converted from (decisions.md, “Chunk F1 – the generic statement input”), so it cannot know how many entries there should be. The caller counted them at the source and states it here, and the ledger refuses a batch that does not match.

object
count
required
Count

How many entries this batch contains

integer
>= 1
totals
required
Totals

Every commodity the batch touches, each named exactly once

Array<object>
>= 1 items
BatchTotal

What the caller says one commodity comes to across the whole batch, as two magnitudes in micros.

Both are non-negative: debits_micros is the sum of every positive posting of this commodity and credits_micros of every negative one. Each entry balances, so the two must be equal once the batch is built, and that is why both are asked for. The caller computes them from its own source, so a figure transposed on one side of the conversion disagrees with the other and the batch is refused.

object
commodity
required
Commodity
string
>= 1 characters <= 64 characters
debits_micros
required
Debits Micros

Sum of the positive postings of this commodity, in micros

string
/^-?(0|[1-9][0-9]*)$/
credits_micros
required
Credits Micros

Sum of the negative postings of this commodity, as a magnitude

string
/^-?(0|[1-9][0-9]*)$/

Successful Response

Media typeapplication/json
BatchResponse
object
entity_id
required
Entity Id
string
legal_name
required
Legal Name
string
base_currency
required
Base Currency
string
snapshot_seq
required
Snapshot Seq
integer
operation_id
required
Operation Id

The one operations row this batch was recorded as

string
count
required
Count
integer
entry_ids
required
Entry Ids

The entries that were posted, in submission order

Array<string>
totals
required
Totals

What was actually posted; equal to the assertion, or this would have been refused

Array<object>
BatchTotal

What the caller says one commodity comes to across the whole batch, as two magnitudes in micros.

Both are non-negative: debits_micros is the sum of every positive posting of this commodity and credits_micros of every negative one. Each entry balances, so the two must be equal once the batch is built, and that is why both are asked for. The caller computes them from its own source, so a figure transposed on one side of the conversion disagrees with the other and the batch is refused.

object
commodity
required
Commodity
string
>= 1 characters <= 64 characters
debits_micros
required
Debits Micros

Sum of the positive postings of this commodity, in micros

string
/^-?(0|[1-9][0-9]*)$/
credits_micros
required
Credits Micros

Sum of the negative postings of this commodity, as a magnitude

string
/^-?(0|[1-9][0-9]*)$/
audit_seq
required
Audit Seq

The batch.posted audit action’s event sequence

integer
links
required
Links
object
key
additional properties
string

Example

{
"totals": [
{
"debits_micros": "1200000",
"credits_micros": "1200000"
}
]
}

Bad Request

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Unauthorized

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Forbidden

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Not Found

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Conflict

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Precondition Failed

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Unprocessable Content

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Internal Server Error

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}

Service Unavailable

Media typeapplication/json
ErrorEnvelope
object
error
required
ErrorBody
object
code
required
Code
string
message
required
Message
string
retryable
required
Retryable
boolean
details
required
Details
Array<object>
object
key
additional properties
any
request_id
Any of:
string
next_action
Any of:
object
key
additional properties
any

Example generated

{
"error": {
"code": "example",
"message": "example",
"retryable": true,
"details": [
{}
],
"request_id": "example",
"next_action": {}
}
}