Jahresabschluss.io
DESign inRegister →

Annual report API

Read German annual financial statements via API and MCP

Once a German company's annual financial statements (Jahresabschluss) have been issued in jahresabschluss.io, an AI agent or a script can read them through the API: GET /v1/annual-reports/status shows where a fiscal year stands, GET /v1/annual-reports/{id} returns the balance sheet, profit and loss account, notes and management report as text — exactly the issued version — and the disclosure XML for the company register comes back byte for byte with a SHA-256 to verify it. Preparing and issuing the statements happens in the app; the API's one write step is handing over the trial balance.

Last reviewed: 2026-10-19

What a German Jahresabschluss contains

A GmbH or UG prepares annual financial statements under the German Commercial Code (HGB): balance sheet (Bilanz), profit and loss account (Gewinn- und Verlustrechnung, GuV) and notes (Anhang), which form one unit, plus a management report (Lagebericht) unless the company is small (§ 264(1) HGB). Small companies may take up to six months of the new year where that fits orderly business practice; micro companies may omit the notes if they show certain disclosures below the balance sheet. The statements are drawn up in German and in euros (§ 244 HGB).

They are then submitted electronically to the Unternehmensregister, the German company register, no later than one year after the balance sheet date (§ 325 HGB). The annual-accounts module of jahresabschluss.io prepares single-entity statements; group accounts are a separate module.

Endpoints and MCP tools

Reading needs only the read right, which every key has.

  • GET /v1/annual-reports/status?fiscal_year_id=… (get_annual_report_status) — where a fiscal year stands.
  • GET /v1/annual-reports (list_annual_reports) — issued statements with ID, variant, format and checksum.
  • GET /v1/annual-reports/{id} (get_annual_report) — the sections of an issued statement as text and HTML.
  • GET /v1/annual-reports/{id}/file (download_annual_report) — the PDF or DOCX file.
  • GET /v1/disclosure-files (list_disclosure_files) — archived disclosure files with document type, target, file name and SHA-256.
  • GET /v1/disclosure-files/{id}/content (download_disclosure_file) — the exact XML bytes.
  • POST /v1/saldenliste/publish (publish_trial_balance) — the one write step: the trial balance from the books goes to the annual-accounts module.

Where does the year stand?

get_annual_report_status answers in one call (values illustrative):

{
  "fiscal_year": { "id": "…", "year": 2025, "start_date": "2025-01-01", "end_date": "2025-12-31" },
  "festgeschrieben_bis": "2025-12-31",
  "festgeschrieben": true,
  "saldenliste_uebergeben": true,
  "abschluss_ausgestellt": { "aufstellung": "2026-…", "offenlegung": "2026-…" },
  "offenlegung": { "dateien": 1, "abgeschlossen_am": null },
  "ebilanz": [ { "status": "paid", "transmission_status": "transmitted", "test_mode": false, "transmitted_at": "…" } ],
  "kst": { "elster_status": "…", "test_mode": false, "uebermittelt_am": "…" },
  "gewst": null
}

festgeschrieben_bis is the date up to which the books are locked. aufstellung and offenlegung are the latest issued versions — the statements as prepared for the company and the version for disclosure. ebilanz, kst and gewst show the E-Bilanz and the corporate and trade tax returns of the same year. The field names are German; an agent translates them for you.

The issued statements as text

list_annual_reports lists every issued statement — variant aufstellung or offenlegung, format PDF or DOCX, file name, size, artifact_sha256 and date — optionally for one fiscal year. get_annual_report returns its sections with key, heading, text and HTML: the balance sheet, the P&L, the notes, the management report and the other parts of the document.

It is exactly the issued version, not the draft in the editor. If nothing has been issued, the answer is 404 no_issued_report — never empty figures. That makes the text a stable basis for an agent: comparing two years, explaining the equity ratio, drafting a summary for the bank or for investors, always from the document that was actually issued.

Files: PDF, DOCX and the disclosure XML

Files do not go through the model; download them with the key from an environment variable:

export JAB_API_KEY="jab_live_…"
BASE="https://api.jahresabschluss.io/functions/v1/bookkeeping-api/v1"

# Issued statement as PDF or DOCX, file name from the server
curl -H "Authorization: Bearer $JAB_API_KEY" -OJ "$BASE/annual-reports/<id>/file"

# Disclosure XML, then compare with sha256 from GET /disclosure-files
curl -H "Authorization: Bearer $JAB_API_KEY" \
  -o offenlegung.xml "$BASE/disclosure-files/<id>/content"
shasum -a 256 offenlegung.xml

Over MCP, download_annual_report returns such a command instead of the file. download_disclosure_file returns the XML as text and can be large; the sha256 from list_disclosure_files proves that the bytes are identical to the archived file. Files above 15 MB are not served through the API (413 payload_too_large) and are downloaded in the app.

Handing over the trial balance

The step from the books to the statements is publish_trial_balance — POST /v1/saldenliste/publish with the write right, a fiscal_year_id and an idempotency_key; a retry with the same key is not handed over twice. The answer contains the trial balance ID, how many accounts were mapped to HGB line items and how many remain unmapped, whether it balances, and any warnings.

Because the trial balance feeds the statements, a hand-over through the API expects the year's entries to be locked; otherwise it answers 409 with the number of unlocked entries. Lock them first with finalize_bookkeeping_period, which needs the finalize right and your explicit yes. Once the annual statements themselves are locked, the trial balance is not regenerated.

What stays in the app

  • Preparing the statements — mapping, valuation decisions, notes and management report — with AI assistance in the app and the review of you or your Steuerberater (tax adviser).
  • Issuing them: the API sees only issued versions.
  • Generating the E-Bilanz; an agent can then check and prepare it with the tax tools (art=ebilanz) for you to file in the app.
  • Submitting to the Unternehmensregister: the software creates the submission file but does not submit it.
  • Group accounts, which are a separate module and not part of this API.
  • An audit where one is required — the software does not replace an auditor.

Frequently asked questions

Can I read a German Jahresabschluss through an API?

Yes. Once it is issued, GET /v1/annual-reports/{id} or the MCP tool get_annual_report returns balance sheet, P&L, notes and management report as text, and the file and disclosure XML can be downloaded.

Can an AI agent create the annual financial statements?

No. The agent keeps the books and hands over the trial balance with publish_trial_balance. The statements are prepared, reviewed and issued in the app's annual-accounts module.

Does the API return the draft or the issued version?

Only the issued version. If nothing has been issued for a fiscal year, the API answers 404 no_issued_report instead of returning empty figures.

How do I verify a disclosure file?

Take the sha256 from list_disclosure_files and compare it with the SHA-256 of the downloaded XML. Matching values mean the bytes are identical to the archived file.

Does the software file with the Unternehmensregister?

No. It creates the submission file for the company register; submitting it is a separate step outside the software.

In which language are the statements?

In German and in euros, as § 244 HGB requires. The app's interface is also available in English, and an agent can explain the German text to you.