Startseite » Produkte » DigiBrief: Briefe digital versenden » Briefversand automatisieren » Briefe per API & Schnittstelle versenden

Briefe per API & Schnittstelle versenden: digiBrief automatisiert

Mit der digiBrief-API versenden Sie Briefe direkt aus Ihrer eigenen Software: Sie übergeben ein PDF per REST-Schnittstelle — Druck, Kuvertierung, Frankierung und Übergabe an die Zustellung übernimmt . Kein Drucker, kein Portohandling, kein Gang zur Post.

Die Schnittstelle ist bewusst schlank: ein Bearer-Token, JSON, zwei Pflichtfelder. Wer schon einmal eine REST-API angebunden hat, ist an einem Arbeitstag fertig. Diese Seite enthält alles, was dafür nötig ist — Endpunkte, Feldgrenzen, Statuscodes, Fehlerverhalten und Codebeispiele in fünf Sprachen.

Auf einen Blick

Basis-URLhttps://digibrief-api.easynova.de
ProtokollREST, JSON (UTF-8), PDF als Base64
AuthentifizierungBearer-Token, 8 Stunden gültig
Interaktive DokumentationSwagger UI — öffentlich, ohne Login
Maschinenlesbare BeschreibungOpenAPI 3.0 unter https://digibrief-api.easynova.de/swagger/v1/swagger.json
Grenzen20 MB je Sendung, 300 MB je Aufruf, DIN A4 Hochformat
Verschlüsselungdurchgehend TLS
Kosten der Schnittstellekeine — Sie zahlen nur den Brief

Die Schnittstelle kennt acht Endpunkte. Drei davon brauchen Sie für den Regelbetrieb, die übrigen sind optional.

EndpunktZweck
POST /api/LoginAnmelden, Token holen
POST /api/letterEine Sendung oder einen ganzen Stapel einliefern
GET /api/letter/{letterId}Status einer einzelnen Sendung
GET /api/letter/BatchStatus aller Sendungen einer batchID
GET /api/companyBillingGuthaben und Abrechnungsdaten des Kontos
POST /api/pricePreviewPreis einer Sendung abfragen, ohne einzuliefern
GET /api/accountKonfiguration Ihres Kontos abfragen
GET /healthVerfügbarkeitsprüfung für Ihr Monitoring
easyNova digiBrief REST-API (Swagger/OpenAPI 3.0) mit Endpunkten zum Einliefern und zum Statusabruf von Briefen
Die Swagger-UI ist öffentlich erreichbar — Endpunkte anklicken, Felder ansehen, Aufrufe direkt ausprobieren.

In drei Schritten zur ersten Sendung

1. Anmelden

POST /api/Login
Content-Type: application/json

{ "ekp": "ihr-konto@beispiel.de", "password": "IHR-KENNWORT" }

Die Antwort enthält das Token im Feld token. Es gilt 8 Stunden und wird bei allen weiteren Aufrufen als Kopfzeile mitgegeben: Authorization: Bearer IHR-TOKEN. Einen Verlängerungsendpunkt gibt es nicht — nach Ablauf melden Sie sich erneut an. Falsche Zugangsdaten beantwortet der Endpunkt mit HTTP 400.

Das Token ist zum Wiederverwenden gedacht. Melden Sie sich einmal an und benutzen Sie dasselbe Token für alle Aufrufe der folgenden acht Stunden — nicht für jeden Brief neu. Jede Anmeldung schickt Ihr Kennwort über die Leitung und ist der langsamste Aufruf der ganzen Schnittstelle. Wer das Token hält, meldet sich dreimal am Tag an statt hundertmal.

Verlassen Sie sich dabei nicht allein auf die Uhr. Ein Token kann auch vor Ablauf ungültig werden — nach einem Kennwortwechsel, auf Ihren Wunsch oder von uns aus, etwa bei Verdacht auf einen weitergegebenen Zugang. Der Server antwortet dann mit HTTP 401, und das ist keine Störung, sondern die Aufforderung, sich neu anzumelden.

  1. Beim ersten Aufruf anmelden und das Token behalten.
  2. Es für alle weiteren Aufrufe benutzen.
  3. Bei 401 einmal neu anmelden und den Aufruf wiederholen — danach läuft es weiter.

Genau einmal, nie in einer Schleife. Bleibt es beim zweiten Versuch bei 401, stimmt etwas mit den Zugangsdaten nicht; weitere Anläufe erzeugen nur Last. Und beim Einliefern wiederholen Sie nur mit demselben Idempotency-Key.

Zwei Feldnamen stiften erfahrungsgemäß Verwirrung. ekp ist ein Erbstück aus der Postsprache (Einheitliche Kundennummer) und nimmt schlicht Ihren Benutzernamen entgegen — in aller Regel die E-Mail-Adresse des Kontos. Die Felder vendorId und secret tauchen in der Spezifikation noch auf, werden aber nur aus Kompatibilität zur Vorgängerversion angenommen und nicht ausgewertet. Sie brauchen sie nicht.

2. Brief einliefern

POST /api/letter
Authorization: Bearer IHR-TOKEN
Content-Type: application/json

[
  {
    "fileName": "rechnung_4711.pdf",
    "data": "PDF-INHALT-ALS-BASE64",
    "isColor": false,
    "isDuplex": false,
    "testFlag": true,
    "testEMail": "ihre-adresse@example.com",
    "testShowRestrictedArea": true
  }
]

Der Rumpf ist immer ein Array, auch bei einem einzelnen Brief. Das ist die häufigste Stolperstelle beim ersten Aufruf. Die Antwort liefert je Brief eine dauerhafte Kennung:

[ { "fileName": "rechnung_4711.pdf", "letterID": 100123 } ]

Tipp für den Einstieg: Lassen Sie testFlag auf true, bis Ihre Integration steht. Testsendungen durchlaufen sämtliche Prüfungen, werden aber weder gedruckt noch zugestellt.

3. Status verfolgen

GET /api/letter/100123
Authorization: Bearer IHR-TOKEN

Haben Sie beim Einliefern eine eigene batchID vergeben, fragen Sie den ganzen Stapel auf einmal ab: GET /api/letter/Batch. Mit dem Parameter onlyIssues bekommen Sie ausschließlich die Sendungen zurück, bei denen etwas nicht stimmt — praktisch, wenn Sie täglich vierstellige Stückzahlen einliefern und nur die Ausreißer sehen wollen.

Codebeispiele: Anmelden, Briefe einliefern, Status abfragen

Jedes Beispiel zeigt den vollständigen Ablauf und arbeitet mit testFlag: true — es durchläuft alle Prüfungen, gedruckt wird nichts. Für den Produktivbetrieb setzen Sie testFlag auf false oder lassen das Feld weg; testEMail und testShowRestrictedArea können stehen bleiben — ohne testFlag: true sind sie wirkungslos. Drei Muster stecken bewusst in allen Beispielen: das Token wird wiederverwendet statt vor jedem Aufruf neu geholt, die Zugangsdaten kommen aus Umgebungsvariablen statt aus dem Quelltext, und Fehler werden aus der errorList gelesen — dort steht die Begründung im Klartext. Die Beispiele brechen bei jedem Fehler ab — welche Antworten stattdessen eine Wiederholung verlangen, steht unten unter Fehler behandeln. Pflicht sind allein fileName und data — die Empfängeradresse liest aus dem PDF. Wollen Sie Adressdaten zur eigenen Zuordnung mitgeben, ergänzen Sie addressLine1, zipCode und city; auf die Zustellung haben sie keinen Einfluss.

curl

# 1. Anmelden – Token gilt 8 Stunden
TOKEN=$(curl -s https://digibrief-api.easynova.de/api/Login \
  -H "Content-Type: application/json" \
  -d "{\"ekp\":\"$DIGIBRIEF_BENUTZER\",\"password\":\"$DIGIBRIEF_KENNWORT\"}" \
  | jq -r .token)

