Fixed Assets
Fixed assets represent long-term tangible property (equipment, vehicles, furniture, etc.) that depreciates over time. This feature requires the Fixed Assets add-on; without it every /api/v1/fixed-assets call returns 403 BILLING_003.
Asset Lifecycle
| Status | Description |
|---|---|
draft |
Recorded but not yet in service — no depreciation. Every new asset starts here |
active |
In service and depreciating |
fully_depreciated |
Book value has reached salvage value (set automatically when a posting takes it there) |
disposed |
Sold, traded, scrapped, lost or donated |
Asset Categories
Organize assets by category with default depreciation settings and the ledgers each posting should hit:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/categories" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Computer Equipment",
"default_useful_life_months": 36,
"default_depreciation_method": "straight_line",
"default_salvage_percent": 10,
"asset_ledger_id": "ASSET_LEDGER_UUID",
"accumulated_depreciation_ledger_id": "ACCUM_DEPR_LEDGER_UUID",
"depreciation_expense_ledger_id": "DEPR_EXPENSE_LEDGER_UUID"
}'All ledger IDs are optional; the system Fixed Assets, Accumulated Depreciation and Depreciation Expense ledgers are used when a category does not set them. default_useful_life_months is 1-600 (default 60) and default_salvage_percent is 0-100 (default 0).
Depreciation methods:
| Method | Monthly amount |
|---|---|
straight_line |
(cost - salvage) / useful life in months; the final month absorbs any rounding remainder so the schedule lands exactly on salvage |
declining_balance |
Current book value x (1 / life in years) / 12, drawn down to salvage in the last month |
double_declining |
Current book value x (2 / life in years) / 12, drawn down to salvage in the last month |
units_of_production |
Not calendar-driven: no schedule is projected and no entries are queued (set total_expected_units) |
Seed the standard categories (Equipment, Vehicles, Furniture & Fixtures, Computer Equipment, Buildings, Leasehold Improvements, Software, Machinery, Office Equipment, Land Improvements). Categories that already exist by name are skipped, and the response lists only the ones created:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/categories/seed-defaults" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"GET /api/v1/fixed-assets/categories lists them as {"categories": [...], "count": N} (each with asset_count); GET /api/v1/fixed-assets/categories/{category_id} fetches one. PATCH / DELETE /api/v1/fixed-assets/categories/{category_id} edit or remove one; a category that still has assets cannot be deleted (400).
Create a Fixed Asset
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "MacBook Pro M4",
"category_id": "CATEGORY_UUID",
"original_cost": 349900,
"purchase_date": "2026-03-01",
"useful_life_months": 36,
"salvage_value": 30000,
"depreciation_method": "straight_line",
"serial_number": "C02XYZ123",
"vendor_id": "VENDOR_UUID"
}'
original_costandsalvage_valueare in cents.349900= $3,499.00.
Response data (abbreviated):
{
"success": true,
"data": {
"id": "019ab37c-9d11-7000-8000-000000000001",
"name": "MacBook Pro M4",
"status": "draft",
"original_cost": 349900,
"salvage_value": 30000,
"useful_life_months": 36,
"depreciation_method": "straight_line",
"purchase_date": "2026-03-01",
"in_service_date": null,
"accumulated_depreciation": 0,
"book_value": 349900,
"monthly_depreciation_amount": 8886
}
}Required: name, original_cost, purchase_date. useful_life_months (1-600) defaults to 60, salvage_value to 0 (it cannot exceed original_cost), depreciation_method to straight_line. These defaults come from the request schema: send the values you want rather than relying on the category's defaults. Optional: description, asset_number (unique per business, 409 if reused), location, notes, total_expected_units (for units_of_production). The asset is always created as a draft; passing in_service_date records the date but does not start depreciation. Call Place in Service to activate it.
Capitalize from bank transactions
If the purchase already sits in a bank feed, turn those transactions into an asset instead of re-typing the cost:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/from-transactions" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"name": "Delivery van",
"ledger_id": "VEHICLES_LEDGER_UUID",
"transaction_ids": ["TRANSACTION_UUID"],
"useful_life_months": 84,
"auto_place_in_service": true
}'The cost basis is the sum of the transactions' absolute amounts; all of them must already be assigned to ledger_id (directly, or through the category leg of their journal entry), otherwise 400. salvage_value must be less than the cost basis. The purchase date is the earliest transaction date, and in_service_date defaults to the latest. With auto_place_in_service (default true) the asset is activated immediately, a reclassification journal entry is posted, and its depreciation is queued; set it to false to leave a draft. The asset is grouped under a category named after the ledger (created if needed). The response is {"asset": {...}, "schedule": {...}}. POST /api/v1/fixed-assets/suggest-capitalization asks the AI which recent transactions look like capital purchases.
List Fixed Assets
curl "https://api.ondayzero.com/api/v1/fixed-assets?status=active" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"| Parameter | Type | Description |
|---|---|---|
status |
string | draft, active, fully_depreciated, disposed (in_service is accepted as an alias for active) |
category_id |
UUID | Filter by asset category |
search |
string | Case-insensitive match on the asset name |
The response is {"assets": [...], "count": N} with every matching asset. This endpoint does not return next_cursor, so it is not cursor-paginated like other lists. GET /api/v1/fixed-assets/{asset_id} returns one asset.
Each asset in the response includes computed book_value, accumulated_depreciation, depreciable_amount, monthly_depreciation_amount and remaining_life_months.
Place in Service
Start depreciation on a draft asset (any other status is a 400). in_service_date is required and cannot be earlier than the purchase date:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/{asset_id}/place-in-service" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{"in_service_date": "2026-03-15"}'This sets the asset to active, posts a capitalization journal entry dated the in-service date (debit the category's asset ledger or the system Fixed Assets ledger, credit Accounts Payable), and queues the whole depreciation schedule as pending entries (see Scheduled depreciation below).
Depreciation
View Schedule
curl "https://api.ondayzero.com/api/v1/fixed-assets/{asset_id}/depreciation-schedule" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"The schedule has one row per month: period, period_date (first of the month), beginning_book_value, depreciation_amount, accumulated_depreciation and ending_book_value. It is empty for units_of_production. GET /api/v1/fixed-assets/{asset_id}/depreciation-entries returns the entries recorded or queued so far (status is pending, posted or reversed), and GET /api/v1/fixed-assets/depreciation-matrix?start_date=…&end_date=… gives a month-by-asset grid across the whole register (periods, rows with per-month amount_cents, posted_cents and scheduled_cents, and column_totals; include_posted and include_scheduled default to true).
Preview Period Depreciation
See what depreciation entries would be generated for a specific period. period_date is normalized to the first day of its month, so 2026-03-31 and 2026-03-01 are the same period:
curl "https://api.ondayzero.com/api/v1/fixed-assets/depreciation-preview?period_date=2026-03-31" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID"Run Depreciation
Post depreciation for a period — all active assets, or only asset_ids (assets that are not active are reported in errors). Months an asset already has a posted entry for, assets not yet in service, and fully depreciated assets are skipped:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/run-depreciation" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{"period_date": "2026-03-31", "create_journal_entries": true}'Each posting debits Depreciation Expense and credits Accumulated Depreciation (the category's ledgers, or the system defaults), dated the first of the month. With create_journal_entries: false the depreciation entries are recorded without a journal entry. The response has period_date, assets_processed, total_depreciation (cents), entries_created, journal_entries_created and errors. A queued entry for the period is posted at its queued amount; the amount never exceeds what is left above salvage.
Scheduled depreciation
DayZero can also queue every future depreciation entry up front and post each one when its date arrives:
POST /api/v1/fixed-assets/generate-schedulesqueues draft entries for active assets that have none (a backfill; creates no journal entries).GET /api/v1/fixed-assets/scheduled-journal-entries?through_date=…&limit=200shows what is queued (limit1-1000), each entry with its debit/creditlinesand astatusofscheduled(future) ordue, pluscount,total_count,due_count,total_amount_centsandtruncated.POST /api/v1/fixed-assets/post-scheduled-depreciationwith an optional{"as_of": "2026-03-31"}posts everything due. It is idempotent — a retry cannot double-post — and skips entries for disposed assets. The response hasas_of_date,entries_due,entries_posted,entries_skipped,total_depreciationanderrors.
Dispose an Asset
Record the disposal (sale, write-off, etc.) of an asset:
curl -X POST "https://api.ondayzero.com/api/v1/fixed-assets/{asset_id}/dispose" \
-H "Authorization: Bearer dz_your_token_here" \
-H "x-business-id: YOUR_BUSINESS_ID" \
-H "Content-Type: application/json" \
-d '{
"disposal_date": "2026-06-15",
"disposal_method": "sold",
"disposal_amount": 100000,
"disposal_notes": "Sold to employee"
}'disposal_method is one of sold, traded, scrapped, lost, donated; disposal_amount (proceeds, in cents) defaults to 0. Only active or fully_depreciated assets can be disposed (a draft or already disposed asset is a 400). Gain or loss is disposal_amount minus book value. The response is {"asset": {...}, "gain_loss": -20000, "journal_entry_id": "..."}, where a positive gain_loss is a gain. The journal entry debits Accumulated Depreciation, credits the asset's cost, debits Cash for any proceeds, and books the difference to the system Gain on Disposal or Loss on Disposal ledger. Queued (pending) depreciation for the asset is removed. Disposal is irreversible — confirm the asset and amount first.
Update or Delete
PATCH /api/v1/fixed-assets/{asset_id} edits name, description, asset_number, serial_number, location, notes, category_id, vendor_id, salvage_value, useful_life_months, depreciation_method and total_expected_units. Cost, purchase date and in-service date cannot be changed. A disposed asset cannot be updated (400). Changing salvage value, useful life or method re-cuts the queued entries; already-posted periods are left as they are.
DELETE /api/v1/fixed-assets/{asset_id} removes an asset that has no posted depreciation. Add ?force=true to also remove its depreciation entries and every journal entry posted for it (capitalization, depreciation, disposal) — for assets that were set up by mistake.
Errors
| Status | code |
Cause |
|---|---|---|
403 |
BILLING_003 |
The business does not have the Fixed Assets add-on |
400 |
VALIDATION_236 |
Placing in service an asset that is not draft |
400 |
VALIDATION_153 |
in_service_date earlier than purchase_date |
400 |
VALIDATION_154 / VALIDATION_148 |
Disposing a draft asset / an asset that is already disposed |
400 |
VALIDATION_237 |
Updating a disposed asset |
400 |
VALIDATION_155 |
Deleting an asset with posted depreciation without force=true |
400 |
VALIDATION_147 |
Deleting a category that still has assets |
400 |
VALIDATION_395 / VALIDATION_396 |
from-transactions: a transaction is not assigned to ledger_id, or the cost basis is zero or not above salvage_value |
409 |
VALIDATION_152 |
asset_number already used in this business |