eFakturuj / API Docs
eFakturuj Guides

Pagination

Every list endpoint in eFakturuj returns the same envelope: a slim items array plus the total row count, the page index, and the page size. Iterate by incrementing page until you've covered total — there is no cursor today.

Query parameters

All list endpoints (GET /invoices, GET /customers) accept the same paging surface:

ParamTypeDefaultRangeNotes
pageint1>= 11-based page index.
page_sizeint201100Hard cap is 100 — larger values are rejected with 422.
qstringnone<= 200 charsServer-side substring search (case-insensitive). On invoices matches invoice number, supplier name, buyer name. On customers matches name and VAT id.

GET /invoices adds extra filters and sort: comma-separated status=draft,validated, ISO-date from_date / to_date against issue_date, a created_by UUID, and a sort clause that lists columns separated by commas with an optional - prefix for descending order:

?sort=-issue_date,total_gross

GET /customers does not support sort — results are always returned alphabetically by name.

Response envelope

Both endpoints return the same shape (InvoiceListPaginated / CustomerListPaginated in the OpenAPI):

{
  "items": [ /* page_size rows max */ ],
  "total": 123,
  "page": 1,
  "page_size": 20
}

items carries a list-row projection — slim columns for table rendering. The full record is one fetch away (GET /invoices/{id}, GET /customers/{id}).

Iteration recipe

Loop until page * page_size >= total. Pull the first page first so you know total before deciding whether to keep going.

# curl — first page
curl -H 'Authorization: Bearer EFK_TOKEN' \
  'https://api.efakturuj.sk/api/v1/invoices?page=1&page_size=100'
# Python — drain every page
import httpx

def all_invoices(token: str):
    page = 1
    with httpx.Client(headers={"Authorization": f"Bearer {token}"}) as c:
        while True:
            r = c.get(
                "https://api.efakturuj.sk/api/v1/invoices",
                params={"page": page, "page_size": 100},
            )
            r.raise_for_status()
            body = r.json()
            yield from body["items"]
            if page * body["page_size"] >= body["total"]:
                return
            page += 1
// Dart — drain every page
Future<List<Map<String, dynamic>>> allInvoices(String token) async {
  final out = <Map<String, dynamic>>[];
  var page = 1;
  while (true) {
    final res = await dio.get(
      'https://api.efakturuj.sk/api/v1/invoices',
      queryParameters: {'page': page, 'page_size': 100},
      options: Options(headers: {'Authorization': 'Bearer $token'}),
    );
    out.addAll(List<Map<String, dynamic>>.from(res.data['items']));
    if (page * (res.data['page_size'] as int) >=
        (res.data['total'] as int)) break;
    page += 1;
  }
  return out;
}

Performance tips

  • Set page_size=100 for full drains. The 20-row default exists for human dashboards — programmatic callers should always paginate at the cap.
  • Filter on the server, not the client. Pass q, status, from_date / to_date, and created_by to the API rather than pulling everything and filtering in your code. The same indexes power list and search.
  • Don't paginate when you're really polling. If you only care about new rows since last sync, scope with from_date and remember the last created_at you saw. Webhooks (Webhooks) remove the need to poll for invoice status changes entirely.
  • Cursor pagination is on the roadmap for very large drains (10k+ rows) where deep page values become slow on the indexed scan. Today the page × page_size interface is consistent across both list endpoints — track Changelog for cursor support.