Skip to navigation

Line Items

Learn about how Ottimate manages invoice line items

Overview

Line items are individual entries within an invoice that detail:

  • Product or service descriptions
  • Quantities
  • Unit prices
  • Line item costs

Each line item can be coded with its own dimensions, allowing for granular expense tracking and reporting.

Reading line items

Line items are returned by the Invoice Details endpoint — there is no standalone line-items endpoint:

GET /v1/invoices/{id}

Where {id} is the Ottimate generated invoice ID.

GET /v1/invoices (the list endpoint) does not include line items. Fetch the invoice detail endpoint for each invoice whose items you need.

Writing line items

Line items are created and updated through the items array on PATCH /v1/invoices/{id}:

  • Update an existing item — include its id
  • Create a new item — omit id
{
"items": [
{
"id": 456,
"quantity": 10,
"price": 50.00
},
{
"name": "New Line Item",
"quantity": 5,
"price": 20.00
}
]
}

The write field is price; the read field is unit_price. GET /v1/invoices/{id} returns each item’s per-unit cost as unit_price, but PATCH /v1/invoices/{id} expects it as price. Copying an item straight from a GET response into a PATCH body will silently leave the price unchanged, because unit_price is not a recognised write field.

Item fields

FieldWrite nameDescription
Item IDidExisting item ID to update. Omit to create a new item.
Inventory itemitemOttimate inventory item ID to link this line to.
DescriptionnameLine item description. Max 200 characters. Required when creating a new item.
SKUskuVendor SKU or item code. Max 200 characters.
QuantityquantityNumber of units. Required when creating a new item.
Unit pricepricePer-unit cost. Required when creating a new item. Returned as unit_price on reads.
Taxableis_taxedWhether this line is taxed.
DimensionsdimensionsItem-level dimension mappings.
Custom fieldscustom_fieldsItem-level custom metadata. Requires account-level custom field configuration.

Item-level dimensions

Dimensions are passed as key-value pairs keyed by dimension type (e.g. DEPARTMENT, CLASS). Each value must be a plain string — the erp_dimension_id from GET /v1/dimensions:

{
"items": [
{
"id": 456,
"dimensions": {
"DEPARTMENT": "erp_dim_dept123",
"CLASS": null
}
}
]
}

Item-level dimensions merge with what is already stored:

  • Set a value to a string to add or replace that dimension
  • Set a value to null to remove only that dimension
  • Pass {} or omit the field entirely to leave all existing dimensions unchanged

Item-level and header-level dimensions behave differently. Item dimensions merge, but header dimensions on the same request replace the entire stored set — passing {} at the header level clears all header dimensions. See Updating invoices.

Custom fields

Item custom_fields replace the stored object — any key you omit is reset to its configured default value. Custom fields must be configured for your account before use; sending them without a configured spec, or sending an unrecognised key, returns a 400 error.

Partial item failures

PATCH /v1/invoices/{id} still returns 200 when some items fail. Check items_processing_result in the response to see which succeeded:

{
"items_processing_result": {
"success": { "0": 12345 },
"failure": { "1": "Item with id 99999 not found" },
"status": "partial_success"
}
}

The keys in success and failure are the positions of the items in your request array ("0" is the first item you sent), and the values in success are the resulting Ottimate item IDs.

statusMeaning
successEvery item in the request was applied.
partial_successAt least one item was applied and at least one failed.
failureEvery item failed.
no_items_providedThe request contained no items array. Only seen on POST /v1/invoices.

The field is named differently on create and update. POST /v1/invoices returns this object as items; PATCH /v1/invoices/{id} returns it as items_processing_result. The contents are the same shape.

A common failure when creating items on an invoice whose vendor has not been mapped yet:

{
"items_processing_result": {
"success": {},
"failure": {
"0": "Failed to create an item because the invoice vendor is unmapped.",
"1": "Item with id 99999999 not found"
},
"status": "failure"
}
}

A 200 response does not mean every line item was written. All three items_processing_result values — including failure, where nothing was applied — are returned with HTTP 200. Always inspect items_processing_result.status rather than relying on the status code alone.