List sales invoices
GEThttps://
Returns the organisation's sales invoices, newest invoice date first.
Access
- Token scope
- api:
read: sales_invoices Without it:
403 insufficient-token-scope. - Permission
- sales_invoices::
read Without it:
403 insufficient-permission. - Feature
- Needs the billing feature on your organisation.
Without it:
404 endpoint-not-found. - Rate cost
- 1 unit, read bucket.
view=detailmakes it 3. Adds: each include +1,q+2. - Also
If-None-Matchanswers304when nothing changed. Never cached:private, no-store. Unknown query parameters are refused, never ignored.
Both are checked, scope first. A token never does more than its user. How access is checked
Defaults to the summary view; view=detail adds sync_error and internal_notes and costs three read units instead of one. Search with q= over the invoice number, and pass trashed=with|only to see deleted invoices. Combine filter[invoice_date][gte] and [lte] for a period, filter[status]=draft or pending_approval for the concept and approval queues in plnnrly, and filter[sync_status]=failed for invoices the accounting sync rejected. Sorting by total or invoice number is deliberately not offered, so a money-ordered page has to be sorted client-side.
Query parameters
Unknown parameters are refused with 400, naming the parameter.
52 parameters in 7 groups
Views
Pagination
Rows per page. At most 25 when include names a to-many relation; a larger value is 400 invalid-query-parameter.
Default: 25
Filters
- =
- equals
- [in]
- any of a comma-separated list
- [null]
trueorfalse: whether it is empty- [gte][lte][lt]
- at least, at most, less than
- [ne]
- not equal
Creation timestamp. Pair with sort=id for a stable full export.
Customer the invoice is billed to.
A comma-separated list of at most 100 values.
Customer subscription the invoice was generated from. Pass [null] for invoices that were not generated from a renewal.
A comma-separated list of at most 100 values.
Date payment is due. Pass [null] for invoices with no term applied.
Whether the field is null.
Invoice date, a zone-free calendar date. Combine [gte] and [lte] for a period.
Whether the invoice was converted from a legacy invoice, and is therefore read-only.
The id of the legacy invoice this invoice was converted from, so it can be matched with GET /api/v2/invoices.
A comma-separated list of at most 100 values.
When the invoice was settled. Pass [null] for unsettled invoices.
Whether the field is null.
Project the invoice was raised for. Pass [null] for invoices raised against no project.
A comma-separated list of at most 100 values.
Lifecycle status of the invoice.
A comma-separated list of at most 100 values.
draftpending_approvalsentpaidoverduecancelled
New values may be added.
When the invoice was last handed to the sync, successfully or not.
Whether the field is null.
How far the invoice has got through the accounting sync. filter[sync_status]=failed reproduces the sync error page in plnnrly.
A comma-separated list of at most 100 values.
pendingsyncedfailedlocal
New values may be added.
When the invoice last synced successfully. Pass [null] for invoices that have never synced.
Whether the field is null.
Search
Sorting
| Key | Sorts by |
|---|---|
invoice_date | Invoice date, newest first by default. |
due_date | Date payment is due. |
synced_at | When the invoice last synced successfully. |
sync_attempted_at | When the invoice was last handed to the sync. |
paid_at | When the invoice was settled. |
id | Id, ascending. An id never changes, so use this for a stable full export. |
updated_at | Last-write timestamp; pair with the id tiebreaker for sync. |
Prefix a key with - for descending.
Includes
| Path | Adds | Cost |
|---|---|---|
customer | The customer this invoice is billed to, with their name and code. Requires the customers::read permission and a token scope covering the customers prefix. | +1 |
Other
Request headers
A correlation id of your own. It is recorded in our logs next to the server's request id but never returned: the response header always carries the server's id. A value that does not match the pattern is discarded silently, never rejected.
Response 200
Returns a page of SalesInvoiceList rows.
The rows, each a SalesInvoiceList.
per_page, next_cursor, prev_cursor, total, current_page, last_page.
self, next, prev.
Each row is a SalesInvoiceList: 28 fields.
Headers
ETag- A weak validator (
W/"…") of the rendered page. RateLimit- The IETF
httpapi-ratelimit-headersform of your remaining allowance on the tightest bucket this request touched. RateLimit-Policy- The ceiling and window of that bucket, as
<limit>;w=<seconds>. X-Request-Id- The server-generated ULID correlating this response with our logs.
Every response also carries Cache-Control, Vary, X-Content-Type-Options, X-Plnnrly-Api-Version, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Headers and versioning
The customer this invoice is billed to. Expanding it with ?include=customer additionally requires the customers::read permission and a token scope covering the customers prefix.
Customer subscription this invoice was generated from, when it was generated from a renewal.
Invoice number, allocated by the server from the organisation's yearly sequence: B-26-00001 for an invoice raised in this flow, L-1234 for one converted from a legacy invoice. It also works in the path: GET sales-invoices/B-26-00001 works. This is the field ?q= searches.
The customer's own reference, typically a purchase-order number, reproduced on the invoice.
Invoice date, a zone-free calendar date. Newest first is the default sort.
Date payment is due, a zone-free calendar date. Null when no term was applied.
Lifecycle status. Resolved by the server on create and never writable: a caller without sales_invoices::finalize creates a pending_approval invoice, and any update by such a caller returns the invoice to pending_approval.
draftpending_approvalsentpaidoverduecancelled
New values may be added.
Whether the invoice is emailed to the customer when it syncs. The email is sent through the accounting integration, so it is forced to false in an organisation with no integration configured. Writing it requires sales_invoices::finalize.
Sum of the row line totals excluding VAT, as a decimal string. Recomputed from the rows; never written directly.
2 decimal places, may be negative
Sum of the row VAT amounts, as a decimal string. Recomputed from the rows; never written directly.
2 decimal places, may be negative
Subtotal plus VAT, as a decimal string. Recomputed from the rows; never written directly.
2 decimal places, may be negative
The accounting system's own identifier for this invoice, written by the sync. Not a local id.
Sales journal the invoice is booked in, resolved from the organisation's accounting settings on create. Null in an organisation with no integration configured.
How far the invoice has got through the accounting sync. Set on create: local in an organisation with no integration configured, pending otherwise.
pendingsyncedfailedlocal
New values may be added.
Why the last sync attempt failed, verbatim from the accounting system. Null while nothing has failed.
When the invoice last synced successfully.
When the invoice was last handed to the sync, successfully or not.
When the invoice was settled. Set on create for a local invoice that is immediately definitive; otherwise written when payment is registered.
Whether this invoice was converted from a legacy invoice. Such an invoice is read-only: PATCH and DELETE answer 409 state-conflict with reason locked_by_legacy.
The id of the legacy invoice this invoice was converted from, so it can be matched with GET /api/v2/invoices. The legacy invoice may since have been removed.
Notes for colleagues. Never rendered on the invoice the customer receives.
Last-write timestamp; use for incremental sync. It also feeds the ETag revision, because a sales invoice has no version field.
Errors
8 errors every operation can return: 304, 400, 401, 404, 406, 429, 500, 503
304 Not modified.
400 Bad request.
idempotency-key-requiredinvalid-cursorinvalid-query-parametermalformed-requestunsupported-parameter
401 Unauthenticated.
404 Not found.
406 Not acceptable.
429 Too many requests.
500 Server error.
503 Service unavailable.
This path allows GET, POST. Anything else answers 405.
Something wrong or missing on this page? Tell us