# 2. Testbrief einliefern – der Rumpf ist immer ein ARRAY.
#    Empfängeradresse kommt aus dem PDF – hier sind keine Adressfelder nötig.
base64 -w0 brief.pdf | jq -Rs '[{fileName: "brief.pdf", data: ., testFlag: true,
  testEMail: "ihre-adresse@example.com", testShowRestrictedArea: true}]' > brief.json

curl -s https://digibrief-api.easynova.de/api/letter \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data-binary @brief.json
# Antwort: [{"fileName":"brief.pdf","letterID":100123}]

# 3. Status abfragen
curl -s https://digibrief-api.easynova.de/api/letter/100123 \
  -H "Authorization: Bearer $TOKEN"

PowerShell

# Windows PowerShell 5.1 braucht die TLS-Zeile, PowerShell 7 nicht.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$basis = 'https://digibrief-api.easynova.de'

# 1. Anmelden – Token 8 Stunden aufheben
$zugang = @{ ekp = $env:DIGIBRIEF_BENUTZER; password = $env:DIGIBRIEF_KENNWORT } | ConvertTo-Json
$login  = Invoke-RestMethod -Method Post -Uri "$basis/api/Login" -ContentType 'application/json' -Body $zugang
$kopf   = @{ Authorization = "Bearer $($login.token)" }

# 2. Testbrief einliefern – das führende Komma erzwingt ein Array
$pdf = [Convert]::ToBase64String([IO.File]::ReadAllBytes('brief.pdf'))
# Empfängeradresse kommt aus dem PDF – hier sind keine Adressfelder nötig
$briefe = ,@{ fileName = 'brief.pdf'; data = $pdf; testFlag = $true; testEMail = 'ihre-adresse@example.com'; testShowRestrictedArea = $true }
$antwort = Invoke-RestMethod -Method Post -Uri "$basis/api/letter" -Headers $kopf -ContentType 'application/json' -Body (ConvertTo-Json $briefe -Depth 5)
$letterId = $antwort[0].letterID

# 3. Status abfragen – bei 99 steht die Begruendung in der errorList
$status = Invoke-RestMethod -Uri "$basis/api/letter/$letterId" -Headers $kopf
"Status $($status.statusID): $($status.statusDetails)"
$status.errorList | ForEach-Object { "  $($_.code): $($_.description)" }

C# (.NET 8)

using System.Net.Http.Headers;
using System.Net.Http.Json;
using System.Text.Json;

using var http = new HttpClient { BaseAddress = new Uri("https://digibrief-api.easynova.de") };

// 1. Anmelden – Token 8 Stunden wiederverwenden
var login = await http.PostAsJsonAsync("/api/Login", new
{
    ekp      = Environment.GetEnvironmentVariable("DIGIBRIEF_BENUTZER"),
    password = Environment.GetEnvironmentVariable("DIGIBRIEF_KENNWORT")
});
login.EnsureSuccessStatusCode();
var token = (await login.Content.ReadFromJsonAsync<JsonElement>()).GetProperty("token").GetString();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

// 2. Testbrief einliefern – der Rumpf ist immer ein Array
var pdf = await File.ReadAllBytesAsync("brief.pdf");   // Base64 macht der Serialisierer
var antwort = await http.PostAsJsonAsync("/api/letter", new[]
{
    new
    {
        // Empfängeradresse kommt aus dem PDF – hier sind keine Adressfelder nötig
        fileName = "brief.pdf",
        data     = pdf,
        testFlag = true,
        testEMail              = "ihre-adresse@example.com",
        testShowRestrictedArea = true
    }
});
antwort.EnsureSuccessStatusCode();
var letterId = (await antwort.Content.ReadFromJsonAsync<JsonElement>())[0].GetProperty("letterID").GetInt32();

// 3. Status abfragen – bei 99 steht die Begruendung in der errorList
var status = await http.GetFromJsonAsync<JsonElement>($"/api/letter/{letterId}");
Console.WriteLine($"Status {status.GetProperty("statusID").GetInt32()}: {status.GetProperty("statusDetails").GetString()}");
foreach (var fehler in status.GetProperty("errorList").EnumerateArray())
    Console.WriteLine($"  {fehler.GetProperty("code")}: {fehler.GetProperty("description")}");

Python

import base64, os, requests

BASIS = "https://digibrief-api.easynova.de"

# 1. Anmelden – Token 8 Stunden aufheben
login = requests.post(f"{BASIS}/api/Login", json={
    "ekp": os.environ["DIGIBRIEF_BENUTZER"],
    "password": os.environ["DIGIBRIEF_KENNWORT"],
})
login.raise_for_status()
kopf = {"Authorization": f"Bearer {login.json()['token']}"}

# 2. Testbrief einliefern – der Rumpf ist immer eine LISTE
with open("brief.pdf", "rb") as f:
    pdf_b64 = base64.b64encode(f.read()).decode()

antwort = requests.post(f"{BASIS}/api/letter", headers=kopf, json=[{
    # Empfängeradresse kommt aus dem PDF – hier sind keine Adressfelder nötig
    "fileName": "brief.pdf",
    "data": pdf_b64,
    "testFlag": True,
    "testEMail": "ihre-adresse@example.com",
    "testShowRestrictedArea": True,
}])
antwort.raise_for_status()
letter_id = antwort.json()[0]["letterID"]

# 3. Status abfragen – bei 99 steht die Begruendung in der errorList
status = requests.get(f"{BASIS}/api/letter/{letter_id}", headers=kopf).json()
print(f"Status {status['statusID']}: {status['statusDetails']}")
for fehler in status["errorList"]:
    print(f"  {fehler['code']}: {fehler['description']}")

PHP

<?php
$basis = 'https://digibrief-api.easynova.de';

function aufruf(string $url, ?string $token = null, ?string $json = null): array {
    $ch   = curl_init($url);
    $kopf = ['Content-Type: application/json'];
    if ($token) $kopf[] = "Authorization: Bearer $token";
    curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => $kopf]);
    if ($json !== null) {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $json);
    }
    $antwort = curl_exec($ch);
    $code    = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    curl_close($ch);
    if ($code >= 400) throw new RuntimeException("HTTP $code: $antwort");
    return json_decode($antwort, true);
}

// 1. Anmelden – Token 8 Stunden aufheben
$login = aufruf("$basis/api/Login", null, json_encode([
    'ekp'      => getenv('DIGIBRIEF_BENUTZER'),
    'password' => getenv('DIGIBRIEF_KENNWORT'),
]));
$token = $login['token'];

// 2. Testbrief einliefern – der Rumpf ist immer ein ARRAY von Briefen
$briefe = [[
    // Empfängeradresse kommt aus dem PDF – hier sind keine Adressfelder nötig
    'fileName' => 'brief.pdf',
    'data'     => base64_encode(file_get_contents('brief.pdf')),
    'testFlag' => true,
    'testEMail' => 'ihre-adresse@example.com',
    'testShowRestrictedArea' => true,
]];
$antwort  = aufruf("$basis/api/letter", $token, json_encode($briefe));
$letterId = $antwort[0]['letterID'];

// 3. Status abfragen – bei 99 steht die Begruendung in der errorList
$status = aufruf("$basis/api/letter/$letterId", $token);
echo "Status {$status['statusID']}: {$status['statusDetails']}" . PHP_EOL;
foreach ($status['errorList'] as $fehler) {
    echo "  {$fehler['code']}: {$fehler['description']}" . PHP_EOL;
}

Für jede andere Sprache laden Sie die maschinenlesbare Schnittstellenbeschreibung unter https://digibrief-api.easynova.de/swagger/v1/swagger.json in Postman, Insomnia oder einen OpenAPI-Generator — damit erzeugen Sie sich Aufrufbeispiele und Client-Klassen selbst. Ein eigenes SDK brauchen Sie dafür nicht, und Sie sind nicht darauf angewiesen, dass wir eines für Ihre Sprache pflegen.

Fehler behandeln: was endgültig ist und was nicht

