Skip to content
Documentation
English
Open the app

Pagination

The three list shapes returned by the NovaFisko API, the page and per_page parameters, and the right way to go through all pages.

Not all lists are paginated. The API returns three shapes depending on the nature of the resource. The reference specifies the shape of each route.

Shape When Examples
Plain array Reference data of limited size companies, accounts, journals, third-parties, vat-codes, fiscal-years
Page-based pagination Lists that keep growing entries, documents, document-imports, bank-transactions, coda-files, history, sync/conflicts
Cursor stream Change tracking sync/pull

Plain arrays

Reference data is returned in full, as a JSON array at the root. Filter it with the search parameters of the route.

curl "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/third-parties?type=supplier&q=brasserie" \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN"
[
  {
    "id": 41,
    "type": "supplier",
    "code": "BRASSCOL",
    "name": "Brasserie des Collines SA",
    "vat_number": "BE0999900134",
    "version": 3
  }
]

Page-based pagination

Parameters

Parameter Default Maximum Description
page 1 Page number, starting at 1
per_page 50 200 Number of items per page

Bank transactions (bank-transactions) are an exception: 100 items by default, 500 at most.

Response shape

curl "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries?from=2026-07-01&to=2026-09-30&per_page=2&page=1" \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN"
{
  "current_page": 1,
  "data": [
    {
      "id": 1842,
      "journal_id": 3,
      "number": 212,
      "entry_date": "2026-09-30T00:00:00.000000Z",
      "label": "Brasserie des Collines SA",
      "reference": "F-2026-0918",
      "status": "posted",
      "journal": {"id": 3, "code": "ACH", "type": "purchase"},
      "third_party": {"id": 41, "name": "Brasserie des Collines SA"},
      "lines": [
        {"id": 5521, "account_id": 118, "debit": "1250.00", "credit": "0.00", "account": {"id": 118, "number": "604000", "label": "Achats de marchandises"}},
        {"id": 5522, "account_id": 77, "debit": "262.50", "credit": "0.00", "account": {"id": 77, "number": "411000", "label": "TVA à récupérer"}},
        {"id": 5523, "account_id": 90, "debit": "0.00", "credit": "1512.50", "account": {"id": 90, "number": "440000", "label": "Fournisseurs"}}
      ]
    }
  ],
  "first_page_url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries?page=1",
  "from": 1,
  "last_page": 87,
  "last_page_url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries?page=87",
  "links": [
    {"url": null, "label": "« Précédent", "active": false},
    {"url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries?page=1", "label": "1", "active": true}
  ],
  "next_page_url": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries?page=2",
  "path": "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/entries",
  "per_page": 2,
  "prev_page_url": null,
  "to": 2,
  "total": 173
}
Field Description
data The items of the page
current_page, last_page Current page and last page
per_page Page size applied, after capping
total Total number of items matching the filters
from, to Rank of the first and last item of the page
next_page_url, prev_page_url URL of the next or previous page, null if there is none
Warning

The URLs contained in next_page_url and links do not include your filters (from, to, per_page...). Build the URL of the next page yourself by incrementing page and keeping your parameters.

Variants

A few routes add fields to the standard pagination or simplify its shape.

Route Specific feature
sync/conflicts Standard pagination, plus open: the number of conflicts still open
trash data, current_page, per_page, last_page, total, plus counts, types, retention_days, can_purge
activity, firms/{firm}/activity data, current_page, per_page and has_more instead of total
firms/{firm}/webhooks/{webhook}/deliveries data and meta: {current_page, last_page, per_page, total}

For the activity log, keep going as long as has_more is true.

Going through all pages

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://api.novafisko.com/v1/',
    'headers' => ['Authorization' => 'Bearer '.getenv('NOVAFISKO_TOKEN'), 'Accept' => 'application/json'],
]);

$page = 1;
do {
    $response = json_decode((string) $client->get("companies/{$company}/entries", [
        'query' => ['fiscal_year_id' => 7, 'per_page' => 200, 'page' => $page],
    ])->getBody(), true);

    foreach ($response['data'] as $entry) {
        // Handle one entry
    }
    $page++;
} while ($page <= $response['last_page']);
import os
import requests

session = requests.Session()
session.headers.update({"Authorization": f"Bearer {os.environ['NOVAFISKO_TOKEN']}", "Accept": "application/json"})

def all_entries(company, **filters):
    page = 1
    while True:
        payload = session.get(
            f"https://api.novafisko.com/v1/companies/{company}/entries",
            params={**filters, "per_page": 200, "page": page},
            timeout=60,
        ).json()
        yield from payload["data"]
        if page >= payload["last_page"]:
            break
        page += 1

Order and stability

Paginated lists are sorted from newest to oldest (entries by entry date then by id, history by id). If items are created while you are going through the list, an item may slip from one page to the next and appear twice. Two safeguards:

  • bound the period with from and to over a closed interval;
  • deduplicate on id on your side.
Tip

For a complete copy kept up to date, do not poll the lists in a loop. Load them once, then follow the changes with sync/pull.

Cursor stream

GET sync/pull has no pages. You give it the last cursor received and it returns the changes that have occurred since.

curl "https://api.novafisko.com/v1/companies/k3Jd9fPq2LmX/sync/pull?since=48211&limit=500" \
  -H "Authorization: Bearer $NOVAFISKO_TOKEN"
{
  "cursor": 48236,
  "has_more": false,
  "full_resync": false,
  "changes": [
    {"resource": "third_parties", "op": "upsert", "id": 41, "version": 4, "data": {"id": 41, "name": "Brasserie des Collines SA"}, "changed_at": "2026-10-05T08:41:02+00:00", "seq": 48236}
  ],
  "server_time": "2026-10-05T08:41:09+00:00"
}

As long as has_more is true, call the route again immediately with the new cursor. The full walkthrough is in Continuous sync.

See also