Changelog
Reverse-chronological release notes for the gnubok REST API. Versions follow Stripe's dated format (
YYYY-MM-DD). The current version is2026-05-12.
2026-05-12 (current)
The first stable release of the public REST API. Six phases of development covering the full agent-native surface: authentication + discovery, invoicing vertical, transactions vertical, bookkeeping engine + suppliers + compliance check, payroll + reports + import, webhooks.
Authentication + discovery (Phase 1)
- API key auth via
Authorization: Bearer gnubok_sk_<live|test>_<random>. 100 RPM rate limit per key. gnubok_sk_test_*keys bound to deterministic sandbox companies.- Scope-based authorisation per endpoint (
invoices:read,payroll:write,webhooks:manage, ...). - Discovery:
GET /llms.txt,GET /api/v1/openapi.json,GET /.well-known/skills/index.json. - Health:
GET /api/v1/health. - Response envelope:
{ data, meta: { request_id, api_version, audit, next_cursor } }. X-Request-Idon every response; idempotency on every write.
Invoices vertical (Phase 2)
- Customers: GET list + detail, POST create + bulk-create, PATCH, DELETE.
- Invoices: GET list + detail, POST create, PATCH, lifecycle verbs
/mark-sent,/mark-paid,/credit,/send,/bulk-create. PDF download at/{id}/pdf. - VIES validation runs on commit for EU-business customers with a VAT number.
- Mixed-rate invoices supported — per-item
vat_rateoverrides the header rate. - ROT/RUT-avdrag flow and supplier-invoice fakturamodellen on the AP side.
Transactions vertical (Phase 3)
- Transactions: cursor-paginated GET list + detail. Single-tx verbs
/categorize,/uncategorize,/match-invoice,/match-supplier-invoice. Bulk/ingest(up to 500),/batch-categorize(up to 100). - Reconciliation:
POST /reconciliation/bank/run,GET /reconciliation/bank/status. - Reads:
GET /accounts,GET /fiscal-periods. - All write surfaces honour strict-mode (commit fully or error with no side effects).
Bookkeeping primitives + AP + compliance (Phase 4)
- Suppliers + supplier-invoices vertical (mirror of Phase 2 invoices on the AP side).
- Journal entries primitives:
POST /journal-entries(draft+commit),/{id}/commit,/{id}/reverse(storno) and/{id}/correct(rättelse) — both satisfy BFL 5 kap 5 § (storno is the canonical method of rättelse),/batch-create. - Voucher gap explanations:
POST /voucher-gap-explanationsper BFNAR 2013:2. - Fiscal-periods async ops:
/lock,/close,/year-end,/opening-balances,/currency-revaluation. All return 202 with operation_id; poll atGET /api/v1/operations/{id}. - Compliance check:
GET /compliance/check?type={year_end_readiness|voucher_gaps}— pre-flight findings before submission. - Documents:
POST /documents(multipart upload, magic-number-checked),GET /{id}/download(15-min signed URL),POST /{id}/link(attach to journal entry).
Payroll + reports + import (Phase 5)
- Employees: full CRUD with personnummer masking on list/create per GDPR Art.5(1)(c). Soft-delete via
is_active. - Salary runs: CRUD + lifecycle verbs
/calculate,/approve,/mark-paid,/book,/generate-agi. State machine: draft → review → approved → paid → booked./generate-agiproduces and persists the arbetsgivardeklaration XML — the response carries it asdata.xmlfor the integrator to upload to Skatteverket Mina Sidor (or via the optionalskatteverketextension). gnubok does NOT auto-submit; the AGI deadline — the 12th of the following month for every reporting period EXCEPT January and August, where companies with annual turnover ≤ 40 MSEK get the 17th — is the integrator's responsibility. - JSON reports (14): trial-balance, balance-sheet, income-statement, general-ledger, journal-register, vat-declaration, monthly-breakdown, ar-ledger, supplier-ledger, continuity-check, salary-journal, avgifter-basis, vacation-liability.
- Binary report:
GET /reports/sie-export(text/plain SIE4 file). Note: a SIE4 export alone does NOT satisfy BFL 7 kap archiving obligations — SIE captures account-level positions and verifikationer but lacks system documentation and behandlingshistorik. Treat SIE as a portability format (Fortnox/Visma/Bokio migration), not as a complete archive. - Async imports:
POST /imports/sie(multipart, 50 MB),POST /imports/bank(multipart, 10 MB, auto-format detection across 11 bank formats). Both async viaoperationssubstrate. Post-SIE-import warning: SIE files do NOT carry VAT codes or tax-rate-to-account mappings, AND they do NOT transfer behandlingshistorik (the source system's processing log required by BFNAR 2013:2 kap 8 §) or systemdokumentation. After importing from Fortnox / Visma / BL / SpeedLedger / Bokio you MUST manually reconfigure VAT codes (typically via/settings/tax-codes) before the first momsdeklaration; skipping this step is the most common source of incorrect VAT submissions in migrated bookkeeping. The behandlingshistorik gap must be preserved separately — under BFNAR 2013:2 kap 8 § the obligation attaches to the entire räkenskapsår, not from the import date forward. Best practice for a mid-year migration: export the source system's behandlingshistorik for the full fiscal year and archive it alongside the SIE file. gnubok starts a fresh behandlingshistorik from the import date forward; the pre-import portion of the year remains the source system's record.
Webhooks (Phase 6 PR-1) — shipped 2026-05-15
- Subscriptions:
POST /webhooks(HMAC secret returned exactly once), GET list + detail, PATCH, DELETE. Per-event-type elevated scope check (salary_run.*andagi.generatedrequirepayroll:read). - Delivery substrate: per-minute Vercel cron at
/api/webhooks/dispatch/cron. Exponential backoff1m / 5m / 30m / 2h / 12h / 24h / 48h(7 retries, ~72h total). HTTP 410 from receiver auto-disables the webhook. - Signature:
X-Gnubok-Signature: t=<unix>,v1=<hex-HMAC-SHA256>. Stripe-format. Sample receivers in Node + Python. - SSRF protection: webhook_url must be HTTPS; resolved IPs in private/loopback/link-local/CGNAT/cloud-metadata ranges are rejected at create AND dispatch time.
redirect: 'error'on every outbound POST. - Audit + retention: webhook delivery rows are behandlingshistorik per BFNAR 2013:2 kap 8 § — immutable once terminal so the audit trail of what an integration was notified of stays intact. Delivery rows are NOT räkenskapsinformation themselves; the 7-year statutory retention under BFL 7 kap 1 § applies only to the underlying verifikation / faktura / AGI XML in its own table, NOT to the delivery envelope. gnubok keeps accounting-event delivery rows for 7 years as a voluntary operational policy (the duration aligns with BFL 7 kap on the underlying records but is not itself a statutory obligation on delivery rows). Webhook DELETE preserves the delivery audit trail (
ON DELETE SET NULLonwebhook_id). - Verbs:
POST /webhooks/{id}/testenqueues a synthetic event;POST /webhook-deliveries/{id}/retryre-enqueues a dead/delivered delivery.