Die fünf Beispiele oben brechen bei jedem Fehler ab. Für den ersten Lauf ist das richtig — Sie wollen sehen, dass etwas schiefging. Im Dauerbetrieb ist es zu grob: Drei Antworten bedeuten „später noch einmal“, nicht „aufgeben“.

AntwortBedeutungWas zu tun ist
400Anfrage unvollständig oder Zugangsdaten falschendgültig — nicht wiederholen
401Token abgelaufen oder entwerteteinmal neu anmelden, Aufruf wiederholen
403dem Token fehlt eine Berechtigungendgültig
422fachlich abgelehnt, etwa eine unzulässige Einschreiben-Artendgültig — erst die Anfrage ändern
429zu viele fehlgeschlagene AnmeldungenRetry-After abwarten, dann einmal
503vorübergehend nicht möglichRetry-After abwarten, dann einmal

Bei 503 wurde nichts gesendet und nichts gespeichert. Die Wiederholung erzeugt also keinen zweiten Brief. Bei allen übrigen Wiederholungen der Einlieferung gilt: nur mit demselben Idempotency-Key.

Und immer genau einmal wiederholen, nie in einer Schleife. Bleibt es beim zweiten Versuch beim selben Fehler, hilft kein weiterer Anlauf — er erzeugt nur Last, und bei 429 verlängert jeder Fehlversuch die Wartezeit.

import time

def mit_wartefrist(aufruf, neu_anmelden):
    """401: einmal neu anmelden. 429/503: Retry-After abwarten, einmal wiederholen."""
    antwort = aufruf()

    if antwort.status_code == 401:
        neu_anmelden()
        antwort = aufruf()
    elif antwort.status_code in (429, 503):
        time.sleep(int(antwort.headers.get("Retry-After", "5")))
        antwort = aufruf()

    antwort.raise_for_status()   # alles andere bleibt endgueltig
    return antwort

Eine Besonderheit bei curl: curl -s prüft von sich aus gar nichts — auch bei 500 liefert es den Rumpf und den Rückgabewert 0. Mit --fail-with-body bekommen Sie einen Fehlercode und trotzdem die Meldung des Servers.

Das PDF: worauf es ankommt

Die Zustelladresse liest aus Ihrem Dokument — aus dem Adressfenster der ersten Seite, bei Bedarf per Texterkennung. Das ist die wichtigste Eigenschaft der Schnittstelle und der häufigste Grund, warum eine erste Integration nicht funktioniert: Wer die Adresse nur im JSON übergibt und im PDF weglässt, bekommt eine Ablehnung.

Diese Entscheidung ist Absicht. Was auf dem Brief steht, wird zugestellt — eine Abweichung zwischen Dokument und Versanddaten kann es damit gar nicht geben. Daraus ergeben sich drei Gestaltungsregeln:

  1. Empfängeradresse ins Adressfenster der ersten Seite, positioniert wie bei einem DIN-5008-Geschäftsbrief.
  2. Absender ins Absenderfeld. Über dem Adressfenster steht die Absenderzeile — Name, Straße, PLZ und Ort in einer Zeile, wie sie im Fensterumschlag sichtbar ist. Sie ist nicht optional: Ein Brief ohne erkennbaren Absender wird abgelehnt, nicht kommentarlos versendet. Das gilt für alle Konten mit Freimachungszone, und das ist der Regelfall. Das Feld senderAdressLineComplete ersetzt ihn nicht — es wird gespeichert, aber nicht in den Brief gesetzt.
  3. Frankierzone freihalten. Der obere Bereich des Adressfensters ist für den Freimachungsvermerk reserviert. Anderer Inhalt in dieser Zone (Logos, Grafiken) führt zur Ablehnung — mit Begründung, nie stillschweigend. Wie eine solche Sperrfläche aussieht, zeigt anschaulich unser Beitrag Sperrflächen-Updates für E-POST Briefe samt Schablone zum Herunterladen. Verbindlich für Ihren Ausgabekanal ist aber der Testmodus: testShowRestrictedArea zeichnet im Testmodus (mit testEMail) die geltenden Flächen direkt auf Ihr eigenes Dokument — auch wenn die Sendung abgelehnt wird; dann ist die Stelle hervorgehoben, an der sie scheitert.
  4. Adresse zu weit oben? Nur auf Anforderung wird korrigiert. Sitzt die Empfängeradresse so, dass sie mit der Freimachungszone kollidiert, kann sie für Sie an die zulässige Stelle setzen — aber nicht von selbst. Geben Sie dazu "addressCorrection": "auto" mit. Ihr Layout bleibt unverändert, nur der Adressblock wird neu gesetzt; Briefe mit korrekt sitzender Adresse werden nicht angetastet. Ohne diese Anforderung wird ein Brief mit kollidierender Adresse abgelehnt — die Fehlermeldung nennt dann ausdrücklich auto als Ausweg und listet die für Ihr Konto hinterlegten Korrekturprofile.
  5. Format: DIN A4 im Hochformat, maximal 20 MB je Sendung und 300 MB je Aufruf.

Die JSON-Adressfelder (addressLine1, zipCode, city …) sind optional: Sie können sie zur eigenen Zuordnung mitgeben — dann erscheinen sie unverändert in der Statusauskunft —, auf die Zustellung haben sie keinen Einfluss. Maßgeblich ist immer die Adresse im PDF.

Auslandsversand folgt derselben Logik: Steht eine ausländische Empfängeradresse im Adressfenster, wird der Brief dorthin zugestellt. Ein zusätzliches Feld ist dafür nicht nötig. Die Portokosten richten sich nach dem Zielland — die geltenden Sätze finden Sie unter digiBrief-Preise.

Die Felder im Überblick

Eine Sendung kennt 37 Felder. Pflicht sind genau zwei — der Dateiname und das PDF. Mit ihnen allein versenden Sie bereits produktiv; alles Weitere ist Feinsteuerung.

FeldPflichtBedeutung und Grenzen
fileNamejaDateiname aus Ihrem System
datajaDas PDF, Base64-kodiert
addressCorrectionneinAdresskorrektur anfordern: "auto" setzt die Empfängeradresse selbst an die zulässige Stelle, "favorit" nimmt das für Ihr Konto hinterlegte Profil, oder Sie nennen ein Profil beim Namen. Ohne dieses Feld wird nicht korrigiert.
registeredLetterneinEinschreiben-Variante, im Klartext oder als ePost-Kürzel (bis 50 Zeichen)
senderAdressLineCompleteneinAbsenderzeile als Metadatum, bis 100 Zeichen — gespeichert, aber nicht gedruckt. Der Absender muss im PDF stehen.
senderAdressLine1, senderStreet, senderZipCode, senderCityneinAbsender-Metadaten zur eigenen Zuordnung, je bis 100 Zeichen — ohne Einfluss auf die Zustellung. Maßgeblich ist der Absender im PDF.
addressLine1 bis addressLine5neinEmpfänger-Metadaten zur eigenen Zuordnung, je bis 80 Zeichen — ohne Einfluss auf die Zustellung
zipCode, city, countryneinEbenfalls reine Zuordnungshilfen (bis 20 bzw. 80 Zeichen)
isColorneinFarbdruck (Vorgabe: schwarzweiß)
isDuplexneinBeidseitiger Druck (Vorgabe: einseitig) — bei Einschreiben nicht möglich
batchIDneinIhre Stapelkennung für die Sammelabfrage
testFlagneinTestmodus: prüfen, ohne zu drucken
testEMailneinAdresse für die Testrückmeldung, bis 100 Zeichen
testShowRestrictedAreaneinTestrückmeldung mit eingezeichneten Prüfflächen

Ein Hinweis zu zwei Feldern, die die Verarbeitung nicht steuern: custom1 bis custom5 und costCenter werden angenommen und gespeichert, beeinflussen den Versand aber nicht. custom1–custom5 kommen in der Statusauskunft unverändert zurück und sind damit der Weg, eigene Vorgänge zuzuordnen — costCenter wird dort nicht zurückgegeben. Als weiteren verlässlichen Anker haben Sie fileName: Der Dateiname kommt ebenfalls unverändert zurück.

