ELSTER: download tax notices with a browser workflow
Mein ELSTER delivers assessments and tax-office messages to an inbox that somebody has to open. This template picks up after a person's certificate sign-in, reads what arrived since a date, downloads the PDFs and hands the list to your accounting system.
Who opens the ELSTER inbox today
The inbox is the same for a two-person GmbH and a group tax department; only the number of certificates differs.
- In-house finance, monthly
- After each VAT prepayment and every assessment period someone signs in with the company certificate, scrolls the inbox for anything new, downloads the PDF and files it in the DMS. The step is short and easy to postpone, which is how a notice sits unread for three weeks.
- Group tax departments, weekly
- Several entities, several certificates, one shared mailbox for the notification e-mails. The e-mail says a document is ready; it does not say which entity or what it contains, so each one is a separate sign-in.
- What breaks
- The one-month objection period starts with deemed delivery under § 122a AO, not when a person reads the notice. A missed inbox entry is not a lost PDF; it is a lost deadline.
The manual route, click by click
These are the steps the template replaces, taken from the public Mein ELSTER help pages. Labels are quoted as the help pages give them; if your account shows something else, adjust the block instruction rather than the page.
-
Sign in to Mein ELSTER
Open elster.de, choose Mein ELSTER and Login. The public help lists the login options: certificate file (.pfx plus password), the ElsterSecure app, the German ID card with the AusweisApp, a security stick and a signature card.
-
Open Mein Posteingang
The inbox holds notices made available electronically (once you have consented to electronic delivery) and messages from the tax office. Unread entries are marked.
-
Open the entry and download the PDF
Each entry has a detail view with the document as PDF. There is no bulk download in the public description of the inbox; one entry, one download.
-
Note the delivery date
A notice provided for retrieval counts as delivered under § 122a AO a fixed number of days after the notification e-mail was sent. Record that date in your own system; it is what the objection period runs from.
-
Sign out
Use the sign-out link. The public pages say the session ends after a period of inactivity; the exact length is not something this page has verified.
Mein ELSTER facts the template relies on
| Login options | Certificate file, ElsterSecure, ID card (eID), security stick, signature card Mein ELSTER public help |
|---|---|
| Certificate validity | An ELSTER certificate is valid for three years and is renewed from within Mein ELSTER before it expires Mein ELSTER public help |
| Electronic delivery | Assessments can be made available in the inbox instead of by post once you have opted in Mein ELSTER public help |
| Deemed delivery | § 122a AO fixes the day on which a notice provided for retrieval counts as delivered, independent of when it is opened § 122a AO |
| What the vault holds | Username-style fields and TOTP seeds. A certificate file is not a vault field, so the sign-in is a person's step in the live view |
As of 2026-09-08
The template and how to publish it
Publish the JSON as it is, then start a run on a session a person has already signed in to. The labels become variables: Read_inbox publishes Read_inbox_output, which the loop and the webhook read.
{
"title": "Mein ELSTER: collect new notices from the inbox",
"parameters": [
{
"key": "since_date",
"description": "Only inbox entries received on or after this date (YYYY-MM-DD)",
"required": true
},
{
"key": "target_webhook",
"description": "Your endpoint that receives the list of notices",
"required": true
}
],
"runSequentially": true,
"sequentialKey": "mein-elster",
"blocks": [
{
"blockType": "navigation",
"label": "Start_page",
"url": "https://www.elster.de/eportal/start"
},
{
"blockType": "validation",
"label": "Signed_in",
"criterion": "The Mein ELSTER start page of a signed-in user is shown, with the inbox (Mein Posteingang) reachable from the navigation and no login form or certificate prompt on the page"
},
{
"blockType": "action",
"label": "Open_inbox",
"instruction": "Open the inbox (Mein Posteingang) from the Mein ELSTER navigation"
},
{
"blockType": "extraction",
"label": "Read_inbox",
"instruction": "Every inbox entry received on or after {{ since_date }}: date, sender (the tax office), subject, whether it is a tax notice (Bescheid) or a message (Mitteilung), and whether a PDF is attached",
"schema": {
"type": "object",
"properties": {
"entries": {
"type": "array",
"items": {
"type": "object",
"properties": {
"date": {
"type": "string"
},
"sender": {
"type": "string"
},
"subject": {
"type": "string"
},
"kind": {
"type": "string",
"enum": [
"notice",
"message"
]
},
"hasPdf": {
"type": "boolean"
}
},
"required": [
"date",
"subject",
"kind",
"hasPdf"
]
}
}
},
"required": [
"entries"
]
}
},
{
"blockType": "loop",
"label": "Each_entry",
"over": "{{ Read_inbox_output.entries }}",
"maxIterations": 50,
"blocks": [
{
"blockType": "action",
"label": "Download_pdf",
"nextLoopOnFailure": true,
"instruction": "Open the inbox entry dated {{ loopValue.date }} with the subject {{ loopValue.subject }} and download its PDF"
}
]
},
{
"blockType": "http_request",
"label": "Post_list",
"method": "POST",
"url": "{{ target_webhook }}",
"headers": {
"content-type": "application/json"
},
"body": "{{ Read_inbox_output }}"
}
]
}
import { Browserberg } from '@browserberg/sdk';
import template from './elster-notices.json' with { type: 'json' };
const bb = new Browserberg({
apiKey: process.env.BROWSERBERG_API_KEY,
baseUrl: 'https://browserberg.com',
});
const wf = await bb.workflows.publish(template);
// The certificate step belongs to a person: open the watch link, take over, sign in.
await using session = await bb.sessions.create();
const { url } = await bb.sessions.watchLink(session.id, { allowTakeover: true });
console.log('Sign in to Mein ELSTER here, then start the run:', url);
const run = await bb.workflows.run(wf.workflowId, {
sessionId: session.id,
inputs: {
since_date: '2026-08-01',
target_webhook: 'https://erp.internal.example/hooks/elster',
},
});
console.log(run.status, run.endedBy, run.outputs.Read_inbox_output);
Note · Drafted from public documentation
This template was written against the public Mein ELSTER help pages and the block reference, not against a live ELSTER account. Menu labels, the start URL and the inbox layout may differ from what your account shows; treat the JSON as a starting point and expect to adjust one or two instructions on the first run.
Sign-in, session and what the run will not do
Browserberg is not affiliated with ELSTER or the Bavarian tax administration that operates it; this page describes how to drive the public portal with an account you already hold.
The certificate step is a person's step
The vault stores fields and TOTP seeds. It does not store a certificate file, and the browser cannot take one from your machine, so the template deliberately starts after the sign-in. The script creates a session, mints a watch link with takeover allowed, and a person opens it, takes over the browser and completes the login: with the ElsterSecure app by confirming on the phone, or with the certificate file if it is available inside the session. When the person releases the takeover, the run starts and the first validation block checks that the signed-in start page is really there. If it is not, the run fails at block two with that reason, before anything else happens.
When the session ends
Mein ELSTER ends a session after a period of inactivity, and a Browserberg session has its own deadline. Neither is a problem for a run that takes minutes; both are a problem for a run that waits for a person who is at lunch. Start the run once the sign-in is done, not before. runSequentially with a fixed key makes sure two runs never share one certificate login at the same time.
What the effect gates refuse
Every click passes the effect gates, which classify the element under the cursor rather than the instruction. Reading the inbox and downloading a PDF are read effects. A control labelled along the lines of delete, withdraw or pay is classed as destructive or payment and is refused under the default policy, whatever the instruction said. Typing is never gated, and the template types nothing except the search date.
What the run leaves behind
Each block is recorded in the run with its status, and every action lands in the hash-chained action log. The PDFs downloaded in the loop are stored as artifacts of the run; the list itself is posted to your webhook as JSON.
Questions before the first run
Can the vault hold my ELSTER certificate?
No. A certificate is a file plus a password, and the vault stores field values and TOTP seeds, not files. The sign-in is done by a person in the live view; the session then carries the signed-in state for the run.
Does the run reading a notice start the objection period?
No, and neither does a person reading it. Under § 122a AO a notice counts as delivered a fixed number of days after the notification e-mail, whether or not anyone opened it. The template exists so that nobody discovers a notice late.
Can this run on a schedule?
The blocks after the sign-in can, but a scheduled firing creates its own session and nobody has signed in to it, so the validation block fails immediately. For ELSTER a run is started by a person or a script once the certificate step is done. Portals with a vaulted login are the ones that suit a schedule.
What happens with an entry that has no PDF?
The extraction reports hasPdf as false and the download block inside the loop fails for that entry. It carries nextLoopOnFailure, so the loop moves to the next entry instead of ending, and the failure is recorded against that iteration.
Where do the PDFs end up?
As artifacts attached to the run, retrievable through the artifacts endpoint. The webhook receives the structured list, not the files; your system decides what to fetch and where to keep it.
Read next
- Live view and takeover How a person completes the certificate step and hands the browser back
- Credentials vault What the vault stores, and why a certificate file is not on the list
- Cron expression generator For the portals that do suit a schedule
- Portal monitoring The general shape: a portal, no API, a person refreshing a page
Try it on the next notice
Five browser hours, no card. Publish the template, sign in once through the live view, and watch the inbox empty itself.