Skip to content

Recipe

Syncing processing statuses

Mirror where an expense stands in QUiCK processing — without webhooks, using incremental polling.

Advanced~30 min5 steps

Prerequisites

  • A working authenticated integration (see: Authenticating API requests)
  • A database where you store the expense status
  • A scheduler (cron, worker) that runs the sync regularly

1. Which status fields exist

The QUiCK Public API does not send webhooks — you follow changes by polling. These fields describe where an expense stands:

FieldTypeMeaning
accounting_statusstringBookkeeping state
paid_statusinteger1 — unpaid, 2 — paid, 3 — instalment
incompleteboolItem with incomplete data
has_artifactboolWhether a document image is attached
filing_datedatetimeTime of filing

The same properties are available as list filters: is_approved, is_processed, needs_review, is_incomplete, is_exported.

2. Incremental querying

Store the timestamp of the last successful sync and request only the items created or changed since:

bash
curl -sS "https://api.quick.riport.co.hu/1/expenses/?date_field=created&from_date=2026-07-13&ordering=-created&page_size=100" \
  -H "Authorization: Token $QUICK_API_TOKEN"

Use an overlap

Set from_date one day earlier than the last run so items on the boundary are not missed. De-duplicate by id.

3. Idempotent update in your own table

id is the stable key. Only overwrite when the state actually changed — that way the sync can be re-run without side effects:

sql
INSERT INTO quick_expenses (expense_id, invoice_number, partner_name, accounting_status, paid_status, synced_at)
VALUES ($1, $2, $3, $4, $5, now())
ON CONFLICT (expense_id) DO UPDATE
SET accounting_status = EXCLUDED.accounting_status,
    paid_status       = EXCLUDED.paid_status,
    invoice_number    = EXCLUDED.invoice_number,
    synced_at         = now()
WHERE quick_expenses.accounting_status IS DISTINCT FROM EXCLUDED.accounting_status
   OR quick_expenses.paid_status       IS DISTINCT FROM EXCLUDED.paid_status;

4. Details and state changes

The full record of an item — including its accounting assignments — is available separately:

bash
curl -sS https://api.quick.riport.co.hu/2/expenses/90231/ \
  -H "Authorization: Token $QUICK_API_TOKEN"

If your own system decides on approval, you can write the state back. These endpoints are bulk and expect a list of identifiers:

EndpointEffect
POST /1/expenses/approve/Approve the selected expenses
POST /1/expenses/unapprove/Revoke approval
POST /1/expenses/check/Mark as checked
POST /1/expenses/uncheck/Revoke the check

5. Scheduling and fault tolerance

  • Scheduling: accounting data is not real-time — a minute-to-hour cadence is plenty. Polling too frequently returns 429 Too Many Requests.
  • Partial success: only advance the sync timestamp when the full pagination completed without error; otherwise the next run picks up what was missed.
  • Observability: log the number of items processed per run and any errors. A run returning zero items while traffic exists points at a configuration problem.

Related endpoints

  • POST/v1/webhooks
  • GET/v1/invoices

Related terms

Common pitfalls

Waiting for a webhook

The QUiCK Public API sends no event notifications and has no webhook registration endpoint. Anyone designing for webhooks will never receive data — the correct pattern is incremental polling.

A period window without overlap

If from_date is exactly the timestamp of the last run, items arriving on the boundary can be missed. Use at least a one-day overlap and de-duplicate by id.

Polling too frequently

A full re-sync every minute (or more often) leads to 429. Query less often, with a larger page_size and a from_date filter.

Advancing the sync timestamp after a failure

If pagination breaks halfway but you already saved the new timestamp, the missed items will never arrive. Only store the new timestamp after a fully successful run.