Entfernt am 9. September 2026: plugInList stand bis dahin in dieser Reihe. Das Feld ist aus der Spezifikation heraus und wurde nie verarbeitet. Wer es weiter mitsendet, bekommt unverändert 200 — unbekannte Anfragefelder werden ignoriert.

Gefahrlos testen

Der Testmodus ist ein vollwertiger Probelauf, kein Trockenlauf. Mit testFlag: true durchläuft Ihre Sendung sämtliche Prüfungen — Adresserkennung, Flächenprüfung, Aufbereitung — und wird beim Versanddienst als Testsendung registriert. Gedruckt und zugestellt wird nichts.

Das Flag gilt je Sendung: Testbriefe und echte Briefe dürfen im selben Stapel stehen. Sie müssen Ihre Integration also nicht in einem Rutsch scharf schalten, sondern können sie schrittweise umstellen. Der Statusabruf gibt testFlag zurück — Sie sehen jederzeit, ob eine Sendung ein Testbrief war.

Geben Sie zusätzlich testEMail an (bis 100 Zeichen), kommt genau das Dokument per E-Mail zurück, das gedruckt worden wäre — dazu die Sendungsnummer. Das wirkt nur zusammen mit testFlag: true.

testShowRestrictedArea: true ist eine Darstellungsoption dieser Test-E-Mail, keine eigene Funktion: In das zurückgesendete PDF werden die für Ihr Konto geltenden Flächen eingezeichnet — rot die Prüfflächen (Freimachungszone und weitere gesperrte Bereiche), blau die Auslesefenster für Empfängeradresse und Absender, jeweils beschriftet. Damit sehen Sie vor dem ersten echten Brief, ob Ihr Layout sitzt. Ohne testFlag und testEMail bleibt das Flag wirkungslos — es wird ohne Hinweis ignoriert.

Auch eine abgelehnte Testsendung bekommt mit testShowRestrictedArea eine Mail — mit dem Betreff „NICHT angenommen“, dem Grund der Ablehnung und Ihrem Dokument mit Schablone. Kräftig hervorgehoben ist, woran die Prüfung gescheitert ist: eine verletzte Prüffläche („verletzt“) oder das Fenster, in dem Adresse oder Absender nicht gefunden wurden („nicht erkannt“, „fehlt“, „ungültig“). Das gilt für Ablehnungen wegen Adresse, Absender und Prüfflächen; andere Gründe nennt die Statusabfrage.

Die Test-E-Mail ist ein Zusatzweg, kein Statussignal. Ihr Versand ist vom Ergebnis der Sendung entkoppelt: Kommt die Mail nicht an, sagt das nichts über den Brief aus — maßgeblich ist immer die Statusabfrage. Prüfen Sie in dem Fall Adresse und Spam-Ordner. Steht der Test-E-Mail-Rückweg nicht zur Verfügung — testMailAvailable unter Was Ihr Konto kann sagt es Ihnen vorab —, wird eine Testsendung mit testEMail mit klarer Meldung abgelehnt, statt stillschweigend verschluckt zu werden.

Ihre Testsendungen im Postausgangsbuch ansehen. Neben dem zurückgesendeten PDF können Sie Ihre Testsendungen auch im Postausgangsbuch des Web-Clients öffnen, samt Dokumentanzeige. Dort erscheinen ausschließlich angenommene Sendungen — und genau das macht die Ansicht zur dritten Prüfmöglichkeit: Finden Sie eine Einlieferung dort nicht, hat die Ablehnung gegriffen. Abgelehnte Sendungen werden nicht an das Backend weitergegeben; die Begründung steht dann in errorList.

Die Dokumentanzeige ist standardmäßig ausgeschaltet. Briefinhalte sind personenbezogene Daten, deshalb ist die Voreinstellung bewusst restriktiv. Auf Anfrage über den Support schalten wir sie für Ihr Konto frei — nennen Sie dabei Ihre Firma und die gewünschte Sichtbarkeitsdauer (10, 14 oder 30 Tage). Während einer API-Anbindung ist das erfahrungsgemäß hilfreich.

Anmeldung und Token: was schiefgehen kann

Ausgestellte Token entwerten

Wenn ein Token in falsche Hände geraten sein könnte, gilt: Ein Token bleibt bis zu acht Stunden gültig, auch wenn Sie nichts mehr damit tun. Wer es hat, kann in dieser Zeit Briefe auf Ihre Kosten einliefern. Um es zu entwerten, brauchen Sie weder einen Anruf noch eine E-Mail:

  1. Ändern Sie Ihr Kennwort — wie gewohnt im -Portal.
  2. Melden Sie sich einmal über POST /api/Login mit dem neuen Kennwort an.

Damit ist alles erledigt:

altes Kennwortfunktioniert nicht mehr
alle zuvor ausgestellten Tokensofort ungültig, sie antworten mit 401
das Token aus Schritt 2gültig

Der zweite Schritt ist der wirksame — erst die Anmeldung mit dem neuen Kennwort entwertet die alten Token. Das Kennwort allein zu ändern genügt nicht.

Ihre laufenden Dienste melden sich danach von selbst neu an, sofern sie 401 behandeln. Sie brauchen nichts zu stoppen — achten Sie nur darauf, dass überall das neue Kennwort hinterlegt ist, sonst bleiben sie an der Anmeldung hängen.

Ein normaler Login entwertet nichts. Sie können sich weiterhin von mehreren Diensten aus parallel anmelden; jedes Token lebt seine acht Stunden. Nur der Wechsel des Kennworts macht die Vorgänger ungültig.

Möchten Sie Token entwerten, ohne das Kennwort zu wechseln? Das geht derzeit nur über uns — melden Sie sich über den Support, dann erledigen wir es.

Zu viele Anmeldeversuche: 429

Die Anmeldung ist gedrosselt. Zwei Schranken greifen, und beide betreffen ausschließlich POST /api/Login — Einlieferung, Statusabruf und Preisvorschau laufen ungebremst.

SchrankeWertAntwort
Fehlgeschlagene Anmeldungen je Benutzername10 in 5 Minuten429 mit Retry-After in Sekunden
Anmeldeaufrufe je Absender-IPgroßzügig bemessen — im Normalbetrieb nicht erreichbar429

Gezählt werden nur Fehlschläge, also die mit 400 beantworteten Anmeldungen. Eine erfolgreiche Anmeldung setzt den Zähler sofort zurück; eine Störung auf unserer Seite erhöht ihn nicht. Wer sich nach neun Fehlversuchen richtig anmeldet, fängt wieder bei null an.

Retry-After nennt die Wartezeit in Sekunden — und zwar die tatsächliche: Der Name wird frei, sobald der älteste Fehlversuch aus dem Fünf-Minuten-Fenster fällt, nicht erst fünf Minuten nach dem letzten. Warten Sie diese Frist ab und wiederholen Sie dann einmal. Eine Schleife verlängert die Sperre, weil jeder weitere Fehlversuch mitzählt.

Die Antwort trägt einen erklärenden Text:

{
  "message": "Zu viele fehlgeschlagene Anmeldungen für diesen Benutzernamen.
              Bitte warten Sie 283 Sekunden und versuchen Sie es erneut. …"
}

Ein 429 sagt nichts darüber aus, ob es den Benutzernamen gibt. Gedrosselt wird der eingegebene Name, auch ein unbekannter — andernfalls wäre die Drossel ein Werkzeug, um gültige Konten zu erraten.

Der häufigste Auslöser ist kein Angriff, sondern ein Dienst, der sich vor jedem Aufruf neu anmeldet und dabei veraltete Zugangsdaten benutzt. Wer das Token hält und auf 401 reagiert, sieht diese Drossel nie.

Verbindungsabbrüche: der Idempotency-Key

