DHL business portal: fetch invoices and shipment status by workflow
Parcel invoices arrive in the business customer portal, and the shipments they bill are tracked two menus away. One template signs in with a vaulted login, lists the month's invoices, checks the shipments you name and posts both to accounts payable.
What a person clicks in the portal
Taken from DHL's public pages for the business customer portal. Where the exact label is uncertain this page says so instead of guessing.
-
Sign in
Open the business customer portal and sign in with the portal user name and password. Accounts may have a second factor enabled; the public pages describe it as optional.
-
Open the invoices area
The portal groups invoices under a Rechnungen entry. The list can be filtered by date and shows invoice number, date and amount; each row offers the PDF.
-
Download the PDFs you need
One click per invoice. The portal's pages do not describe a select-all download for invoices, and this template does not assume one.
-
Look up shipments
Sendungsverfolgung takes one or several shipment numbers and shows the current status with the event history. It is a separate area from invoices.
-
Book in accounts payable
Invoice number, date and gross go to the AP system; the PDF is filed under the retention rules. Shipment status goes to whoever asked.
Template, credential and monthly trigger
The two tracking blocks carry continueOnFailure, so an empty shipment list or a tracking outage does not cost you the invoices.
{
"title": "DHL business customer portal: invoices and shipment status",
"parameters": [
{
"key": "period_from",
"description": "First invoice date to include (YYYY-MM-DD)",
"required": true
},
{
"key": "period_to",
"description": "Last invoice date to include (YYYY-MM-DD)",
"required": true
},
{
"key": "shipment_numbers",
"description": "Comma-separated shipment numbers whose status you want",
"required": false,
"default": ""
},
{
"key": "ap_webhook",
"description": "Endpoint that receives invoices and statuses",
"required": true
}
],
"runSequentially": true,
"sequentialKey": "cred_dhl_gkp",
"blocks": [
{
"blockType": "login",
"label": "Sign_in",
"credentialId": "cred_dhl_gkp",
"url": "https://geschaeftskunden.dhl.de/"
},
{
"blockType": "action",
"label": "Open_invoices",
"instruction": "Open the invoices area (Rechnungen) of the business customer portal and filter invoices dated from {{ period_from }} to {{ period_to }}"
},
{
"blockType": "extraction",
"label": "Invoices",
"instruction": "Every invoice in the filtered list: invoice number, invoice date, gross amount, currency, customer number (Kundennummer), whether a PDF download is offered",
"schema": {
"type": "object",
"properties": {
"invoices": {
"type": "array",
"items": {
"type": "object",
"properties": {
"number": {
"type": "string"
},
"date": {
"type": "string"
},
"gross": {
"type": "number"
},
"currency": {
"type": "string"
},
"customerNumber": {
"type": "string"
},
"hasPdf": {
"type": "boolean"
}
},
"required": [
"number",
"date",
"gross"
]
}
}
},
"required": [
"invoices"
]
}
},
{
"blockType": "action",
"label": "Track_shipments",
"continueOnFailure": true,
"instruction": "Open shipment tracking (Sendungsverfolgung) in the portal and look up the shipment numbers {{ shipment_numbers }}; if the list is empty, do nothing"
},
{
"blockType": "extraction",
"label": "Statuses",
"continueOnFailure": true,
"instruction": "For each shipment number in {{ shipment_numbers }}: the current status, the timestamp of the last event and the delivery date if delivered",
"schema": {
"type": "object",
"properties": {
"shipments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"number": {
"type": "string"
},
"status": {
"type": "string"
},
"lastEvent": {
"type": "string"
},
"deliveredOn": {
"type": "string"
}
},
"required": [
"number",
"status"
]
}
}
},
"required": [
"shipments"
]
}
},
{
"blockType": "http_request",
"label": "Post_to_ap",
"method": "POST",
"url": "{{ ap_webhook }}",
"headers": {
"content-type": "application/json"
},
"body": "{\"invoices\": {{ Invoices_output }}, \"shipments\": {{ Statuses_output }}}"
}
]
}
import { Browserberg } from '@browserberg/sdk';
import template from './dhl-business-invoices.json' with { type: 'json' };
const bb = new Browserberg({
apiKey: process.env.BROWSERBERG_API_KEY,
baseUrl: 'https://browserberg.com',
});
const cred = await bb.credentials.create({
name: 'DHL business customer portal',
url: 'https://geschaeftskunden.dhl.de/',
fields: { username: 'logistik@example.de', password: process.env.DHL_PASSWORD },
nonSecretFields: ['username'],
});
const wf = await bb.workflows.publish({
...template,
blocks: template.blocks.map((b) =>
b.blockType === 'login' ? { ...b, credentialId: cred.id } : b),
});
// First of the month, 06:10 Berlin time; a missed night is one firing, not a backlog.
await bb.triggers.create(wf.workflowId, {
kind: 'schedule', name: 'Monthly DHL invoices',
cron: '10 6 1 * *', timezone: 'Europe/Berlin',
});
Note · From the public portal pages, not from a live account
The invoice list, its date filter and the tracking area are described as DHL's public pages present the business customer portal on the date above. The template was drafted from that description and has not been verified against a live portal login; a label may differ and an instruction may need a word changed.
Who does this today
Logistics and AP share the portal and rarely share the login.
- Accounts payable, monthly
- Someone signs in at month end, filters last month's invoices, downloads each PDF and keys the totals. Parcel invoices are numerous and small, which makes the job tedious rather than hard.
- Customer service, daily
- A shipment number from a complaint is pasted into tracking to answer the customer. The answer is a status and a timestamp, which is a copy-and-paste job with a login in front of it.
- Controlling, quarterly
- Freight cost per shipment means joining invoices to shipments, which needs both lists in the same place. Today that place is a spreadsheet.
- What breaks
- A password shared in a team chat, a second factor tied to one person's phone, and a month whose invoices were downloaded twice or not at all because two people did it.
Portal facts
| Portal | DHL business customer portal (Geschäftskundenportal) for parcel and freight customers DHL business customer portal |
|---|---|
| Login | User name and password; a second factor may be enabled on the account DHL business customer portal |
| Invoices | A filterable list with PDF per invoice, under the portal's invoices entry DHL business customer portal |
| Tracking | Shipment tracking by number inside the portal, separate from invoices DHL |
| Vault fields | username and password; optional totpSeed if the account uses an authenticator app |
As of 2026-09-08
Login, expiry and the gates
Browserberg is not affiliated with DHL or Deutsche Post; this page describes automating a portal with the business account you hold.
A vaulted password, typed on one site only
The login block names a credential the vault created for the portal's own URL. The password is released at the moment of typing and only on that registrable site; a redirect elsewhere means nothing is typed. If the account has a second factor from an authenticator app, the seed lives in the vault too and the code is generated at login. A second factor by SMS turns the sign-in into a person's step through the live view, after which the run continues on that session.
What ends a session
The portal signs out after inactivity. The template does not wait for anyone, so a run finishes long before that; runSequentially keyed on the credential prevents two runs from evicting each other on a portal that allows one login at a time.
Refusals you should expect
The effect gates classify the element under each click. Filtering, downloading and tracking are read effects. The business portal also contains controls that create shipments, order pickups or change payment data; a label the gate reads as payment or destructive is refused under the default policy, and the run stops with the block named. A propose policy would hand such a step to a person instead. Nothing in this template goes near those screens, and the gate does not take the template's word for it.
Questions from logistics and AP
Does it download every invoice PDF?
The published template lists the invoices and reports which offer a PDF. To fetch each file, add a loop over Invoices_output.invoices with an action block that opens the row and downloads; each file becomes an artifact of the run.
What if a shipment number is unknown?
The tracking extraction reports it with whatever status the portal shows, or the block fails and, since it carries continueOnFailure, the run still posts the invoices.
Can two departments use one template?
Yes, but give each a credential of its own and a workflow of its own. Failures stay local and the action log says which team's run did what.
Does the webhook body have to be JSON?
No, but this one is: the body template composes both outputs into one object. A single expression such as the Invoices output alone would be sent as the array itself.
Is any of this hidden from DHL?
No. The portal sees a Chromium session under your account from EU hardware. There is no stealth and no attempt to look like a different client.
Run it for last month
Five browser hours, no card. Vault the portal login, publish the template and compare the JSON with the folder somebody downloaded by hand.