Welcome to the Coperniq API release notes. This section highlights noteworthy changes across endpoints, schemas, and docs.

Recent highlights

  • New: AHJs — GET /ahjs (search, filter, and lat+lng geo lookup), GET /ahjs/{id}, and PATCH /ahjs/{id} to update custom property values. v2 mirrors these under /v2 with the standard success envelope.
  • Updated: GET /properties — now documents the ahj record type (custom AHJ properties only) and adds an isCustom boolean to every property to distinguish custom columns from built-in standard ones.
  • New: Sections — line items on projects, invoices, and bills can now be grouped into named sections (matching quotes and work orders); read responses expose sectionName per line item.
  • New: Vendors — full CRUD via GET/POST /vendors, GET/PATCH/DELETE /vendors/{vendorId}, GET /vendors/search, and many-to-many project linking via POST/DELETE /projects/{projectId}/vendors/{vendorId}. Vendor-specific fields: vendorType (enum), website, and projectIds.
  • New: Labels — GET /labels (filter by type), POST /labels, GET /labels/{labelId}. type is WORK (work orders) or ASSET. v2 mirrors these under /v2 with the standard success envelope.
  • New: Assets — GET /assets (filter by account_id), POST /assets, GET/PATCH /assets/{assetId} (set isArchived: true via PATCH to archive). v2 mirrors these under /v2 with the standard success envelope.

Looking for a specific date? See the entries below.

Line item sections for projects, invoices, and bills

Line items can now be grouped into named sections — the same grouping you see on quotes and in the Coperniq UI — across project line items, invoices, and bills.

Sections on write

PUT /projects/{projectId}/line-items, POST/PATCH /invoices, and POST/PATCH /bills accept a sections array alongside (or instead of) lineItems:

1{
2 "lineItems": [ { "catalogItemId": 101, "quantity": 1, "unitCost": 10, "unitPrice": 20 } ],
3 "sections": [
4 { "name": "Labor", "lineItems": [ { "catalogItemId": 202, "quantity": 4, "unitCost": 30, "unitPrice": 60 } ] }
5 ]
6}
  • lineItems and sections may be combined in one request: top-level lineItems stay ungrouped, sections carry named groups.
  • A section’s name may be omitted or null for an unnamed group.
  • A catalogItemId may appear at most once across the flattened set (lineItems + every section’s items); duplicates are rejected with 400.

Section name on read

Every line item in project, invoice, bill, and quote responses now includes sectionName — the name of the section the item belongs to, or null when the item is ungrouped. (sectionId is not returned; replacing all line items is the only update path, so the name is the grouping signal.)

Invoice creation: status and issueDate

  • status is now optional and defaults to DRAFT; issueDate is now optional. Omit both to create a draft invoice.
  • A finalized status (SENT, PARTIALLY_PAID, PAID) requires an issueDate. An issueDate without a finalized status is ignored (the invoice is created as a draft).
  • Lifecycle statuses (DECLINED, OVERDUE) cannot be set at creation and are rejected with 400.
  • description is fully optional — invoice creation no longer fails when it is omitted.

Invoice updates: calculationMethod is fixed at creation

PATCH /invoices/{invoiceId} no longer accepts calculationMethod (matching bills, where this was already the case). Sending it returns 400. percentage cannot be combined with lineItems/sections in the same update.

Validation tightening

  • calculationMethod: PERCENTAGE invoices and bills now reject lineItems (previously they were silently ignored), in addition to the existing sections rejection.
  • PUT /projects/{projectId}/line-items validation errors now surface the specific problem (e.g. the duplicate-catalog-item message) instead of a generic “Invalid input”.

Deprecation

Passing a bare top-level array of line items to PUT /projects/{projectId}/line-items is deprecated. It is still accepted for backwards compatibility but will not be supported in a future version — use the object form with lineItems and/or sections.