Was passiert, wenn Ihre Verbindung abbricht, nachdem Sie den Brief gesendet haben, aber bevor die Antwort ankommt? Ohne Absicherung müssten Sie raten: nochmal senden und einen zweiten Brief riskieren — oder nicht senden und vielleicht gar keinen verschicken.

Geben Sie deshalb beim Einliefern eine Kopfzeile mit:

POST /api/letter
Authorization: Bearer IHR-TOKEN
Idempotency-Key: auftrag-2026-08-4711

Wiederholen Sie den Aufruf im Zweifelsfall einfach mit demselben Schlüssel: Sie erhalten die ursprüngliche letterID zurück, und es wird nichts ein zweites Mal gedruckt. Als Schlüssel eignet sich jede Kennung, die in Ihrem System eindeutig ist — Vorgangs-, Auftrags- oder Rechnungsnummer (bis 180 Zeichen).

Liefern Sie mehrere Briefe in einem Aufruf ein, gilt der Schlüssel für den gesamten Aufruf; behalten Sie bei einer Wiederholung dann die Reihenfolge der Briefe bei.

Wiederholungen sind sicher — mit Idempotency-Key. Wiederholen Sie einen Aufruf mit demselben Idempotency-Key und demselben PDF innerhalb von 15 Minuten, wird der Brief nicht ein zweites Mal gedruckt, auch nicht bei zwei gleichzeitigen Aufrufen. Ohne Idempotency-Key ist jeder Aufruf eine neue Sendung — wer denselben Brief zweimal einliefert, bekommt ihn zweimal gedruckt.

Zwei Feinheiten, die in der Praxis zählen: Nach Ablauf des Fensters ist derselbe Brief wieder eine neue Sendung — der Mahnlauf nächste Woche geht also durch. Und eine abgelehnte Sendung blockiert nichts: Dort ist kein Porto entstanden, und die erneute Einlieferung nach einer Korrektur ist der normale Weg.

Das Statusmodell

statusIDBedeutung
1Annahme der Sendung
2Verarbeitung der Sendung
3Einlieferung in das Druckzentrum
4Verarbeitung im Druckzentrum
99Verarbeitungsfehler — Begründung in der errorList

Jede Ablehnung trägt eine verständliche Begründung, etwa „Dokument Seite 1: Inhalt verletzt Sperrfläche DV-Freimachung“. Die errorList ist damit die erste Anlaufstelle bei Problemen — nicht der Support.

Statuswechsel folgen dem Produktionsrhythmus. Eine Abfrage mehrmals täglich genügt; häufigeres Abfragen liefert keine neueren Daten und belastet nur beide Seiten. Für Monitoring-Zwecke gibt es GET /health — der Endpunkt meldet, ob die Schnittstelle Anfragen an ihre Datenbank beantworten kann.

Zeitangaben kommen in Ortszeit mit Versatz: Felder wie createdDate lauten 2026-08-21T13:55:03.769854+02:00 — deutsche Ortszeit mit Zeitzonenversatz, im Winter +01:00, nicht UTC. Wer den Versatz mitliest, rechnet richtig; wer ein Z erwartet, liegt um zwei Stunden daneben.

Testsendungen bleiben auf statusID 1. Eine Sendung mit testFlag: true wird geprüft, aber nicht produziert — sie durchläuft die Stufen 2 bis 4 deshalb nicht und behält dauerhaft Status 1. Das ist der Sollzustand und kein Fehler: Warten Sie beim Testen nicht auf Status 4. Ob die Prüfung sauber durchgelaufen ist, sehen Sie an statusID 1 ohne Einträge in errorList — und am zurückgesendeten PDF, wenn Sie testEMail gesetzt haben.

Welche Felder die Statusauskunft füllt

Die Antwort enthält aus historischen Gründen mehr Felder, als befüllt. Diese Übersicht erspart Ihnen das Rätselraten:

FeldInhalt
letterID, fileName, statusID, statusDetails, createdDateimmer gefüllt — die Kernauskunft
noOfPagesSeitenzahl nach der Aufbereitung. Bei beidseitigem Druck mit ungerader Seitenzahl wird eine leere Rückseite angehängt — dann meldet noOfPages eine Seite mehr, als Sie eingeliefert haben. Der Preis ändert sich dadurch nicht, weil je Blatt abgerechnet wird.
errorListBegründungen bei Status 99, sonst leer
processedDateZeitpunkt der Produktion im Druckzentrum, sobald der Versanddienst ihn meldet. Ein Brief kann seinen Endstatus erreichen, bevor das Datum vorliegt — leer heißt „liegt noch nicht vor“, nicht „gibt es nicht“.
testFlag, testEMail, testShowRestrictedAreaEcho Ihrer Testmodus-Angaben
registeredLetterEcho der beauftragten Einschreiben-Art
batchID, zipCode, city, country, isColor, isDuplexEcho Ihrer Angaben zur Wiedererkennung
registeredLetterID, registeredLetterStatus, registeredLetterStatusDateSendungsnummer der Post, weiterführender Zustellstatus und dessen Zeitstempel — bei Einschreiben gefüllt. Im Testmodus bleiben sie dauerhaft leer.
custom1–custom5kommen unverändert zurück — Ihr Anker, um Kosten und Status einem eigenen Vorgang zuzuordnen
priceNet, priceWithTaxder tatsächlich abgerechnete Preis in Euro, netto und mit Umsatzsteuer — gefüllt ab der Nachtübertragung, also meist schon vor dem Druck. Am Einlieferungstag und bei Testsendungen leer. Siehe unten.
costCenter, subVendorID, vendorSystemInformation, frankierID, destinationAreaStatus, destinationAreaStatusDate, printUploadDate, printFeedbackDatebleiben leer — sie stehen aus Kompatibilitätsgründen in der Schnittstellenbeschreibung, werden von digiBrief aber nicht befüllt. Warten Sie nicht auf sie, auch nicht auf die beiden Datumsfelder.
coverLetterimmer false — Deckblätter werden nicht unterstützt, siehe Einschreiben.

Alle Felder bleiben dauerhaft Teil der Antwort; Ihre Integration muss also nichts umstellen.

Was kostet ein Brief? Die Preisvorschau

Bevor Sie den ersten echten Brief verschicken, können Sie den Preis abfragen — ohne etwas einzuliefern:

POST /api/pricePreview
Authorization: Bearer IHR-TOKEN
Content-Type: application/json

{ "pagesCount": 2, "isColor": false, "isDuplex": false,
  "countryIso": "DE", "zipCode": "53115" }

Die Antwort:

{ "pagesCount": 2, "priceNet": 0.69, "priceWithTax": 0.8211 }

Geändert am 8. September 2026: Bis dahin lieferte die Vorschau sechs Preisfelder. Die vier Einzelsätze (standardNet, standardGross, optimizedNet, optimizedGross) sind entfallen, und priceGross heißt jetzt priceWithTax — derselbe Name wie in der Statusauskunft, damit niemand zwei Wörter für dieselbe Sache lesen muss. Wer eines der fünf alten Felder verbucht, muss umstellen: Ein fehlendes JSON-Feld löst bei den meisten Clients keinen Fehler aus, sondern liest sich als 0.

Statt pagesCount können Sie auch data senden, also das PDF als Base64 — dann zählt die Seiten selbst. Mit registeredLetter erhalten Sie den Preis inklusive Einschreiben; ist die gewünschte Variante für Ihr Konto nicht freigeschaltet, antwortet die Vorschau mit der Begründung statt mit einem Preis. So erfahren Sie es, bevor eine Sendung abgelehnt wird. Mit optimizePrice: true wird die Portooptimierung einbezogen — sie zählt nur, wenn sie günstiger ist.

Der Wert ist eine Momentaufnahme und keine Zusage: Verbindlich rechnet das Backend bei der Verarbeitung ab.

Was eine Sendung gekostet hat

Die Vorschau oben schätzt vor dem Versand. Was am Ende abgerechnet wurde, steht an der Sendung selbst — in der Statusauskunft, unter denselben zwei Namen.

