Using the APIPagination and filters

Using the API

Pagination and filters

Page through any list with cursors, narrow it with field filters and text search, and sort it on documented fields.

Every list endpoint, such as List documents, List clients or List items, works the same way. You get one page at a time using an opaque cursor, and you narrow the list with plain query parameters named after fields.

Cursor pagination

Lists use cursor pagination (proposed).

Query parameterDefaultMeaning
limit50How many records per page, from 1 to 200
cursornoneThe next_cursor value from the previous page

Every list response has the same envelope:

List response
{
  "data": [
    { "id": "0193f2b4-5a6b-7c8d-9e0f-1a2b3c4d5e6f", "number": "INV-2027-0042", "status": "sent" }
  ],
  "next_cursor": "eyJ0IjoiMjAyNy0wMS0wNVQx...",
  "has_more": true
}
  • data is the records on this page.
  • has_more is true when another page exists.
  • next_cursor is the value to pass as cursor to get that page, or null on the last page.

The cursor is opaque: do not build, change or decode it. Keep every other query parameter the same when you pass it, so the next page continues the same filtered list.

Walk every page

# First page
curl "https://api.freeinvoiceautomation.com/v1/documents?type=invoice&status=overdue&limit=100" \
  -H "Authorization: Bearer $FIA_API_KEY"

# Next page: same filters plus the cursor
curl "https://api.freeinvoiceautomation.com/v1/documents?type=invoice&status=overdue&limit=100&cursor=eyJ0IjoiMjAyNy0wMS0wNVQx..." \
  -H "Authorization: Bearer $FIA_API_KEY"

Order is stable

Unless you set sort, lists are ordered newest first by created_at, then by id, both descending. The order is stable, so the same query walks the records in the same order every time, and ties on created_at are broken by id.

Filters

Filters are plain query parameters named after the field they filter. The ones in common use are:

ParameterExampleMeaning
business_idbusiness_id=0193f29e-...Only records of this business
client_idclient_id=0193f2a1-...Only records of this client
typetype=invoiceDocument type: invoice, estimate, credit_note, receipt
statusstatus=sent,overdueOne or more statuses
currencycurrency=EUROnly records in this currency
due_before, due_afterdue_before=2027-02-01Due date range
issued_after, issued_beforeissued_after=2027-01-01Issue date range
updated_afterupdated_after=2027-01-10T00:00:00ZChanged since a moment; useful for syncing
external_refexternal_ref=5012Your own reference, such as a store order id
archivedarchived=trueArchived records instead of active ones

Each endpoint page lists exactly which filters it accepts, so check the page before relying on a filter.

Several values

Pass several values separated by commas. They are combined with OR inside one parameter, and different parameters are combined with AND:

GET /v1/documents?type=invoice&status=sent,overdue&currency=USD

This returns USD invoices that are sent or overdue.

q searches the main text fields of the resource: names, document numbers and email addresses.

GET /v1/clients?q=acme
GET /v1/documents?q=INV-2027-0042

Sorting

Set sort to a documented field. A leading - sorts descending.

GET /v1/documents?sort=due_date
GET /v1/documents?sort=-total_minor

Sorting works on documented fields only; the endpoint page lists them, often as the allowed values of sort.

Reports take their own parameters

Report endpoints are not paginated lists. They take a period and filters, and a format:

ParameterMeaning
from, toThe period, as dates
client_id, currency, business_idNarrow the report
formatjson, csv or pdf

Keeping a copy in sync

To mirror records into your own system, combine updated_after with pagination: store the time of your last successful sync, ask for records updated after it, walk every page, then save the new time. For changes as they happen, subscribe to webhook events instead of polling, and use the list endpoints to catch up after downtime.

Limits and errors

  • limit must be between 1 and 200. Query parameters are validated like any other input, and invalid values return validation_failed (422) with the problem in details.issues.
  • Pass the cursor back unchanged, with the same filters. If you change the filters, start again from the first page.
  • Large lists count against rate limits one request per page, so use limit=200 for bulk work.