Customer Invoices
Reference for the customer_invoices resource. Requests follow the conventions in
Requests and Responses; fields you
receive and may write are filtered by your user's permissions, so responses can
contain a subset of the fields below.
Operations
| Operation | Request |
|---|---|
| List | GET /{profile}/user/v4/customer_invoices |
| Fetch | GET /{profile}/user/v4/customer_invoices/{id} |
| Create | POST /{profile}/user/v4/customer_invoices |
| Update | PATCH /{profile}/user/v4/customer_invoices/{id} |
| Delete | DELETE /{profile}/user/v4/customer_invoices/{id} |
How it works
customer_invoices is the invoice header for a customer. Full CRUD plus a list
endpoint. Amounts are not on the header — they live on invoice_line_items
(a separate resource), so an invoice can exist with zero line items and a total
of 0.00. This mirrors v1/v3 exactly: create the header, then add line items.
A row belongs to a customer through entity_id (with entity_type fixed to
customer for this resource), and its permission location is that customer's:
everything is gated by the Customer Invoices permission at the customer's
location (leads use the lead-invoices permission).
Creating
POST /customer_invoices requires:
| Field | Required | Notes |
|---|---|---|
entity_id |
Yes | The customer this invoice bills. It's the record's permission context. |
type |
Yes | One of invoice, quote, refund_receipt, credit_memo. |
sale_date |
Conditional | YYYY-MM-DD. Required for an invoice and a refund_receipt; optional for a quote. |
due_date |
Conditional | YYYY-MM-DD. Required for an invoice; optional for a quote / refund_receipt. |
Date requirements follow the type (matching the app): an invoice needs both
sale_date and due_date; a refund_receipt needs sale_date; a quote needs
neither (an omitted date is stored as the empty 0000-00-00 sentinel). entity_type
is fixed to customer (you don't send it — lead-company invoices aren't part of
this resource). Optional: po_number, sold_by_user_id,
invoice_term_id, internal_note, external_note, mailing_address,
mailing_name. external_note auto-fills from the company default when omitted.
curl -X POST "https://portal.securitytrax.com/acme/user/v4/customer_invoices" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"entity_id":100,"type":"invoice","sale_date":"2026-07-14","due_date":"2026-08-14","po_number":"PO-1"}}}'
Type rules (ported from v1/v3): a quote or refund_receipt must have
invoice_term_id = 0; a credit_memo is only valid for a customer (always true
here). To add amounts, create invoice_line_items against the invoice.
Line items inline (optional)
You may send the line items in the same create as an embedded
invoice_line_items relationship, instead of POSTing each to the
invoice_line_items endpoint afterward. Each embedded line is created against the
new invoice (its amounts computed from quantity × unit_price, as on the
invoice_line_items resource). It's all-or-nothing: if any line is invalid, the
whole create is rejected (422) and nothing is saved — not the header, not any line.
Sending them separately after the header still works exactly as before; embedding is
just a convenience.
curl -X POST "https://portal.securitytrax.com/acme/user/v4/customer_invoices" \
-H "Authorization: Bearer stx_acme_..." \
-H "Content-Type: application/json" \
-d '{"data":{"attributes":{"entity_id":100,"type":"invoice","sale_date":"2026-07-14","due_date":"2026-08-14"},"relationships":{"invoice_line_items":{"data":[{"attributes":{"quantity":"2","unit_price":"49.99"},"relationships":{"invoice_billable_item":{"data":{"type":"invoice_billable_items","id":5}}}}]}}}}'
Managed (read-only) fields
status, entity_type, invoice_recurring_id, and credit_memo_payment_id are
returned on read but not writable — a PATCH that sets them returns 422.
Change the lifecycle with the DELETE verb (below), not by writing status.
combo_id and bill_with_parent are model-managed and not exposed for writing.
Deleting
DELETE /customer_invoices/{id} soft-deletes the invoice and, matching the app:
- cascades — removes the invoice's line items and payment-to-invoice links,
- for a credit memo, is blocked if the credit memo has been applied to
other invoices (
422), and otherwise removes its linked payment, - queues the change for external accounting sync (async).
Afterward every read of the invoice returns 404.
Side-effects
Creating or updating an active customer invoice queues it for external accounting
sync (NetSuite/QuickBooks/etc.) — asynchronous, the same as the in-app screens.
Converting a quote to an invoice (a type change) triggers the conversion
workflow.
Listing
GET /customer_invoices returns active customer invoices (excludes deleted and
recurring templates) at locations where you can view customer invoices. Filters:
| Filter | Match |
|---|---|
entity_id |
exact — one customer's invoices |
type |
invoice | quote | refund_receipt | credit_memo |
sold_by_user_id |
exact |
sale_date_from / _to, due_date_from / _to, created_at_from / _to, updated_at_from / _to |
inclusive date/datetime ranges |
Sortable: id, entity_id, type, sale_date, due_date, created_at,
updated_at. Add ?count_only=true for just the total.
Fields
Fields are grouped by the permission that gates them. A group you may not view
is absent from responses; a group you may not write is rejected with 422 when
sent in a write.
Invoice
View: customers — Customer Invoices at the record's location; leads — Lead Invoices. Create: customers — Customer Invoices at the record's location; leads — Lead Invoices. Update: customers — Customer Invoices at the record's location; leads — Lead Invoices.
| Field | Type | Writable | Validation |
|---|---|---|---|
entity_id |
integer (nullable) | Create, update | Required on create; min 0 |
type |
string (nullable) | Create, update | Required on create; one of: invoice, quote, refund_receipt, credit_memo |
sale_date |
string (nullable) | Create, update | — |
due_date |
string (nullable) | Create, update | — |
invoice_term_id |
integer (nullable) | Create, update | min 0 |
po_number |
string (nullable) | Create, update | max length 255 |
sold_by_user_id |
integer (nullable) | Create, update | min 0 |
internal_note |
string (nullable) | Create, update | — |
external_note |
string (nullable) | Create, update | — |
mailing_address |
string (nullable) | Create, update | — |
mailing_name |
string (nullable) | Create, update | max length 1024 |
bill_with_parent |
boolean (nullable) | Read-only | — |
Managed
View: customers — Customer Invoices at the record's location; leads — Lead Invoices.
| Field | Type | Writable | Validation |
|---|---|---|---|
entity_type |
string (nullable) | Read-only | one of: customer, lead_company |
status |
string (nullable) | Read-only | one of: active, deleted, recurring |
invoice_recurring_id |
integer (nullable) | Read-only | min 0 |
credit_memo_payment_id |
integer (nullable) | Read-only | min 0 |
Pagination
The list endpoint uses client-controlled offset pagination: ?page= (1-based) and
?per_page= (default 25, max 100). The response mirrors
meta.pagination (page, per_page, total, last_page) and sends an RFC5988
Link header; follow rel="next" to walk pages. See
Pagination.
Filters
The list endpoint accepts these query-param filters: entity_id, type, sold_by_user_id, sale_date_from, sale_date_to, due_date_from, due_date_to, created_at_from, created_at_to, updated_at_from, updated_at_to.
An unsupported filter parameter returns 422. See
Filtering collections
for matching semantics.
Sorting
GET .../customer_invoices?sort= orders the list by: id, entity_id, type, sale_date, due_date, created_at, updated_at.
Prefix a field with - for descending; comma-separate for tie-breakers. An
unsupported field returns 422. See
Sorting collections.
Related
- Requests and Responses — envelope, errors, pagination, and rate limits.
- Authentication — tokens and the
Authorizationheader.