GET /api/letter/100829
Authorization: Bearer IHR-TOKEN

{
  "letterID": 100829,
  "statusID": 4,
  "processedDate": "2026-09-01T20:03:01+02:00",
  "priceNet": 3.71,
  "priceWithTax": 4.4149
}

Vier Dinge dazu, damit Sie nicht rätseln müssen:

  • Leer heißt „liegt noch nicht vor“, nicht „kostenlos“. Solange der Versanddienst den Betrag nicht gemeldet hat, bleiben beide Felder leer. Eine 0 liefern wir in diesem Fall nicht — denn 0,00 kann ein gültiger Betrag sein, und Ihr System könnte die beiden Fälle nicht auseinanderhalten.
  • Wann der Betrag da ist. Am Tag der Einlieferung steht er noch nicht. Mit der Übertragung in der Nacht ist er da — also am Morgen des nächsten Produktionstages und damit vor dem Druck. Sie müssen nicht auf das Produktionsdatum warten.
  • Der Preis hängt nicht am Status. Er kann auch erscheinen, ohne dass sich statusID bewegt. Fragen Sie ihn deshalb nicht nur einmal beim Statuswechsel ab.
  • Testsendungen weisen keinen Preis aus. Eine Sendung mit testFlag: true wird nicht gedruckt und nicht zugestellt, also entstehen keine Versandkosten — beide Felder bleiben leer. Für eine Kostenschätzung nehmen Sie POST /api/pricePreview.

Wer die Kosten je Vorgang zuordnen muss — etwa je Akte, Auftrag oder Nachlass — sendet custom1–custom5 mit: Diese fünf Felder kommen unverändert in der Statusauskunft zurück und stehen dort neben dem Preis. Ein Abruf genügt damit für eine vollständige Kostenzeile. Wollen Sie mehrere Schriftstücke eines Vorgangs zusammen abrechnen, fassen Sie sie über batchID zu einem Stapel zusammen und rufen GET /api/letter/Batch ab.

Nicht costCenter verwenden. Das Feld wird bei der Einlieferung angenommen und gespeichert, in der Statusauskunft aber nicht zurückgegeben. Als Klammer zwischen Betrag und Vorgang ist es deshalb unbrauchbar.

Wenn Ihr Konto keine Preise ausweist

Manche Konten sind so eingerichtet, dass sie keine Beträge sehen — etwa weil ein Vertriebspartner die Abrechnung übernimmt. Ist das bei Ihnen der Fall, gilt es einheitlich für alle Auskunftswege:

AuskunftWas dann kommt
StatusabfragepriceNet und priceWithTax bleiben leer
POST /api/pricePreviewantwortet normal (200) mit pagesCount, die beiden Beträge bleiben leer
GET /api/companyBillingZahlart und Wallet-ID kommen, alle Beträge bleiben leer

Vier Dinge, die dabei nicht passieren: Es gibt keinen Fehler und kein 503 — eine Zurückhaltung ist keine Störung, eine Wiederholung ändert nichts. Es gibt keine Null, sondern null, damit Sie „kostenlos“ von „wird nicht ausgewiesen“ unterscheiden können. Die Auskunft wird im Übrigen nicht schmaler: Status, Seitenzahl, Produktionsdatum, Sendungsnummer und Fehlerlisten kommen unverändert. Und Ihre Post wird nicht anders behandelt — die Guthaben- und Limitprüfung läuft weiter mit den echten Zahlen; reicht das Guthaben nicht, wird die Sendung wie immer mit Begründung abgelehnt.

Konto und Guthaben

Mit GET /api/companyBilling fragen Sie die Abrechnungssicht Ihres Kontos ab: Zahlart, aktuelles Guthaben, im laufenden Zeitraum aufgelaufene Kosten sowie Limit- und Warnschwelle. Bei Prepaid-Konten lohnt sich der Aufruf als Vorabprüfung, bevor Sie einen größeren Stapel einliefern — so scheitert die Einlieferung nicht am Guthaben. Die Werte sind eine Momentaufnahme aus dem Backend und ersetzen keine Rechnungsprüfung.

Was Ihr Konto kann

GET /api/account beantwortet die Fragen, die sonst erst ein Fehlversuch beantwortet — vor der ersten Sendung. Die Auskunft gilt immer für das Konto Ihres Tokens; einen Parameter dafür gibt es nicht.

outputNamewelcher Ausgabekanal Ihre Post befördert
registeredLetter.de, .xqwelche Einschreiben-Arten freigeschaltet sind, getrennt nach Inland und Ausland
addressCorrection.profiles, .favoritewelche Adresskorrektur-Profile es gibt und welches hinter "favorit" steht
restrictedAreas, extractAreaswo die Sperrflächen liegen und aus welchen Fenstern die Adresse gelesen wird — in Millimetern von links oben, dieselben Maße, gegen die Ihr PDF geprüft wird
testMailAvailable, ocrEnabledob der Test-E-Mail-Rückweg zur Verfügung steht und ob Texterkennung mitläuft
retrievedAt, fromCacheStand der Auskunft — siehe unten

Die Angaben sind einige Minuten zwischengespeichert, damit ein Aufruf vor jedem Brief nichts kostet. retrievedAt nennt den Stand, fromCache sagt, ob er gerade frisch geholt wurde. Wird Ihr Konto im Hintergrund umgestellt, wird das also mit kurzer Verzögerung sichtbar.

Ein Feld verdient besondere Beachtung: Steht registeredLetter.available auf false, war die Einschreiben-Auskunft im Moment der Abfrage nicht erreichbar. Die Listen de und xq sind dann leer — und das bedeutet nicht, dass Ihr Konto keine Einschreiben versenden darf. Fragen Sie in diesem Fall später noch einmal.

Jede Fläche trägt ein Feld group — es nennt den Dokumenttyp, zu dem sie gehört (etwa Default.Document für Inland oder BZL.XQ.Document für Auslandssendungen). Prüfen Sie Ihr PDF gegen die Flächen der Gruppe, die zu Ihrer Sendung passt.

Zugangsdaten und Beträge enthält die Auskunft nicht; für die Abrechnungssicht gibt es GET /api/companyBilling.

Einschreiben über die Schnittstelle

Varianten im Klartext: Einschreiben, Einschreiben Einwurf, Einschreiben Rückschein, Einschreiben Einwurf Rückschein. Die Wortstellung des ePost-Altsystems (Einwurf Einschreiben) wird ebenfalls verstanden — Bestandsintegrationen müssen hier nichts umbauen.

Varianten als Kürzel: national E---- (Einschreiben), EEW-- (Einwurf), ER--- (Rückschein), EEWR- (Einwurf + Rückschein); international IE--- und IER--.

Nicht mehr verfügbar: Einschreiben Eigenhändig und die Kombination mit Rückschein (Kürzel EEH--, EEHR-, IEEH-). Die Deutsche Post hat die Leistung zum 1. Januar 2026 eingestellt; entsprechende Aufrufe werden abgelehnt.

Welche Varianten für Ihr Konto und das Empfängerland freigeschaltet sind, prüft die Einlieferung. Eine nicht freigeschaltete Variante wird abgelehnt — mit Nennung der für Sie zulässigen Werte und niemals stillschweigend als Normalbrief versendet. Einschreiben sind nur im einseitigen Druck möglich (isDuplex: false) und kostenpflichtig; mit testFlag: true prüfen Sie den Ablauf kostenfrei.

Nicht unterstützt: Deckblätter (coverLetter, coverData) — Sendungen mit diesen Feldern werden mit einer klaren Fehlermeldung abgewiesen. Das ist die wichtigere Zusage dahinter: Ihre Sendung wird nie unbemerkt anders versendet als beauftragt. Eine Schnittstelle, die etwas Unmögliches stillschweigend abändert, ist gefährlicher als eine, die es ablehnt.

