Pagination and keeping in sync
Every list endpoint returns one page at a time.
{
"data": [ { "id": "inv_7Qa2" }, { "id": "inv_8Rb3" } ],
"has_more": true,
"next_cursor": "eyJ2IjoxLCJ..."
}
Reading every page
limitsets the page size, from 1 to 100. The default is 50.- When
has_moreis true, call the same endpoint again withcursorset tonext_cursor. - Keep every other parameter exactly the same across pages. A cursor belongs to the filters
it was made with; changing a filter mid-way returns
400. Start again withoutcursorif you need different filters. - Stop when
has_moreis false.
curl "https://api.trued.io/v1/invoices?period=2026-09&limit=100" \
-H "Authorization: Bearer $TRUED_API_KEY"
curl "https://api.trued.io/v1/invoices?period=2026-09&limit=100&cursor=eyJ2IjoxLCJ..." \
-H "Authorization: Bearer $TRUED_API_KEY"
Lists are ordered by when each row last changed, oldest first. /v1/events is ordered by when
each event happened, oldest first.
Filters
| Parameter | Where | Meaning |
|---|---|---|
period |
invoices, time entries, charges | A billing period: 2026-09 (monthly), 2026-W18 (weekly), 2026-BW09 (every two weeks) |
client_id |
invoices, time entries, charges, payments | One client |
contractor_id |
invoices, time entries, charges | One contractor |
updated_since |
every list except events | Only rows that changed at or after this time (ISO 8601) |
created_since |
events | Only events at or after this time |
An unknown parameter is refused with 400, so a typo never silently returns everything.
Keeping a copy in sync
The usual pattern for a dashboard or a data warehouse:
- First load: read each list in full and store the rows by
id. - Every few minutes or hours: read each list with
updated_sinceset to the time of your last successful sync, minus a small margin (one minute is plenty). Replace stored rows that come back byid. - Save the start time of each successful sync as the next
updated_since.
Two things to know:
- A change appears in lists a few seconds after it happens. Rows are ordered by when they
were published, so a cursor never skips one. Reading a single row by id
(
/v1/invoices/{id}) is always current. Keep the one-minute margin when you useupdated_since. - Deleted rows do not come back in a list. A deleted time entry or charge simply stops
appearing. To catch deletions, either re-read a month that is still open in full (for example
once a night), or follow the
time_entry.deletedandcharge.deletedevents (Webhooks).
Once a month is closed (period_closed is true on its invoices), its figures are final and you
can stop re-reading it.