Judge an accounting API by eight things you can verify from its documentation in an afternoon: how a caller authenticates and to which tenant, whether permissions are scoped, whether writes are idempotent, whether it tells you about changes (webhooks), what the rate limit is and how it fails, whether there is a sandbox, what an error looks like, and whether an AI assistant can use it without being able to do damage. A vendor that answers all eight with specifics has thought about integrations; a vendor that answers with "yes" has not. This page gives the questions, then KRONENWERK's answers with the real numbers and the real limitations.
Why the API decides more than the feature list
An accounting system that your product writes to becomes part of your product. Its API shapes how you model customers and invoices, how you recover from a failed request at 3 a.m., and what an auditor sees when they ask which system created an entry. Choosing on the feature list and discovering the API later is how integrations end up with a nightly CSV job and a person who "checks it".
The eight criteria below are ordered by how expensive they are to work around. Missing idempotency, for example, cannot be fixed on the client side; a coarse rate limit can be.
The evaluation table
Use the middle column as the question to put to any vendor; use the right column to judge the answer.
| Criterion | What to ask | A good answer looks like |
|---|---|---|
| Authentication and tenancy | How does a request identify itself, and how does the server know which company it applies to? | A bearer secret bound to exactly one company at issuance; the tenant never comes from a header or path the caller controls; a call that tells you which company a key belongs to. |
| Scopes | Can a key be limited to reading, or to one object type? | Named scopes per object and per direction (read / write), checked server-side, with read not implying write. |
| Idempotency | What happens when I retry a POST whose response I never received? | An Idempotency-Key header; same key and body returns the original result; same key with a different body is refused; a documented key lifetime. |
| Webhooks | How do I learn that an invoice was paid without polling? | Signed deliveries (HMAC over timestamp and raw body), an event identifier for deduplication, retries with a documented count, HTTPS only, no redirects followed. |
| Rate limits | How many calls, measured how, and what comes back when I exceed it? | A stated budget and refill rate per key; 429 with Retry-After; the number, not "fair use". |
| Sandbox | Where do I test without touching real books? | Test credentials that exercise the same API with the same validation; clear separation from live data. |
| Errors and versioning | What does a failure look like, and what does a version promise? | JSON with a machine-readable code plus a human sentence; a version in the path; a stated rule for what may change within a version. |
| MCP for assistants | Can an AI assistant read the books, and what can it not do? | An MCP server with the same key and scopes; read tools plus draft tools; no tool that issues documents, sends mail, moves money or changes settings. |
Three criteria in more depth
Idempotency is the one you cannot retrofit
Every network eventually loses a response. The IETF draft for the header describes the purpose: to "make non-idempotent HTTP methods such as POST or PATCH fault-tolerant". The draft expired without becoming an RFC, but the convention it documents is what most payment and accounting APIs use. If a vendor's API lacks it, your only options are to query before every write (a race) or to accept occasional duplicate customers and invoices. Neither survives an audit well.
Webhooks: the same rules as Stripe's
Stripe's webhook guidance has become the de-facto standard, and it is a good yardstick for any accounting API: signatures to "verify that webhook events originate" from the sender, tolerance for duplicates because endpoints "might occasionally receive the same event more than once", no guaranteed ordering, and a fast 2xx before any heavy processing. Ask the vendor whether their deliveries carry a signature, a timestamp and an event identifier — and whether the signature is computed over the raw body, because a signature over re-serialised JSON cannot be verified reliably.
MCP: read a lot, prepare a little, trigger nothing
The Model Context Protocol is "an open protocol that enables seamless integration between LLM applications and external data sources and tools", using JSON-RPC 2.0 messages between hosts, clients and servers. Its specification is explicit that tools "represent arbitrary code execution and must be treated with appropriate caution" and that "hosts must obtain explicit user consent before invoking any tool". For an accounting ledger that translates into a simple test: list the tools, and check that none of them can issue an invoice, send a document, move money or change a setting. An assistant that can answer "who is overdue?" and draft an invoice for a person to review is useful; one that can issue it is a liability.
How KRONENWERK answers each criterion
The numbers below are the ones the API enforces today; the reference is at the developer reference. The API, webhooks, MCP server and integration directory are part of the Enterprise plan — see plans. SUPPORTED WITH LIMITATIONS
| Criterion | KRONENWERK |
|---|---|
| Authentication and tenancy | Bearer API key, prefix greif_live_ or greif_test_, at https://kronenwerk.org/api/extern/v1. One company per key, fixed at issuance; no header or path selects a company. GET /me returns the company and scopes. Only a hash of the key is stored; a lost key is replaced, not recovered. See authentication. |
| Scopes | customers:read, customers:write, invoices:read, invoices:write, transactions:read, transactions:write, reports:read, companies:read. Read and write are separate grants. |
| Idempotency | Idempotency-Key required on every POST. Same key and body: the original record; same key and a different body: refused with 409 and code IDEMPOTENZ_KONFLIKT; keys live 24 hours. See idempotency. |
| Webhooks | Events invoice.issued, invoice.paid, invoice.cancelled, purchase.recorded, payment.recorded. Headers KRONENWERK-Signature (t=…,v1=…, HMAC-SHA256 over t.raw_body, 5-minute tolerance), KRONENWERK-Event-Id, KRONENWERK-Event, KRONENWERK-Delivery, KRONENWERK-Attempt, Idempotency-Key. HTTPS only, retried until accepted, redirects not followed. See webhooks. |
| Rate limits | A budget of 240 requests per key, refilling continuously at about two per second. Exceeding it returns 429 with Retry-After and code ZU_VIELE_ANFRAGEN. See limits. |
| Sandbox | A greif_test_ key works against the same API in test mode for the company that created it. There is no separate sandbox host. |
| Errors and versioning | Errors are JSON with a machine code and a sentence, e.g. {"fehler": "…", "code": "NICHT_GEFUNDEN"}; the code is part of the contract, the sentence may be reworded. The version is in the path (/v1); within a version fields may be added but not removed or retyped, and codes keep their meaning. See errors. |
| MCP | Server at /api/extern/mcp, Streamable HTTP, same API key. Read tools: get_customer, search_customers, get_invoice, list_invoices, get_transaction, list_transactions, list_receivables, list_payables, get_profit_and_loss, get_balance_sheet, get_business_attention. Draft tools: create_invoice_draft, create_transaction, add_transaction_note. No tool issues an invoice, sends mail, moves money or changes settings. See MCP. |
The complete endpoint list is short by design: GET /me, GET /customers, GET /customers/{id}, POST /customers, GET /invoices, GET /invoices/{number}, POST /invoices/drafts, GET /transactions, POST /transactions, GET /reports/outstanding. A request and its refusal look like this:
GET /api/extern/v1/invoices?status=OPEN&size=1 HTTP/1.1
Host: kronenwerk.org
Authorization: Bearer greif_live_…
HTTP/1.1 200 OK
Content-Type: application/json
{"data":[{"number":"R-2026-0001","issuedOn":"2026-04-02","buyer":"Kellermann GmbH",
"currency":"EUR","gross":{"minor":105910,"currency":"EUR"},
"outstanding":{"minor":105910,"currency":"EUR"},"paymentState":"OPEN","overdue":false}],
"page":0,"size":1,"total":1,"more":false}
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json
{"fehler":"…","code":"ZU_VIELE_ANFRAGEN"}
The API is described in prose on the accounting API page; the security review is on developer security; the wider evaluation for European companies — formats, VAT, languages — is on what a European business needs.
Frequently asked questions
Is an API key enough, or should I insist on OAuth?
For a server-to-server integration where you control both ends, a scoped key bound to one company is simpler and no less safe. OAuth matters when third parties act on behalf of many of your users; that is not the case for a company integrating its own app with its own ledger.
What is a reasonable rate limit for an accounting API?
Enough for a burst at month end and a steady trickle otherwise. KRONENWERK's budget of 240 requests refilling at about two per second fits that pattern; what matters more is that the limit is stated and that 429 carries Retry-After.
Why does KRONENWERK not let the API issue invoices?
Because issuing assigns a legal number, generates the e-invoice and checks the VAT ID; the product keeps that step behind validation and a person. Drafts over the API, issuing in the product.
Can I use the sandbox without a paid plan?
A test key is created inside a company on the Enterprise plan; there is no separate public sandbox host. See plans.
Does the MCP server give an assistant write access to my books?
Only to drafts and notes: it can prepare an invoice draft or a transaction for a person to review. It cannot issue, send, pay or reconfigure anything.