Nachweis und Sendungsverfolgung. Bei Einschreiben liefert GET /api/letter/{letterId} die Sendungsnummer der Post (registeredLetterID) sowie den weiterführenden Zustellstatus (registeredLetterStatus) mit Zeitstempel (registeredLetterStatusDate). Die Nummer erscheint in der Nacht nach der Einlieferung, wenn die Sendung an den Druckdienstleister übertragen wird — also vor der eigentlichen Produktion. Ein Zustellergebnis kann Tage später folgen. Geführt wird jeweils die aktuelle Meldung, keine Ereignishistorie. Solange keine Angabe vorliegt, bleiben die Felder leer; im Testmodus bleiben sie dauerhaft leer, weil eine Testsendung nicht eingeliefert wird. Was Sie mit der Sendungsnummer bei der Post abrufen können, richtet sich nach Ihrem Vertrag mit der Post und liegt außerhalb dieser API.

Wohin der Rückschein geht. Die Felder registeredLetterAdressLine1–3, registeredLetterZipCode und registeredLetterCity stammen aus dem ePost-Altvertrag. Sie werden angenommen und gespeichert, steuern den Rückschein aber nicht und kommen in der Statusauskunft nicht zurück — die Rücksendung richtet sich nach den Absenderdaten des Versands, nicht nach Angaben je Brief. Wenn Sie Rückscheine bestimmten Vorgängen zuordnen müssen, planen Sie das über Ihre eigene Referenz, etwa batchID oder den Dateinamen.

Hinweis für Umsteiger von der alten Schnittstelle. Dort wurde registeredLetter nicht ausgewertet — jede Sendung ging als Normalbrief hinaus, auch wenn das Feld gefüllt war. Auf dieser Schnittstelle wird das Feld erfüllt. Prüfen Sie deshalb vor der Umstellung, was Ihre Integration hineinschreibt: Ein stehengebliebener Beispielwert führt jetzt zu einer Ablehnung, und ein gewolltes Einschreiben erzeugt jetzt echte Einschreiben-Kosten. Wird das Feld leer gelassen, ändert sich nichts.

Einschreiben per API — vollständiges Beispiel

Dieses Beispiel läuft ohne testFlag. Eine Testsendung wird nicht eingeliefert und erhält deshalb nie eine Sendungsnummer — Einschreiben prüfen Sie sinnvoll erst, wenn Ihre Anbindung für Normalbriefe steht. Es entstehen echte Einschreiben-Kosten.

Schritt 1 — vorab prüfen, ob die Variante freigeschaltet ist. Ist sie es nicht, antwortet die Vorschau mit der Begründung statt mit einem Preis — ohne Einlieferung und ohne Kosten.

POST /api/pricePreview
Authorization: Bearer IHR-TOKEN
Content-Type: application/json

{
  "pagesCount": 2,
  "isColor": false,
  "isDuplex": false,
  "registeredLetter": "Einschreiben Einwurf"
}

Schritt 2 — einliefern. Einschreiben werden nur einseitig gedruckt, isDuplex bleibt false.

POST /api/letter
Authorization: Bearer IHR-TOKEN
Content-Type: application/json

[
  {
    "fileName": "kuendigung_4711.pdf",
    "data": "PDF-INHALT-ALS-BASE64",
    "isDuplex": false,
    "registeredLetter": "Einschreiben Einwurf"
  }
]

Schritt 3 — Nachweis abrufen. Die Sendungsnummer erscheint in der Nacht nach der Einlieferung, ein Zustellergebnis kann Tage später folgen.

GET /api/letter/100123
Authorization: Bearer IHR-TOKEN

{
  "letterID": 100123,
  "statusID": 4,
  "registeredLetterID": "RR123456789DE",
  "registeredLetterStatus": "zugestellt",
  "registeredLetterStatusDate": "2026-09-03T21:34:00+02:00"
}

In fünf Schritten zum ersten Brief

  1. Konto einrichten. Sie erhalten Ihre Zugangsdaten.
  2. Anmelden über POST /api/Login — Sie erhalten Ihr API-Token.
  3. Testbrief einliefern mit testFlag und testEMail. Das zurückgesendete PDF zeigt Ihnen, ob das Layout passt.
  4. Guthaben aufladen — bei Prepaid-Konten, dem Regelfall. Den aktuellen Stand fragen Sie jederzeit über GET /api/companyBilling ab.
  5. Produktiv gehen: testFlag weglassen. Mehr ist nicht zu tun.

Für wen sich die Schnittstelle eignet

Überall dort, wo Briefe aus einem System heraus entstehen: Rechnungen und Mahnungen aus der Finanzbuchhaltung, Bescheide aus einer Fachanwendung, Vertragsunterlagen aus dem CRM, Serienkorrespondenz aus einem Branchenprogramm. Der Aufwand lohnt ab dem Punkt, an dem jemand regelmäßig PDFs erzeugt, ausdruckt, kuvertiert und frankiert.

Ab 0,65 € netto je Brief im Inland — ohne Grundgebühr, ohne Mindestumsatz, ohne Vertragsbindung. Die Schnittstelle selbst kostet nichts extra; Sie zahlen nur die Sendung. Skaliert von der Einzelsendung bis zu hohen Volumina.

Andere Wege in

Nicht jedes System lässt sich programmieren, und nicht jeder Versand braucht eine Schnittstelle. Zwei weitere Wege automatisieren den Versand ohne eine Zeile Code — den Überblick über alle drei gibt die Seite Briefversand automatisieren.

WegGeeignet fürEinrichtung
HotfolderSysteme, die PDFs in einen Ordner exportierenOrdnerüberwachung, keine Programmierung
Automatisch verschlagwortenRegelbasierte Zuordnung von Sendungen im Web-Clientkeine Installation

Kein Automatisierungsthema, aber oft gesucht: Wer einfach nur aus einer beliebigen Anwendung heraus drucken oder Serienbriefe aus Word verschicken möchte, nutzt den Windows-Client mit Druckertreiber und Word-Add-in. Serienbriefe gehen außerdem vollständig im Browser — ganz ohne Installation.

Häufige Fragen zur Brief-API

Wie authentifiziere ich mich, und wie lange gilt das Token?

Über POST /api/Login mit Benutzername (Feld ekp, in der Regel die E-Mail-Adresse des Kontos) und Kennwort. Die Antwort enthält ein Bearer-Token, das 8 Stunden gültig ist und bei allen weiteren Aufrufen als Kopfzeile Authorization: Bearer mitgegeben wird. Einen Verlängerungsendpunkt gibt es nicht — nach Ablauf melden Sie sich erneut an. Falsche Zugangsdaten werden mit HTTP 400 beantwortet. Ein Token kann außerdem vor Ablauf ungültig werden, etwa nach einem Kennwortwechsel — der Server antwortet dann mit 401. Behandeln Sie 401 als Aufforderung, sich einmal neu anzumelden, statt nur die Ablaufzeit mitzurechnen.

Wie mache ich ein Token ungültig, das in falsche Hände geraten ist?

Ändern Sie Ihr Kennwort im -Portal und melden Sie sich anschließend einmal über POST /api/Login mit dem neuen Kennwort an. Erst dieser zweite Schritt entwertet alle zuvor ausgestellten Token — sie antworten danach mit 401. Das Kennwort allein zu ändern genügt nicht. Ein normaler Login entwertet nichts: Mehrere Dienste können sich parallel anmelden, jedes Token lebt seine acht Stunden. Laufende Dienste melden sich von selbst neu an, sofern sie 401 behandeln und das neue Kennwort hinterlegt ist. Soll ein Token ohne Kennwortwechsel entwertet werden, erledigen wir das auf Anfrage.

Warum bekomme ich 429 Too Many Requests bei der Anmeldung?

