GET /v1/ledgers/{ledger_id}/balances
Read native-unit ledger metadata, balances and posting statements. Get, balances and statement require ledger_id. Balances returns one ledger’s per-(account, sub-key) debits, credits and balance in its own unit — the balance read for usage meters, prepaid capacity and share classes as well as currency ledgers; account_code (and, with it, sub_key) narrows it to that account’s rows, summed on the account index; an optional as_of limits it to postings up to that point (a YYYY-MM-DD date includes that whole UTC day; a UTC timestamp counts postings before it), sub-keys intact. Statement pages postings by the exclusive numeric after_id cursor and can be narrowed to one account_code and, with it, one sub_key (the statement’s own subKey string). List pages by the exclusive string ledger-ID after cursor. Currencies names each currency the business’s GAAP ledgers hold real postings in, once, and in ledgers the ledger that holds it now (the open one, else the most recently closed; a functional-currency change or an incorporation succeeds a currency’s ledger). A business starts with its selected functional-currency ledger (USD when omitted); other canonical currency ledgers open when a contract first binds them. Amounts remain exact strings and are never summed across units. Transaction requires occurrence_id (an invoice, bill or payment record) and returns every posting of every event that touched its claims (the record itself, the payments, credits and corrections against it, with each correction’s reversal), in effective order, each with the record it came from, plus otherClaims: other invoices or bills those events also settled. Footprint takes exactly one of party_id, contract_id or occurrence_id and returns every posting of every recording on that party’s contracts, on that contract, or in that record’s transaction, in effective order, each attributed to its record (occurrenceId, occurrenceKey), activity, pattern and party the way the activity_balances report attributes it, with its ledger’s unit and decimals; plus contracts, the contracts it spans. Null when the party, contract or record does not exist.
All operations · Reusable schemas
Complete operation contract
{
"operationId": "ledgers.balances",
"description": "Read native-unit ledger metadata, balances and posting statements. Get, balances and statement require ledger_id. Balances returns one ledger's per-(account, sub-key) debits, credits and balance in its own unit — the balance read for usage meters, prepaid capacity and share classes as well as currency ledgers; account_code (and, with it, sub_key) narrows it to that account's rows, summed on the account index; an optional as_of limits it to postings up to that point (a YYYY-MM-DD date includes that whole UTC day; a UTC timestamp counts postings before it), sub-keys intact. Statement pages postings by the exclusive numeric after_id cursor and can be narrowed to one account_code and, with it, one sub_key (the statement's own subKey string). List pages by the exclusive string ledger-ID after cursor. Currencies names each currency the business's GAAP ledgers hold real postings in, once, and in ledgers the ledger that holds it now (the open one, else the most recently closed; a functional-currency change or an incorporation succeeds a currency's ledger). A business starts with its selected functional-currency ledger (USD when omitted); other canonical currency ledgers open when a contract first binds them. Amounts remain exact strings and are never summed across units. Transaction requires occurrence_id (an invoice, bill or payment record) and returns every posting of every event that touched its claims (the record itself, the payments, credits and corrections against it, with each correction's reversal), in effective order, each with the record it came from, plus otherClaims: other invoices or bills those events also settled. Footprint takes exactly one of party_id, contract_id or occurrence_id and returns every posting of every recording on that party's contracts, on that contract, or in that record's transaction, in effective order, each attributed to its record (occurrenceId, occurrenceKey), activity, pattern and party the way the activity_balances report attributes it, with its ledger's unit and decimals; plus contracts, the contracts it spans. Null when the party, contract or record does not exist.",
"parameters": [
{
"name": "X-Economico-Business",
"in": "header",
"required": true,
"description": "Explicit business slug for this request; must be approved by the connection and token.",
"schema": {
"type": "string"
}
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1,
"maximum": 500,
"default": 100
}
},
{
"name": "ledger_id",
"in": "path",
"required": true,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "occurrence_id",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "party_id",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "contract_id",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "account_code",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 0
}
},
{
"name": "event_id",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 1
}
},
{
"name": "sub_key",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "after",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
},
{
"name": "after_id",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"minimum": 0
}
},
{
"name": "as_of",
"in": "query",
"required": false,
"schema": {
"type": "string",
"minLength": 1
}
}
],
"responses": {
"200": {
"description": "Canonical result; missing read objects are null. Money is in decimal integer strings.",
"content": {
"application/json": {
"schema": {}
}
}
},
"400": {
"description": "Invalid envelope, query or domain input; also `missing_rates`, a foreign-currency command whose exchange rates the shared store could not supply (`details.missing_rates: [{ base, quote, date }]`, plus `details.refusal: { code, message }` when the command also refused), answered by stating an evidenced `exchangeRate`.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"401": {
"description": "Missing or invalid bearer token. Follow the WWW-Authenticate resource_metadata URL.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"WWW-Authenticate": {
"schema": {
"type": "string"
}
}
}
},
"402": {
"description": "plan_required: the command needs a platform plan this business is not on (members beyond the owner and shared views need Founders or Startup), or the command would record more events than Solo's monthly allowance has left. The allowance refusal writes nothing (a retry may keep its idempotency key) and carries `details: { reason, included, used, requested, from, through }` (counts as decimal strings; `from`/`through` the current events period as UTC instants). `reason` `solo_limit`: Solo's allowance; tell the founder the limit and that it resets at `through`, then retry after `through`, or once they accept paid extra events or upgrade to a paid plan `details.choices` names (`founders` while the team fits Founders, `team` for Startup; each with its own offer for `platform_purchase`). `reason` `plan_cancelled`: Startup was cancelled, or Solo's extra events were turned off; the extra events so far were billed then, and until the plan ends at `endsAt` the business has only `allowed` events in each billing period (its included events, or up to the end of a started block the cancellation billed), with no further extra events; after that it is on Solo (`after` `solo`, for Startup); retry after `through` (the next period's included events) or after `endsAt`. Tell the founder; they can keep Startup (or the extra events) from the billing page once the extra events billed then are paid (for monthly Startup whose cancellation billed extra events, keeping it takes a new Startup agreement from the end; a first-year YC price cannot carry over, so that plan ends as scheduled), or choose it again once it has ended. Any new paid plan (Startup, extra events, a switch or that new agreement) starts only once every invoice from Economico is paid; until then the billing page says so. `reason` `usage_settled`: Startup or Solo's extra events were kept after a cancel; this period's usage was settled then, so retry after `through`. With `details.closesAt`, the business is set to close then (its owner approved closing it): tell the founder, and do not wait for `endsAt` or suggest keeping or upgrading the plan; the owner can stop the closing at /account/cancel until then. Reads, exports and payment setup stay available, and so does upgrading unless the business is set to close (`closesAt`).",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"403": {
"description": "Membership revoked, business unavailable for writes, or command credential requirements not met (browser-only commands refuse all OAuth tokens). `demo_business`: the business is a demo (`demo: true` on the business read: fictional, its owner's alone) and the command would reach someone else, send a message (support included, for now), publish it, take a plan or make it look like a real company, or the demo has recorded the 2,000 events it may record; tell the user, who can create their own business to do this.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"404": {
"description": "Unknown route or missing required resource.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"405": {
"description": "Method not supported.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"Allow": {
"schema": {
"type": "string"
}
}
}
},
"408": {
"description": "Request body transfer timed out (code `upload_timeout`): it took over 30 s, or paused over 5 s between chunks; retry the same request.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"409": {
"description": "Domain or idempotency conflict.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"411": {
"description": "Length required (code `length_required`): a JSON body larger than 256 KiB must send Content-Length.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"413": {
"description": "Payload too large (code `payload_too_large`): the request body exceeds the admitted byte limit.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"415": {
"description": "JSON body required.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"429": {
"description": "Address rate budget exhausted. Wait for Retry-After seconds before retrying.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"Retry-After": {
"schema": {
"type": "string",
"pattern": "^[0-9]+$"
}
}
}
},
"500": {
"description": "Internal failure.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}
},
"503": {
"description": "Busy (code `busy`): the business is still receiving other document uploads or serving other large documents, and did not start this request. Retry the same request after Retry-After seconds.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
},
"headers": {
"Retry-After": {
"schema": {
"type": "string"
}
}
}
}
}
}