Transactions
/v1/transactionsList transactions
The ledger's transactions, newest first. Daily market-value entries on investment accounts are balance facts, not transactions, and are never listed.
Parameters
limit integer · query | Page size, 1–200. |
cursor string | null · query | The next_cursor of the previous page. |
account_id integer | null · query | Only transactions touching this account. |
category_id integer | null · query | Only transactions filed under this category account. |
tag_id integer | null · query | Only transactions carrying this tag. |
since date | null · query | On or after this date. |
until date | null · query | On or before this date. |
search string | null · query | Text in the description, the bank's statement line or the name the user gave the counterparty, or an amount (72.80, 72,80; 72 is any amount from 72.00 to 72.99). |
uncategorized boolean · query | Only transactions still waiting for a category. |
purpose string | null · query | personal or business only. |
X-Organization-Id string | null · header |
Returns 200 · TransactionList
data | |
has_more boolean · required | |
next_cursor string | null · required |
curl -X GET "https://api.lumaledger.app/v1/transactions" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/transactionsCreate a transaction
Post a hand-written transaction as a balanced journal entry: a cash
purchase, a loan payment split into interest and principal, an opening
balance. Send an Idempotency-Key so a retry cannot post it twice.
Parameters
Idempotency-Key string | null · header | Any unique string (a UUID is ideal). A retry with the same key returns the first attempt's response instead of doing the work twice. Keys are kept for 24 hours. |
X-Organization-Id string | null · header |
Body · TransactionCreate
date date · required | |
description string · required | |
lines | |
memo string | null |
Returns 201 · Transaction
account_id integer · required | The real account the transaction is on. |
amount Money · required | Negative when money left the account or debt grew, positive when money arrived or debt shrank. In the ledger's base currency. |
category_id integer | null · required | The income or expense account it is filed under. Null for a transfer between the ledger's own accounts. |
counterparty | Who is on the other end. Null for transfers and unrecognized descriptions. |
created_at datetime · required | |
date date · required | |
description string · required | What the bank or the author called it. |
id integer · required | The journal entry id. The same id the app's transaction page uses. |
ignored boolean · required | Set aside by the user: listed, but left out of spending totals. |
is_transfer boolean · required | |
lines | |
memo string | null · required | |
purpose string · required | personal or business. |
source string · required | Where it came from: plaid, import, manual, assistant, … |
statement_line string | null · required | The line as the bank printed it on the statement (SQ *BLUE BOTTLE 0412 OAKLAND CA), which search also matches. Null on an entry nobody imported. |
updated_at datetime · required |
curl -X POST "https://api.lumaledger.app/v1/transactions" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"date": "2026-09-01",
"description": "…",
"lines": [
{
"account_id": 1,
"amount": "42.50",
"direction": "debit"
}
]
}'/v1/transactions/{transaction_id}Delete a transaction
Delete a hand-written transaction. Imported ones cannot be deleted
(the next sync would bring them back); set ignored instead.
Parameters
transaction_id integer · path · required | |
X-Organization-Id string | null · header |
Returns 204 with no body.
curl -X DELETE "https://api.lumaledger.app/v1/transactions/{transaction_id}" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/transactions/{transaction_id}Get a transaction
One transaction by its id (the journal entry id).
Parameters
transaction_id integer · path · required | |
X-Organization-Id string | null · header |
Returns 200 · Transaction
account_id integer · required | The real account the transaction is on. |
amount Money · required | Negative when money left the account or debt grew, positive when money arrived or debt shrank. In the ledger's base currency. |
category_id integer | null · required | The income or expense account it is filed under. Null for a transfer between the ledger's own accounts. |
counterparty | Who is on the other end. Null for transfers and unrecognized descriptions. |
created_at datetime · required | |
date date · required | |
description string · required | What the bank or the author called it. |
id integer · required | The journal entry id. The same id the app's transaction page uses. |
ignored boolean · required | Set aside by the user: listed, but left out of spending totals. |
is_transfer boolean · required | |
lines | |
memo string | null · required | |
purpose string · required | personal or business. |
source string · required | Where it came from: plaid, import, manual, assistant, … |
statement_line string | null · required | The line as the bank printed it on the statement (SQ *BLUE BOTTLE 0412 OAKLAND CA), which search also matches. Null on an entry nobody imported. |
updated_at datetime · required |
curl -X GET "https://api.lumaledger.app/v1/transactions/{transaction_id}" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN"/v1/transactions/{transaction_id}Update a transaction
Correct a transaction's description, date or memo, refile it under
another category, mark it a transfer between two of the ledger's own
accounts (or take that back), or set it aside from spending totals.
Only the fields sent change. Refiling or marking an imported
transaction re-posts its entry, so the returned transaction may carry a
new id.
Parameters
transaction_id integer · path · required | |
X-Organization-Id string | null · header |
Body · TransactionUpdate
category_id integer | null | Refile under this income or expense account. May give the transaction a new id (the entry is re-posted); the response carries it. A transaction marked as a transfer is un-marked first; a transfer the ledger paired from both of its sides cannot be refiled. |
date date | null | |
description string | null | |
ignored boolean | null | Leave it out of spending totals (imported transactions only). |
memo string | null | Null clears it. |
stop_transfer_rule boolean | With transfer_account_id: null: also stop the counterparty rule that files this payee as a transfer. What it already marked stays marked. Default: false. |
transfer_account_id integer | null | Mark it a transfer between the account it is on and this other balance-sheet account of the ledger's (see accounts.list), so it leaves income and spending. null takes a mark back and lets the categorizer file it. Imported transactions only; not with category_id. Re-posts the entry, so the response may carry a new id. Taking back a mark that a counterparty rule makes is refused with a 422 naming the rule, since the rule would mark it again at once: send stop_transfer_rule to stop the rule too, or category_id to file just this one. |
Returns 200 · Transaction
account_id integer · required | The real account the transaction is on. |
amount Money · required | Negative when money left the account or debt grew, positive when money arrived or debt shrank. In the ledger's base currency. |
category_id integer | null · required | The income or expense account it is filed under. Null for a transfer between the ledger's own accounts. |
counterparty | Who is on the other end. Null for transfers and unrecognized descriptions. |
created_at datetime · required | |
date date · required | |
description string · required | What the bank or the author called it. |
id integer · required | The journal entry id. The same id the app's transaction page uses. |
ignored boolean · required | Set aside by the user: listed, but left out of spending totals. |
is_transfer boolean · required | |
lines | |
memo string | null · required | |
purpose string · required | personal or business. |
source string · required | Where it came from: plaid, import, manual, assistant, … |
statement_line string | null · required | The line as the bank printed it on the statement (SQ *BLUE BOTTLE 0412 OAKLAND CA), which search also matches. Null on an entry nobody imported. |
updated_at datetime · required |
curl -X PATCH "https://api.lumaledger.app/v1/transactions/{transaction_id}" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'/v1/transactions/categorizeCategorize transactions in bulk
File up to 200 transactions under one category in a single step.
Nothing moves if any of them cannot be filed there (an income account
for a purchase, say); ids that are not in this ledger, and transfers,
which have no category, are returned in skipped.
Parameters
Idempotency-Key string | null · header | Any unique string (a UUID is ideal). A retry with the same key returns the first attempt's response instead of doing the work twice. Keys are kept for 24 hours. |
X-Organization-Id string | null · header |
Body · CategorizeRequest
category_id integer · required | The income or expense account to file them under. |
transaction_ids array of integer · required |
Returns 200 · CategorizeResult
moved | |
skipped array of integer · required | |
updated integer · required |
curl -X POST "https://api.lumaledger.app/v1/transactions/categorize" \
-H "Authorization: Bearer $LUMALEDGER_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"category_id": 1,
"transaction_ids": [
1
]
}'Objects
CategorizeRequest
Fields
category_id integer · required | The income or expense account to file them under. |
transaction_ids array of integer · required |
CategorizeResult
Fields
moved | |
skipped array of integer · required | |
updated integer · required |
Money
An amount and its currency. `amount` is a base-10 string with two
decimal places and an optional leading minus sign. Parse it with a
decimal type, not a float.
Fields
amount string · required | Pattern: ^-?\d+\.\d{2}$. |
currency string · required | ISO 4217 code. Pattern: ^[A-Z]{3}$. |
MovedTransaction
Fields
from_id integer · required | |
to_id integer · required | The id the transaction has now (re-posting may replace it). |
Transaction
A transaction: one balanced journal entry, read from the side of the real account (bank, card, loan) it moved money in.
Fields
account_id integer · required | The real account the transaction is on. |
amount Money · required | Negative when money left the account or debt grew, positive when money arrived or debt shrank. In the ledger's base currency. |
category_id integer | null · required | The income or expense account it is filed under. Null for a transfer between the ledger's own accounts. |
counterparty | Who is on the other end. Null for transfers and unrecognized descriptions. |
created_at datetime · required | |
date date · required | |
description string · required | What the bank or the author called it. |
id integer · required | The journal entry id. The same id the app's transaction page uses. |
ignored boolean · required | Set aside by the user: listed, but left out of spending totals. |
is_transfer boolean · required | |
lines | |
memo string | null · required | |
purpose string · required | personal or business. |
source string · required | Where it came from: plaid, import, manual, assistant, … |
statement_line string | null · required | The line as the bank printed it on the statement (SQ *BLUE BOTTLE 0412 OAKLAND CA), which search also matches. Null on an entry nobody imported. |
updated_at datetime · required |
TransactionCounterparty
Fields
key string · required | Stable key of the merchant or person on the other end. |
name string · required |
TransactionCreate
A hand-written journal entry. Debits must equal credits.
Fields
date date · required | |
description string · required | |
lines | |
memo string | null |
TransactionLine
One side of the double entry.
Fields
account_id integer · required | |
amount Money · required | Always positive; direction says which side. |
direction string · required | debit or credit. |
TransactionLineInput
Fields
account_id integer · required | An account in this ledger (see accounts.list). |
amount string · required | Positive decimal string, at most two decimal places: "42.50". Pattern: ^\d{1,12}(\.\d{1,2})?$. |
direction string · required | debit or credit. Pattern: ^(debit|credit)$. |
TransactionList
A page of transactions, newest first.
Fields
data | |
has_more boolean · required | |
next_cursor string | null · required |
TransactionUpdate
Only the fields sent are changed.
Fields
category_id integer | null | Refile under this income or expense account. May give the transaction a new id (the entry is re-posted); the response carries it. A transaction marked as a transfer is un-marked first; a transfer the ledger paired from both of its sides cannot be refiled. |
date date | null | |
description string | null | |
ignored boolean | null | Leave it out of spending totals (imported transactions only). |
memo string | null | Null clears it. |
stop_transfer_rule boolean | With transfer_account_id: null: also stop the counterparty rule that files this payee as a transfer. What it already marked stays marked. Default: false. |
transfer_account_id integer | null | Mark it a transfer between the account it is on and this other balance-sheet account of the ledger's (see accounts.list), so it leaves income and spending. null takes a mark back and lets the categorizer file it. Imported transactions only; not with category_id. Re-posts the entry, so the response may carry a new id. Taking back a mark that a counterparty rule makes is refused with a 422 naming the rule, since the rule would mark it again at once: send stop_transfer_rule to stop the rule too, or category_id to file just this one. |