POST /api/Login ist gedrosselt: zehn fehlgeschlagene Anmeldungen je Benutzername in fünf Minuten, dazu eine großzügige Obergrenze je Absender-IP, die im Normalbetrieb nicht erreicht wird. Erfolgreiche Anmeldungen sind unbegrenzt, und eine gelungene Anmeldung setzt den Zähler sofort zurück. Die Antwort trägt Retry-After mit der Wartezeit in Sekunden — warten Sie diese Frist ab und wiederholen Sie dann einmal, nicht in einer Schleife. Ein 429 verrät nicht, ob es den Benutzernamen gibt. Alle anderen Aufrufe — Einlieferung, Statusabruf, Preisvorschau — sind nicht gedrosselt. Wenn Sie die Drossel im Normalbetrieb sehen, meldet sich Ihr Dienst meist vor jedem Aufruf neu: Ein Token gilt acht Stunden und sollte wiederverwendet werden.

Woher nimmt digiBrief die Empfängeradresse?

Aus dem PDF. Die Adresse wird aus dem Adressfenster der ersten Seite gelesen, bei Bedarf per Texterkennung. Die JSON-Felder addressLine1, zipCode und city sind optional und dienen nur Ihrer eigenen Zuordnung und der Statusauskunft — auf die Zustellung haben sie keinen Einfluss. Pflicht sind allein fileName und data.

Warum wird mein Brief abgelehnt, obwohl die Empfängeradresse stimmt?

Häufigste Ursache ist der Absender. Ein Brief ohne erkennbaren Absender im PDF wird abgelehnt — das gilt für alle Konten mit Freimachungszone und damit im Regelfall. Weil die Fehlermeldung von der Adresse spricht, wird oft an der Empfängeradresse gesucht. Prüfen Sie die Absenderzeile über dem Adressfenster; ein Dokument ohne erkennbaren Absender wird abgelehnt — das JSON-Feld senderAdressLineComplete ersetzt ihn nicht. Zweithäufigste Ursache ist eine Empfängeradresse, die mit der Freimachungszone kollidiert — dagegen hilft addressCorrection auto.

Wie teste ich, ohne dass ein Brief gedruckt wird?

Setzen Sie testFlag auf true. Die Sendung durchläuft alle Prüfungen und wird als Testsendung registriert, aber weder gedruckt noch zugestellt. Mit testEMail erhalten Sie das verarbeitete PDF per E-Mail zurück, mit testShowRestrictedArea zusätzlich eine Schablone, die Prüfflächen und Adressfenster auf Ihrem Dokument einzeichnet. Auch eine abgelehnte Testsendung kommt dann per Mail zurück, mit hervorgehobener Ursache. Zusätzlich können Sie angenommene Testsendungen im Postausgangsbuch des Web-Clients ansehen — die Dokumentanzeige dazu schalten wir auf Anfrage für Ihr Konto frei.

Welche Dateigrößen und Formate sind erlaubt?

PDF im Format DIN A4 hochkant. Maximal 20 MB je Sendung und maximal 300 MB je Aufruf. Der Dateiname im Feld fileName darf bis zu 200 Zeichen lang sein.

Kann ich Einschreiben über die API versenden?

Ja. Setzen Sie registeredLetter auf die gewünschte Variante, entweder im Klartext (Einschreiben, Einschreiben Einwurf, Einschreiben Rückschein, Einschreiben Einwurf Rückschein) oder als ePost-Kürzel (E----, EEW--, ER---, EEWR-, international IE--- und IER--). Die Wortstellung des ePost-Altsystems (Einwurf Einschreiben) wird ebenfalls verstanden. Nicht mehr verfügbar ist Einschreiben Eigenhändig (Kürzel EEH--) — die Deutsche Post hat die Leistung zum 1. Januar 2026 eingestellt. Welche Varianten für Ihr Konto und das Empfängerland freigeschaltet sind, prüft die Einlieferung; eine nicht freigeschaltete Variante wird abgelehnt und niemals stillschweigend als Normalbrief versendet. Einschreiben sind nur im einseitigen Druck möglich und kostenpflichtig. Nicht unterstützt sind Deckblätter.

Was passiert, wenn ich denselben Brief zweimal einliefere?

Ohne Idempotency-Key gilt jeder Aufruf als neue Sendung — derselbe Brief zweimal eingeliefert wird zweimal gedruckt. Senden Sie deshalb den Kopfzeilen-Eintrag Idempotency-Key mit einer in Ihrem System eindeutigen Kennung: Wiederholen Sie den Aufruf mit demselben Schlüssel und demselben PDF innerhalb von 15 Minuten, wird nichts ein zweites Mal gedruckt, und Sie erhalten die ursprüngliche letterID zurück. Nach Ablauf der 15 Minuten gilt derselbe Brief wieder als neue Sendung; eine abgelehnte Sendung blockiert nichts.

Wie erkenne ich, dass eine Sendung abgelehnt wurde?

An der statusID 99. Die Begründung steht im Klartext in der errorList der Statusabfrage, zum Beispiel wenn der Inhalt die Frankierzone verletzt oder die Adresse nicht lesbar ist. Im Testmodus mit testEMail und testShowRestrictedArea kommt eine abgelehnte Testsendung zusätzlich per Mail zurück, mit hervorgehobener Ursache. Bei Stapeln liefert GET /api/letter/Batch mit dem Parameter onlyIssues ausschließlich die betroffenen Sendungen.

Kann ich mit der API Briefe ins Ausland versenden?

Ja. Steht eine ausländische Empfängeradresse im Adressfenster des PDFs, wird der Brief dorthin zugestellt. Ein zusätzliches Feld ist dafür nicht erforderlich; die Portokosten richten sich nach dem Zielland.

Kann ich Briefe aus meinem ERP- oder CRM-System versenden?

Ja. Jedes System, das PDFs erzeugen und HTTP-Aufrufe absetzen kann, lässt sich anbinden — typischerweise Finanzbuchhaltung, Fachanwendungen und CRM-Systeme. Wo eine Programmierung nicht möglich ist, bieten Hotfolder, Server-Druckertreiber und das Word-Add-in denselben Versandweg ohne Entwicklung.

Kann ich den Preis abfragen, bevor ich versende?

Ja, über POST /api/pricePreview. Sie geben entweder pagesCount oder das PDF als data mit, dazu Farbe, Duplex, Empfängerland und Postleitzahl, und erhalten Netto- und Bruttopreis zurück, ohne etwas einzuliefern. Mit registeredLetter ist der Einschreiben-Zuschlag enthalten; ist die Variante für Ihr Konto nicht freigeschaltet, antwortet die Vorschau mit der Begründung statt mit einem Preis. Der Wert ist eine Momentaufnahme und keine Zusage.

Wie prüfe ich vorab, ob mein Guthaben reicht?

Über GET /api/companyBilling. Der Endpunkt liefert Zahlart, aktuelles Guthaben, aufgelaufene Kosten sowie Limit- und Warnschwelle des Kontos. Bei Prepaid-Konten – dem Regelfall – eignet sich der Aufruf als Vorabprüfung vor größeren Einlieferungen.

Ist der automatisierte Briefversand DSGVO-konform?

Die Übertragung erfolgt durchgehend TLS-verschlüsselt, die Verarbeitung findet in Deutschland statt. easyNova ist nach ISO 27001, ISO 9001 und ISO 14001 zertifiziert; ein Auftragsverarbeitungsvertrag nach Art. 28 DSGVO wird gestellt.

Gibt es ein Mindestvolumen oder eine Vertragsbindung?

Nein. Es gibt keine Grundgebühr, keinen Mindestumsatz und keine Vertragsbindung. Die Schnittstelle selbst kostet nichts extra — abgerechnet wird je versendetem Brief, ab 0,65 € netto im Inland.

Mehr zum Thema: Hybridpost, Serienbrief aus Word, Einschreiben online und der Überblick Briefversand automatisieren.

Ohne eigene Programmierung lässt sich der Versand ebenfalls automatisieren: Der Hotfolder überwacht einen Ordner und verschickt abgelegte Dokumente automatisch, während das automatische Verschlagworten Ihre Sendungen im Web-Client regelbasiert sortiert und kennzeichnet.


Aktualisiert am