Transactions
Transactions represent bank transactions synced from Plaid, imported from Ramp, Xero or QuickBooks, uploaded from CSV, or created manually. They are the core data type for bank feeds, categorization, and reconciliation.
Transaction Lifecycle
- Sync — Transactions arrive from a connected bank (
source: plaid), a card program (ramp), a migration (xero,quickbooks), a CSV upload (bulk_upload) or the API (manual) - Clean — Merchant names are normalized into
counterpartyautomatically - Categorize — AI, bank rules, or manual assignment to an expense/revenue ledger via the transaction's journal entry
- Review — A user confirms the categorization (
review_status: reviewed) - Reconcile — Matched against bank statements (
reconciled: true) — see Reconciliation
List Transactions
curl "https://api.ondayzero.com/api/v1/transactions?limit=25&only_uncategorized=true&start_date=2026-03-01" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Filter Parameters
| Parameter | Type | Description |
|---|---|---|
start_date / end_date |
date | Transaction date range |
ledger_id |
UUID | Bank account ledger the transaction belongs to |
opposing_ledger_id |
UUID | Category ledger (the expense/revenue side of the journal entry) |
source_account_id |
UUID[] | Plaid source account(s) |
search |
string | Case-insensitive match on description or counterparty |
amount_direction |
string | inflow (money in) or outflow (money out) |
only_uncategorized |
boolean | Only transactions with no category yet |
missing_counterparty |
boolean | Only transactions with no counterparty |
review_status |
string | unreviewed, reviewed, or comma-separated |
reconciled |
boolean | true only reconciled, false only unreconciled |
posted_status |
string | posted (cleared) or pending (unsettled authorizations) |
source |
string | plaid, ramp, bulk_upload, manual, xero, quickbooks, or comma-separated |
tag_id / journal_entry_id / id |
UUID | Exact-match filters |
Plus the standard pagination parameters.
Key Fields
| Field | Type | Description |
|---|---|---|
amount |
integer | Amount in cents (positive = money in, negative = money out) |
currency |
string | ISO currency code |
datetime |
datetime | When the transaction occurred |
description |
string | Raw bank description |
counterparty |
string | Cleaned merchant / payee name |
ledger_id / ledger_name |
UUID / string | The bank account ledger |
journal_entry_id / journal_entry |
UUID / object | The double-entry record that carries the categorization |
opposing_line_entries |
array | The category side(s) of that journal entry — where the money was booked |
posted_status |
string | not_posted, posted, deleted |
review_status |
string | unreviewed, reviewed |
reconciled |
boolean | Matched to a bank statement |
categorization_method |
string | ai, rules, similarity, transfer_between_accounts, user, historical, global_pattern, uncategorized |
source |
string | Where the transaction came from (see filters) |
invoice_ids / bill_ids |
UUID[] | Invoices or bills this transaction pays |
Create a Transaction
For bank accounts that aren't connected to a feed:
curl -X POST "https://api.ondayzero.com/api/v1/transactions" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"amount": -5000,
"currency": "USD",
"datetime": "2026-03-15T00:00:00Z",
"description": "Office supplies",
"source_account_id": "SOURCE_ACCOUNT_UUID"
}'POST /api/v1/transactions/bulk creates many at once. For CSV/Excel statements use the upload flow: POST /api/v1/transactions/bulk-upload/headers (discover the columns), …/bulk-upload/preview, then …/bulk-upload with a column_mapping.
Categorization
Every transaction is categorized through its journal entry — the bank ledger on one side, the category ledger on the other. You rarely build that entry yourself:
- Recategorize one or many:
PATCH /api/v1/transactions/batch/categorywith{"transaction_ids": [...], "ledger_id": "CATEGORY_LEDGER_UUID"}moves the opposing line entries to the new ledger. - Everything for a merchant:
POST /api/v1/transactions/recategorize-by-counterpartywith{"counterparty": "Uber", "ledger_id": "..."}. - Let AI do it:
POST /api/v1/transactions/categorize-allruns the full categorization workflow (bank rules → history → LLM) over all uncategorized transactions, auto-applies high-confidence results, and returns a workflow ID immediately.POST /api/v1/transactions/suggest-categoriesreturns suggestions without applying them. - Split across categories:
PATCH /api/v1/transactions/{transaction_id}/split:
curl -X PATCH "https://api.ondayzero.com/api/v1/transactions/{transaction_id}/split" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"split": [
{ "ledger_id": "MEALS_LEDGER_UUID", "allocation_type": "percent", "value": 7000 },
{ "ledger_id": "TRAVEL_LEDGER_UUID", "allocation_type": "remainder" }
]
}'allocation_type is percent (value in basis points — 7000 = 70%), amount (cents) or remainder. Each leg may carry project_id, class_id or location_id dimensions.
If you do need a hand-built journal entry (for a transaction with no bank feed, an accrual, a correction), see Journal Entries.
Review and Reconcile
PATCH /api/v1/transactions/batch/review-statusmarks transactions reviewed;POST /api/v1/transactions/batch/mark-reviewed-by-perioddoes it for a whole period.PATCH /api/v1/transactions/batch/reconciliation-statussetsreconciledin bulk.PUT /api/v1/transactions/{transaction_id}updates a single transaction'scounterparty,description,review_status,reconciled,personalflag, and so on.GET /api/v1/transactions/{transaction_id}/suggested-matcheslists invoices and bills this transaction probably pays; link them from the Invoices and Bills payment endpoints.
Delete and Restore
DELETE /api/v1/transactions/{transaction_id} hides a bank-fed transaction (soft delete; POST …/restore brings it back) and removes a manual one. DELETE /api/v1/transactions/by-date-range?start_date=…&end_date=… clears an imported range — preview with GET …/by-date-range/preview first.