Skip to content

Fakturoid

Fakturoid is a Czech invoicing and accounting service for freelancers and small businesses.

ingestr supports Fakturoid as a source through the Fakturoid API v3.

URI format

plaintext
fakturoid://?client_id=<client_id>&client_secret=<client_secret>&slug=<slug>&user_agent=<user_agent>

URI parameters:

  • client_id: Required. OAuth client id from the Fakturoid account settings.
  • client_secret: Required. The matching client secret.
  • slug: Required, never defaulted. The account slug as it appears in the Fakturoid URL. One set of credentials can reach several accounts, so guessing would silently load another account's books.
  • user_agent: Required. Must carry a contact address, e.g. MyCompany (billing@mycompany.com).
  • rate_limit: Optional. Requests per second. Defaults to 1.5 (~90/min).

The User-Agent is mandatory

Fakturoid rejects requests with a missing or generic User-Agent — it is a documented hard requirement, not a courtesy. It has no default here on purpose: a shared default would send one user's contact address on everyone else's traffic.

A bad User-Agent does not present as an auth error. It returns 403 on every endpoint, including /oauth/token, so it reads like a credential problem.

Authentication is OAuth2 client_credentials: the client id and secret are sent as HTTP Basic credentials to POST /oauth/token, which returns a bearer token valid for about two hours. Tokens are refreshed lazily and shared across requests, so a long backfill does not die halfway.

Example usage

bash
ingestr ingest \
  --source-uri 'fakturoid://?client_id=<id>&client_secret=<secret>&slug=<slug>&user_agent=MyCompany%20(billing@mycompany.com)' \
  --source-table invoices \
  --dest-uri duckdb:///fakturoid.duckdb \
  --dest-table main.invoices

Tables

TablePrimary keyStrategyData
invoicesidmergeInvoices
invoices_linesinvoice_id, idmergeInvoice line items, exploded from each invoice
invoices_vat_ratesinvoice_id, vat_ratemergePer-invoice VAT-rate summaries
subjectsidmergeCustomers and suppliers

invoices_lines and invoices_vat_rates are derived from the same /invoices.json payload as invoices, so requesting them costs a full re-page of the invoice list.

Notes and limitations

Pagination is fixed at 40 rows and there is no total count

per_page is not a parameter — the page size is a server constant. The only end-of-data signal is a page shorter than 40 rows.

All fields are passed through

Every field Fakturoid returns is loaded and typed by schema inference; nested objects and arrays land as JSON columns. Drop any you don't want with --exclude-columns. Column types can be overridden with --columns.

merge cannot see a deletion

Under the merge strategy on (invoice_id, id), a line removed from an existing invoice lingers in the destination — the API simply stops returning it, and there is no tombstone. Invoice and subject deletions are equally invisible. If deletions matter for your use case, use a periodic full reload rather than an incremental one.