Der Vertrag ist erzeugt,
nicht geschrieben.
OrbitSend nimmt Versandaufträge über eine REST-Schnittstelle an. Das OpenAPI-Dokument entsteht aus den Schemata der Routen, und die Typen dieser Oberfläche entstehen wiederum daraus. Zwischen Vertrag und Verhalten passt deshalb kein Spalt.
Kampagnen und Versandaufträge nimmt die API heute an, gedruckt wird ab Stufe B3. Was heute geht und was noch nicht, steht weiter unten.
Der erste Aufruf braucht keinen Schlüssel.
Das Lebenszeichen antwortet ohne Anmeldung. Es sagt nichts über Ihr Konto, aber alles darüber, ob Sie die richtige Adresse haben, ob die API läuft und gegen welche Version des Vertrags Sie sprechen.
curl -i https://api.staging.orbitsend.de/v1/ping
Drei Aufrufe von der Vorlage zum Brief.
Erst die Kampagne, dann die Probe, dann der Auftrag. Jeder Schritt verlangt seinen Bereich am Schlüssel, und nur der letzte kostet Geld.
Schritt 1
Kampagne anlegen
POST /v1/campaigns
Name, Absender und der Brieftext mit Variablen wie {{anrede}}, jede Pflicht oder optional. Das Anlegen kostet nichts. Die Musterseite setzt die API selbst und liefert sie als PDF oder PNG.
Bereich campaigns:write, Idempotency-Key ist Pflicht
Schritt 2
Trockenlauf
POST /v1/campaigns/{id}/shipments/preview
Dieselbe Prüfung wie die Annahme, aber ohne Wirkung: nichts wird angelegt, nichts gebucht. Die Antwort nennt den Preis, ob das Guthaben reicht, und jede Zeile, die abgelehnt würde, mit ihrer Nummer.
Bereich shipments:write, ohne Idempotency-Key
Schritt 3
Versandauftrag einreichen
POST /v1/campaigns/{id}/shipments
Eine bis 5000 Anschriften, je Zeile mit den Werten der Variablen. Mit einem Live-Schlüssel wird der Preis im selben Moment vom Guthaben abgebucht, mit einem Testschlüssel wird alles geprüft und nie gebucht.
Bereich shipments:write, Idempotency-Key ist Pflicht
Der Aufruf, auf den alles hinausläuft.
Ein Versandauftrag ist eine Liste von Anschriften, je Zeile mit den Werten für die Variablen Ihrer Vorlage. Alles Weitere - Setzen, Drucken, Falzen, Kuvertieren, Einliefern - ist unsere Sache und braucht kein Zutun von Ihnen.
POST /v1/campaigns/{id}/shipments
{ "items": [{
"recipient": { "name": "Ostermann", … },
"letter": { "values": { "rabatt": "15 %" } }
}] }
Die Antwort ist ein Beleg: Kennung, Status, Zahl der Briefe und der Preis, nach dem abgerechnet wurde. Unter der Kennung ist der Auftrag ab diesem Moment auffindbar, und solange er auf den Druck wartet, lässt er sich stornieren.
Angenommen wird ganz oder gar nicht: passt eine Zeile nicht auf die Seite, steht eine Anschrift auf der Sperrliste oder reicht das Guthaben nicht, wird der ganze Auftrag abgelehnt und kostet nichts.
Pflicht: die Kopfzeile Idempotency-Key. Derselbe Schlüssel mit demselben Inhalt ergibt denselben Auftrag und bucht kein zweites Mal.
Was in jeder Antwort gilt.
Sechs Zusagen, die für alle Endpunkte gelten und nicht je Route neu verhandelt werden. Wer sie einmal eingebaut hat, muss sie nie wieder anfassen.
Fehler nach RFC 9457
Jede Ablehnung kommt als application/problem+json mit type, title und status, je nach Fall dazu detail und errors[] mit den betroffenen Feldern oder Zeilen. Ein Format für alle Fehler, maschinenlesbar, ohne Sonderfall je Endpunkt.
Request-ID in jeder Antwort
Der Wert aus x-request-id steht in unserem Log und in Ihrem. Bei einer Rückfrage genügt er, um denselben Vorgang auf beiden Seiten zu finden.
Cursor statt Offset
Listen blättern über einen Cursor. Das bedeutet: es gibt ein Weiter und einen Weg an den Anfang, aber keine Seitenzahlen. Ein Cursor kennt seinen Vorgänger nicht.
Cent und UTC
Beträge sind Ganzzahlen in Cent, Zeitstempel sind ISO 8601 in UTC. Gerundet und in eine Zeitzone gebracht wird erst in der Anzeige, nie im Vertrag.
Kein privilegierter Innenweg
Das Kundenportal benutzt dieselben Endpunkte, die Sie benutzen. Es gibt keine Sonderroute für die eigene Oberfläche, an der die öffentliche API vorbeidriften könnte.
Der Vertrag ist erzeugt
Das OpenAPI-Dokument entsteht aus den Schemata der Routen und wird nie von Hand gepflegt. Was dort steht, gilt, weil es nicht danebenstehen kann.
Was heute geht und was noch nicht.
Wir schreiben hier hin, was existiert, und nicht, was geplant ist. Der Rest steht mit seiner Stufe daneben.
Heute erreichbar
Kampagnen mit Vorlage und Musterseite, der Trockenlauf, Versandaufträge einreichen, lesen und stornieren, dazu Guthaben, Kontoauszug und Sperrliste. API-Schlüssel mit Bereichen erzeugen Sie im Portal, je für Test oder Live.
Druck ab Stufe B3
Ein angenommener Auftrag wartet heute auf den Druck. Die Ausgabe an die Produktion, die daraus einen Stapel macht, kommt mit B3; bis dahin wird nichts gedruckt. Solange ein Auftrag wartet, lässt er sich mit voller Gutschrift stornieren.
Credits ab Stufe B5
Heute bucht der Betrieb Guthaben in Euro, nach einer Überweisung. Mit B5 kaufen Sie Credits per Kreditkarte im Portal, ein Brief kostet einen Credit, und der Kontostand steht dann auch im Vertrag in Credits statt in Cent.
Webhooks ab Stufe B6
Ereignisse wie ein angenommener Versandauftrag oder ein Guthaben unter der Schwelle, damit Ihr System nicht fragen muss, ob sich etwas getan hat.
Zwei Adressen, mehr brauchen Sie nicht.
Beide werden von der laufenden API ausgeliefert. Sie können also nicht älter sein als das, was gerade antwortet.
Referenz der Endpunkte
Jeder Endpunkt, den Sie mit einem API-Schlüssel oder nach der Anmeldung aufrufen können, mit Parametern, Rumpf und Antworten. Erzeugt aus dem OpenAPI-Dokument der laufenden API, nicht abgeschrieben. Routen für den Betrieb und die Druckerei stehen Kunden nicht offen und fehlen deshalb.
Vertrag 3.1.0, OpenAPI 3.1.0, 59 Endpunkte in 12 Gruppen. Gelesen aus dem Dokument der laufenden API und nach einer Stunde neu geholt. Dokument als JSON
Anmeldung
- API-Schlüssel
API-Schluessel als
Authorization: Bearer sk_live_…- Sitzung aus der Anmeldung
Sitzungstoken aus der Anmeldung als
Authorization: Bearer os_sess_...
System
Zustand und Betrieb
GET/
v1/ pingErreichbarkeitstest Zugang
Ohne Anmeldung.
Parameter
- echostring · Abfrage · optional
Wird unveraendert zurueckgegeben
- höchstens 120 Zeichen
Antworten
- 200Erfolg{ pong: boolean, version: string, contractVersion: string, requestId: string, receivedAt: string, echo?: string }
- 400Anfrage passt nicht zum SchemaProblem
Auth
Registrierung, Anmeldung mit Passwort, Passkey oder zweitem Faktor, Sitzung
POST/
v1/ auth/ registerKonto anlegen und anmelden Legt Konto und ersten Nutzer an. Der erste Nutzer bekommt die Rolle OWNER und ist sofort angemeldet. Ist die Registrierung im Betrieb geschlossen, antwortet die Route vor jeder Pruefung des Rumpfs mit 403 und
errors[0].code = registration-closed; ein Konto entsteht dann nicht.Zugang
Ohne Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- accountNamestring · Pflicht
Name des Mandanten. Braucht mindestens drei Buchstaben (Umlaute zaehlen umgeschrieben), weil daraus das Kuerzel jeder Kampagnen-Kennung entsteht. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- Beispiel
Jannausch GmbH
- namestring · Pflicht
Der Name des Nutzers. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- emailstring (email) · Pflicht
Wird klein geschrieben abgelegt
- höchstens 254 Zeichen
- passwordstring · Pflicht
Mindestens 12 Zeichen
- 12 bis 200 Zeichen
Antworten
- 201AngelegtSession
- 400Anfrage passt nicht zum SchemaProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 409Konflikt mit dem aktuellen StandProblem
- 429Zu viele AnfragenProblem
POST/
v1/ auth/ loginAnmelden Mit E-Mail-Adresse und Passwort. Antwortet 200 mit der Sitzung - oder 202, wenn der Nutzer einen zweiten Faktor eingeschaltet hat: dann traegt die Antwort statt der Sitzung einen Beleg (SecondFactorChallenge), und die Sitzung gibt POST /v1/auth/login/totp mit dem Code aus der App aus. Der Beleg gilt fuenf Minuten und fuenf Fehlversuche. Eine Anmeldung mit Passkey (POST /v1/auth/login/passkey) kennt den zweiten Schritt nicht.
Zugang
Ohne Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- emailstring (email) · Pflicht
Wird klein geschrieben abgelegt
- höchstens 254 Zeichen
- passwordstring · Pflicht
- 1 bis 200 Zeichen
Antworten
- 200ErfolgSession
- 202Angenommen, wird verarbeitetSecondFactorChallenge
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 429Zu viele AnfragenProblem
POST/
v1/ auth/ logoutAbmelden Widerruft die Sitzung, mit der der Aufruf kam. Andere Sitzungen bleiben.
Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 204Erfolg, ohne Inhaltohne Inhalt
- 401Nicht angemeldet oder Zugang ungültigProblem
GET/
v1/ meAngemeldeter Nutzer und sein Konto Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 200Erfolg{ user: User, account: Account }
- 401Nicht angemeldet oder Zugang ungültigProblem
POST/
v1/ auth/ passkeys/ authenticationMit Passkey anmelden, Schritt 1: Optionen fuer den Browser Ohne Anmeldung und ohne E-Mail-Adresse: der Browser zeigt die Passkeys, die er fuer diese Domain kennt, und der gewaehlte sagt, wer sich anmeldet. Die Challenge gilt fuenf Minuten und genau fuer POST /v1/auth/login/passkey.
Zugang
Ohne Anmeldung.
Antworten
- 200ErfolgPasskeyAuthenticationStart
- 429Zu viele AnfragenProblem
POST/
v1/ auth/ login/ passkeyMit Passkey anmelden, Schritt 2: Antwort des Browsers pruefen Prueft die Unterschrift gegen den hinterlegten oeffentlichen Schluessel und gibt die Sitzung aus, dieselbe wie bei POST /v1/auth/login. Ein zweiter Faktor wird nicht mehr verlangt: der Authenticator hat den Nutzer schon geprueft. Jede Abweichung ist 401 ohne naehere Angabe: unbekannter Passkey, falsche Herkunft, abgelaufene Challenge, gesperrter Zugang.
Zugang
Ohne Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- challengeIdstring (uuid) · Pflicht
Aus POST /v1/auth/passkeys/authentication
- responsePasskeyAuthenticationResponseInput · Pflicht
AuthenticationResponseJSON nach WebAuthn Level 3, das Ergebnis von startAuthentication()
Felder von PasskeyAuthenticationResponseInput
- idstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- rawIdstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- responseobject · Pflicht
Felder
- clientDataJSONstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- authenticatorDatastring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- signaturestring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- userHandlestring · optional
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- authenticatorAttachmentstring · optional
- Werte
platform,cross-platform
- Werte
- clientExtensionResultsobject · Pflicht
- Namen frei, je Wert
beliebig
- Namen frei, je Wert
- typestring · Pflicht
- Wert
public-key
- Wert
Antworten
- 200ErfolgSession
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 429Zu viele AnfragenProblem
POST/
v1/ auth/ login/ totpAnmelden, Schritt 2: zweiter Faktor Nimmt den Beleg aus der 202-Antwort von POST /v1/auth/login und einen Code: sechs Ziffern aus der App oder einen Wiederherstellungscode. Gibt die Sitzung aus, dieselbe wie bei POST /v1/auth/login. Ein Code gilt einmal: derselbe TOTP-Code wird in seinem Zeitfenster nicht zweimal angenommen, ein Wiederherstellungscode nie. 422 code-invalid bei falschem Code, solange Versuche bleiben. 401, wenn der Beleg unbekannt, abgelaufen oder nach fuenf Fehlversuchen verbraucht ist: dann beginnt die Anmeldung beim Passwort von vorn.
Zugang
Ohne Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- challengeTokenstring · Pflicht
Aus der 202-Antwort von POST /v1/auth/login
- 1 bis 200 Zeichen
- codestring · Pflicht
Sechs Ziffern aus der App oder ein Wiederherstellungscode
- 1 bis 40 Zeichen
Antworten
- 200ErfolgSession
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 422Inhaltlich nicht verwendbarProblem
- 429Zu viele AnfragenProblem
Sicherheit
Passkeys und zweiter Faktor des eigenen Zugangs. Nur in einer angemeldeten Sitzung
GET/
v1/ auth/ passkeysEigene Passkeys auflisten Neueste zuerst, ohne Blaettern: je Nutzer gibt es hoechstens zwanzig. Der oeffentliche Schluessel steht nicht in der Antwort.
Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 200Erfolg{ data: Passkey[] }
- 401Nicht angemeldet oder Zugang ungültigProblem
POST/
v1/ auth/ passkeysPasskey anlegen, Schritt 2: Antwort des Browsers pruefen Prueft die Antwort von navigator.credentials.create() gegen die Challenge aus Schritt 1 und hinterlegt den oeffentlichen Schluessel. Die Challenge ist danach verbraucht, auch wenn die Pruefung scheitert: fuer einen neuen Versuch beginnt Schritt 1 von vorn. Fehlercodes (422): challenge-expired, passkey-rejected (Herkunft, Unterschrift oder Nutzerpruefung passen nicht).
Zugang
Nur mit Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- challengeIdstring (uuid) · Pflicht
Aus POST /v1/auth/passkeys/registration
- namestring · optional
Ohne Angabe "Passkey"
- 1 bis 120 Zeichen
- responsePasskeyRegistrationResponseInput · Pflicht
RegistrationResponseJSON nach WebAuthn Level 3, das Ergebnis von startRegistration()
Felder von PasskeyRegistrationResponseInput
- idstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- rawIdstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- responseobject · Pflicht
Felder
- clientDataJSONstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- attestationObjectstring · Pflicht
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- authenticatorDatastring · optional
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- transportsstring[] · optional
- publicKeyAlgorithminteger · optional
- publicKeystring · optional
- höchstens 16384 Zeichen
- Muster
^[A-Za-z0-9_-]*$
- authenticatorAttachmentstring · optional
- Werte
platform,cross-platform
- Werte
- clientExtensionResultsobject · Pflicht
- Namen frei, je Wert
beliebig
- Namen frei, je Wert
- typestring · Pflicht
- Wert
public-key
- Wert
Antworten
- 201AngelegtPasskey
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ auth/ passkeys/ registrationPasskey anlegen, Schritt 1: Optionen fuer den Browser Gibt die Optionen fuer navigator.credentials.create() aus, samt Challenge. Der Passkey wird als auffindbares Credential mit Nutzerpruefung angelegt (residentKey und userVerification "required"), damit er spaeter ohne E-Mail-Adresse anmeldet und als zweiter Faktor gilt. Schon hinterlegte Passkeys stehen in excludeCredentials; der Browser legt denselben nicht zweimal an. Die Challenge gilt fuenf Minuten und genau fuer POST /v1/auth/passkeys.
Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 200ErfolgPasskeyRegistrationStart
- 401Nicht angemeldet oder Zugang ungültigProblem
- 422Inhaltlich nicht verwendbarProblem
PATCH/
v1/ auth/ passkeys/ {id}Passkey umbenennen Zugang
Nur mit Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· Pflicht- namestring · Pflicht
Wie der Nutzer diesen Passkey nennt, etwa "MacBook" oder "YubiKey"
- 1 bis 120 Zeichen
Antworten
- 200ErfolgPasskey
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 404Nicht gefundenProblem
DELETE/
v1/ auth/ passkeys/ {id}Passkey entfernen Der Passkey meldet danach nicht mehr an. Auf dem Geraet bleibt er stehen, bis der Nutzer ihn dort selbst loescht; das Passwort gilt weiter.
Zugang
Nur mit Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 204Erfolg, ohne Inhaltohne Inhalt
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 404Nicht gefundenProblem
GET/
v1/ auth/ securityPasskeys und zweiter Faktor auf einen Blick Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 200ErfolgSecurityOverview
- 401Nicht angemeldet oder Zugang ungültigProblem
POST/
v1/ auth/ totp/ setupZweiten Faktor einrichten, Schritt 1: Geheimnis ausgeben Erzeugt ein neues TOTP-Geheimnis (SHA-1, sechs Ziffern, dreissig Sekunden) und gibt es als Base32 und als otpauth-Link fuer den QR-Code aus. Eingeschaltet ist der Faktor erst nach POST /v1/auth/totp/enable mit einem passenden Code. Ein erneuter Aufruf davor ersetzt das Geheimnis. 409, wenn der Faktor schon eingeschaltet ist: zum Wechsel der App erst ausschalten.
Zugang
Nur mit Sitzung aus der Anmeldung.
Antworten
- 200ErfolgTotpSetup
- 401Nicht angemeldet oder Zugang ungültigProblem
- 409Konflikt mit dem aktuellen StandProblem
POST/
v1/ auth/ totp/ enableZweiten Faktor einrichten, Schritt 2: ersten Code bestaetigen Prueft den Code gegen das Geheimnis aus Schritt 1 und schaltet den Faktor ein. Ab jetzt antwortet POST /v1/auth/login mit 202. Die Antwort traegt 8 Wiederherstellungscodes, jeder einmal gueltig; sie stehen nur hier. Fehlercodes (422): totp-not-set-up (Schritt 1 fehlt), code-invalid. 409, wenn der Faktor schon eingeschaltet ist.
Zugang
Nur mit Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- codestring · Pflicht
Sechs Ziffern aus der App oder ein Wiederherstellungscode
- 1 bis 40 Zeichen
Antworten
- 200ErfolgRecoveryCodes
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ auth/ totp/ disableZweiten Faktor ausschalten Verlangt das Passwort noch einmal. Loescht Geheimnis und Wiederherstellungscodes; die Anmeldung laeuft danach wieder mit Passwort allein. Wiederholbar: ist kein Faktor eingeschaltet, ist das 204 und nicht 409. Fehlercode (422): password-invalid.
Zugang
Nur mit Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- passwordstring · Pflicht
Das eigene Passwort, zur Bestaetigung
- 1 bis 200 Zeichen
Antworten
- 204Erfolg, ohne Inhaltohne Inhalt
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ auth/ totp/ recovery-codesWiederherstellungscodes neu ausgeben Verlangt das Passwort noch einmal. Die bisherigen Codes, benutzte wie unbenutzte, gelten danach nicht mehr. Fehlercodes (422): password-invalid, totp-not-enabled.
Zugang
Nur mit Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- passwordstring · Pflicht
Das eigene Passwort, zur Bestaetigung
- 1 bis 200 Zeichen
Antworten
- 200ErfolgRecoveryCodes
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 422Inhaltlich nicht verwendbarProblem
Konto
Stammdaten des eigenen Mandanten
GET/
v1/ accountEigenes Konto lesen Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Antworten
- 200ErfolgAccount
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
PATCH/
v1/ accountEigenes Konto aendern Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- namestring · Pflicht
Name des Mandanten. Braucht mindestens drei Buchstaben (Umlaute zaehlen umgeschrieben), weil daraus das Kuerzel jeder Kampagnen-Kennung entsteht. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- Beispiel
Jannausch GmbH
Antworten
- 200ErfolgAccount
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
API-Schluessel
Zugaenge fuer Fremdsysteme. Nur in einer angemeldeten Sitzung zu verwalten
GET/
v1/ api-keysSchluessel des Kontos auflisten Neueste zuerst. Widerrufene sind nur auf Wunsch dabei.
Zugang
Nur mit Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
- includeRevokedstring · Abfrage · optional
Antworten
- 200Erfolg{ data: ApiKey[], next_cursor: string | null }
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
POST/
v1/ api-keysSchluessel ausgeben Der vollstaendige Schluessel steht nur in dieser Antwort. Danach ist in der Datenbank nur noch sein Hash, er laesst sich nicht wiederherstellen.
Zugang
Nur mit Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- namestring · Pflicht
Wofuer der Schluessel da ist. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- environmentstring · Pflicht
- Werte
TEST,LIVE
- Werte
- scopesScopeInput[] · Pflicht
- mindestens 1 Einträge
- expiresAtstring (date-time) · optional
Ohne Angabe laeuft der Schluessel nicht ab
Antworten
- 201AngelegtIssuedApiKey
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ api-keys/ {id}/ revokeSchluessel widerrufen Der Schluessel bleibt als Zeile bestehen und wird nur entwertet. Geloescht wuerde er aus dem Nachweis verschwinden, wer wann womit gearbeitet hat.
Zugang
Nur mit Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgApiKey
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
Dokumente
PDFs hochladen und pruefen lassen
GET/
v1/ documentsDokumente blaettern Neueste zuerst, immer nur die der eigenen Umgebung.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200Erfolg{ data: Document[], next_cursor: string | null }
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
POST/
v1/ documentsPDF hochladen und pruefen Der Rumpf ist das PDF selbst, mit Content-Type application/pdf.
Geprueft wird sofort: Seitenzahl, das Format JEDER Seite und wie stark das Anschriftfeld der ersten Seite belegt ist. Ein PDF, das sich nicht oeffnen laesst, wird mit 422 abgelehnt und hinterlaesst keine Zeile.
Mit B2 wird aus einem Dokument kein Brief mehr: der Brief entsteht aus der Vorlage einer Kampagne. Dokumente ruhen bis v1.1.
Dasselbe PDF ein zweites Mal ergibt dasselbe Dokument und 200 statt 201. Die Pruefung laeuft nicht erneut.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- filenamestring · Abfrage · optional
Nur zur Wiedererkennung in Listen
- höchstens 255 Zeichen
Anfrage-Rumpf
application/pdf· Pflicht · Typ string (binary)Das PDF selbst
Antworten
- 200ErfolgDocument
- 201AngelegtDocument
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 413Anfrage zu großProblem
- 415Inhaltstyp nicht unterstütztProblem
- 422Inhaltlich nicht verwendbarProblem
GET/
v1/ documents/ {id}Ein Dokument mit seinen Befunden Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgDocument
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
GET/
v1/ documents/ {id}/ contentDas PDF selbst Liefert die abgelegte Datei unveraendert zurueck. Diese Route fuehrt als einzige nur ihren Erfolgsfall im Vertrag: produces gilt in OpenAPI fuer alle Antworten einer Route, und die Fehler waeren damit faelschlich als application/pdf ausgewiesen. Sie kommen wie ueberall als problem+json, siehe das Schema Problem.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200Erfolgstring (binary) als application/pdf
Das PDF selbst
Preise
Die geltenden Preise. Offen abrufbar
GET/
v1/ pricesGeltende Preise Je Produkt der Preis, der jetzt gilt. v1 kennt genau eines, den Standardbrief:
unitCreditsje mailItem, Porto inbegriffen. Ein Versandauftrag kostetunitCredits * Anzahl der mailItems.Der Preis ist eine Ganzzahl in Credits. Was ein Credit in Euro kostet, steht in der Credit-Staffel unter
GET /v1/credit-prices.Ohne Zugang abrufbar: das ist der Listenpreis, der auf der Preisseite steht. Ein Interessent muss ihn vor der Registrierung sehen.
Ist noch kein Preis hinterlegt, antwortet die Route mit 503.
Zugang
Ohne Anmeldung.
Antworten
- 200ErfolgPrices
- 503Vorübergehend nicht verfügbarProblem
GET/
v1/ credit-pricesGeltende Credit-Staffel Was ein Credit beim Kauf netto kostet, je Menge. Ein Standardbrief kostet einen Credit, Porto inbegriffen.
Die erreichte Stufe gilt fuer die ganze Menge, nicht stufenweise. Die Umsatzsteuer kommt dazu und wird einmal auf die Summe gerundet; was ein Kauf genau kostet, rechnet
GET /v1/credit-prices/quote.Ohne Zugang abrufbar. Gilt keine Staffel, antwortet die Route mit 503
credit-price-missing.Zugang
Ohne Anmeldung.
Antworten
- 200ErfolgCreditPrice
- 503Vorübergehend nicht verfügbarProblem
GET/
v1/ credit-prices/ quoteAngebot fuer eine Menge Credits Was ein Kauf dieser Menge nach der geltenden Staffel kostet: Stufe, netto, Umsatzsteuer und brutto. Dieselbe Rechnung wie beim Kauf.
Laesst sich der Betrag nicht in einem Kauf bezahlen (unter 0,50 EUR oder ueber 999 999,99 EUR brutto), antwortet die Route mit 422
credit-quantity-out-of-range. Ohne Zugang abrufbar.Zugang
Ohne Anmeldung.
Parameter
- creditsinteger · Abfrage · Pflicht
Die Menge, 1 bis 1 000 000
- 1 bis 1000000
- Beispiel
500
Antworten
- 200ErfolgCreditQuote
- 400Anfrage passt nicht zum SchemaProblem
- 422Inhaltlich nicht verwendbarProblem
- 503Vorübergehend nicht verfügbarProblem
Vorlagen
Briefvorlagen mit Fassungen: Text mit Variablen, Standardvorlage, Musterseite. Ohne Umgebung
GET/
v1/ templatesVorlagen blaettern Neueste zuerst, immer nur die des eigenen Kontos. Jede mit dem Inhalt ihrer neuesten Fassung.
statusgrenzt ein; ohne ihn kommen aktive und archivierte.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
- statusTemplateStatusInput · Abfrage · optional
Stand der Vorlage.
Wert Bedeutung ACTIVEwaehlbar fuer neue Kampagnen, bearbeitbar ARCHIVEDnicht mehr waehlbar, keine neue Fassung; Kampagnen, die auf eine ihrer Fassungen zeigen, laufen weiter Die Standardvorlage ist immer
ACTIVE.- Werte
ACTIVE,ARCHIVED
- Werte
Antworten
- 200ErfolgTemplatePage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
POST/
v1/ templatesVorlage anlegen Legt eine Vorlage mit Fassung 1 an: Name, Text und Variablen. Den Absender kennt die Vorlage nicht; der gehoert zur Kampagne.
Geprueft wird gesetzt, nicht gezaehlt. Der Text geht durch dieselbe Satzrechnung, die spaeter druckt. Abgelehnt wird mit 422 am Feld
text, wenn er schon in seiner kuerzesten Gestalt — alle Variablen leer — nicht auf die Seite passt, wenn ein Zeichen nicht druckbar ist, oder wenn ein Platzhalter keine Variable hat (unknown-placeholder): stuende{{betrga}}im Text und hiesse die Variablebetrag, stuende das auf jedem gedruckten Brief woertlich so da. Ob der Text mit gefuellten Variablen passt, entscheidet sich je Brief bei der Annahme.Ein Konto legt hoechstens 1000 Vorlagen je Kalenderjahr (UTC) an, archivierte mitgezaehlt; darueber 422
template-limit-reached. Jede Vorlage verbraucht eine Nummer aus einem Zaehler je Jahr, an dem auch die Registrierung haengt. Neue Fassungen zaehlen nicht.Die Kopfzeile
Idempotency-Keyist Pflicht: jede Vorlage verbraucht eine laufende Nummer ihrer Kennung, und ein Timeout darf daraus keine zwei machen. Derselbe Schluessel ergibt dieselbe Vorlage; die Wiederholung traegt den Status des ersten Aufrufs undIdempotent-Replay: true.Vorlagen haben keine Umgebung: ein Test- und ein Live-Schluessel sehen dieselben Vorlagen. Eine Vorlage traegt keine Empfaengerdaten und wird nie selbst gedruckt.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idempotency-keystring · Kopfzeile · Pflicht
Je Auftrag eindeutig, am besten eine UUID. Pflicht, weil dieser Aufruf Geld kostet: derselbe Schluessel ergibt denselben Vorgang und bucht kein zweites Mal. Die Wiederholung ist an der Kopfzeile Idempotent-Replay: true zu erkennen. Gueltig 24 Stunden; danach ist derselbe Schluessel wieder ein neuer Auftrag.
- 8 bis 255 Zeichen
- Beispiel
9f1c2f7e-6f7a-4a1e-9a2b-1c9f0d3e5b77
Anfrage-Rumpf
application/json· Pflicht · Schema TemplateRequestInputEine neue Vorlage: Name, Text und Variablen. Sie entsteht mit Fassung 1.
- namestring · Pflicht
Frei gewaehlt, zur Wiedererkennung in Listen. Gehoert zur Vorlage, nicht zur Fassung. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- Beispiel
Zahlungserinnerung
- textstring · Pflicht
Der Text mit Variablen als {{name}}. Ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; der Umbruch innerhalb eines Absatzes entsteht beim Satz. Die Grenze ist die grobe Schranke — ob der Text wirklich auf die Seite passt, entscheidet die Satzrechnung mit 422
- 1 bis 5000 Zeichen
- Beispiel
{{anrede}}, Ihr Konto weist ein Guthaben von {{betrag}} aus.
- variablesTemplateVariableInput[] · optional
Die Variablen, in der Reihenfolge, in der der Editor sie zeigt
- höchstens 50 Einträge
- Vorgabe
[]
Felder je Eintrag von TemplateVariableInput
- namestring · Pflicht
Der Name, wie er in der Vorlage steht: {{anrede}}. Kleinbuchstaben, Ziffern und Unterstrich, beginnend mit einem Buchstaben, hoechstens 40 Zeichen
- Muster
^[a-z][a-z0-9_]{0,39}$ - Beispiel
anrede
- Muster
- requiredboolean · Pflicht
Pflicht heisst: ein mailItem ohne diesen Wert wird abgelehnt. Optional heisst: die Stelle bleibt leer. Vorgabewerte kommen spaeter
- kindTemplateVariableKindInput · optional
Die Art einer Variable. Ein Client entscheidet daran, wie er den Wert erfasst.
Wert Bedeutung LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt ( unsupported-characteram Wert)TEXTfreier Text: ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; so lang, wie die Seite traegt Jede Vorlage darf TEXT-Variablen verwenden. Ob der Text passt, entscheidet je Brief die Satzrechnung; zu lang macht nur diesen einen Brief unbrauchbar.
- Werte
LINE,TEXT - Vorgabe
LINE
- Werte
Antworten
- 200ErfolgTemplate
- 201AngelegtTemplate
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
GET/
v1/ templates/ {id}Eine Vorlage mit ihrer neuesten Fassung Nur Vorlagen des eigenen Kontos; eine fremde ist ein 404.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgTemplate
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
PUT/
v1/ templates/ {id}Vorlage bearbeiten Ersetzt Name, Text und Variablen vollstaendig. Kein PATCH: eine Vorlage, die sich in Teilen aendern laesst, ist eine, deren Zustand nach zwei Aufrufen niemand mehr kennt.
Weichen Text oder Variablen von der neuesten Fassung ab, entsteht eine neue Fassung. Sie wird geprueft wie bei der Anlage (422 am Feld
text). Kampagnen bleiben auf ihrer Fassung; eine neuere erreicht sie erst ueberPUT /v1/campaigns/{id}/template-version, wo die wartenden Briefe durchgerechnet werden. Bearbeiten ist deshalb nie riskant. Aendert sich nur der Name, entsteht keine Fassung. Aendert sich nichts, ist die Antwort dieselbe Vorlage — eine Wiederholung schadet nicht.baseVersionnennt die Fassung, auf der die Aenderung aufsetzt. Ist inzwischen eine neuere entstanden, oder war ein gleichzeitiger Aufruf schneller, kommt 409template-version-conflictstatt eines stillen Ueberschreibens.baseVersionschuetzt Text und Variablen. Der Name ist keine Fassung: aendert sich nur er, gilt der zuletzt geschriebene - ausser es ist dazwischen eine neue Fassung entstanden, dann ebenfalls 409.Eine archivierte Vorlage nimmt keine Aenderung mehr an: 422
template-not-active.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· Pflicht · Schema TemplateUpdateRequestInputDie Vorlage vollstaendig: Name, Text und Variablen.
Weichen Text oder Variablen von der neuesten Fassung ab, entsteht eine neue Fassung. Aendert sich nur der Name, entsteht keine.
- namestring · Pflicht
Frei gewaehlt, zur Wiedererkennung in Listen. Gehoert zur Vorlage, nicht zur Fassung. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- Beispiel
Zahlungserinnerung
- textstring · Pflicht
Der Text mit Variablen als {{name}}. Ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; der Umbruch innerhalb eines Absatzes entsteht beim Satz. Die Grenze ist die grobe Schranke — ob der Text wirklich auf die Seite passt, entscheidet die Satzrechnung mit 422
- 1 bis 5000 Zeichen
- Beispiel
{{anrede}}, Ihr Konto weist ein Guthaben von {{betrag}} aus.
- variablesTemplateVariableInput[] · optional
Die Variablen, in der Reihenfolge, in der der Editor sie zeigt
- höchstens 50 Einträge
- Vorgabe
[]
Felder je Eintrag von TemplateVariableInput
- namestring · Pflicht
Der Name, wie er in der Vorlage steht: {{anrede}}. Kleinbuchstaben, Ziffern und Unterstrich, beginnend mit einem Buchstaben, hoechstens 40 Zeichen
- Muster
^[a-z][a-z0-9_]{0,39}$ - Beispiel
anrede
- Muster
- requiredboolean · Pflicht
Pflicht heisst: ein mailItem ohne diesen Wert wird abgelehnt. Optional heisst: die Stelle bleibt leer. Vorgabewerte kommen spaeter
- kindTemplateVariableKindInput · optional
Die Art einer Variable. Ein Client entscheidet daran, wie er den Wert erfasst.
Wert Bedeutung LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt ( unsupported-characteram Wert)TEXTfreier Text: ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; so lang, wie die Seite traegt Jede Vorlage darf TEXT-Variablen verwenden. Ob der Text passt, entscheidet je Brief die Satzrechnung; zu lang macht nur diesen einen Brief unbrauchbar.
- Werte
LINE,TEXT - Vorgabe
LINE
- Werte
- baseVersioninteger · optional
Die Fassung, auf der diese Aenderung aufsetzt. Ist inzwischen eine neuere entstanden, 409
template-version-conflictstatt eines stillen Ueberschreibens. Ohne Angabe gilt die neueste- mindestens 1
- Beispiel
3
Antworten
- 200ErfolgTemplate
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
GET/
v1/ templates/ {id}/ versionsDie Fassungen einer Vorlage Neueste zuerst. Eine Fassung aendert sich nie und verschwindet nicht, solange es das Konto gibt — auch keine, auf die keine Kampagne mehr zeigt.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200ErfolgTemplateVersionPage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
GET/
v1/ templates/ {id}/ versions/ {version}Eine Fassung Text und Variablen genau dieser Fassung, unveraenderlich.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
- versioninteger · Pfad · Pflicht
- 1 bis 2147483647
Antworten
- 200ErfolgTemplateVersion
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
POST/
v1/ templates/ {id}/ archiveVorlage archivieren Die Vorlage laesst sich fuer keine neue Kampagne mehr waehlen und bekommt keine neue Fassung. Kampagnen, die eine ihrer Fassungen drucken, laufen weiter und duerfen zwischen ihren Fassungen wechseln.
Die Standardvorlage laesst sich nicht archivieren (422
template-is-default): erst eine andere zur Standardvorlage machen.Zweimal archivieren ist derselbe Zustand und kein Fehler. Es gibt keinen Weg zurueck; wer eine archivierte Vorlage wieder braucht, legt sie mit ihrem Text neu an.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgTemplate
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ templates/ {id}/ make-defaultZur Standardvorlage machen Macht diese Vorlage zur Standardvorlage des Kontos; die bisherige verliert die Rolle und bleibt sonst, wie sie ist. Eine Kampagne ohne
templateIdbekommt kuenftig diese. Kampagnen, die schon bestehen, aendern sich nicht.Jedes Konto hat genau eine Standardvorlage; die Datenbank haelt das fest. Ist diese Vorlage es schon, ist das kein Fehler. Eine archivierte Vorlage laesst sich nicht dazu machen: 422
template-not-active.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgTemplate
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ templates/ {id}/ previewDie Musterseite einer Vorlage Werte rein, gesetzte Seite raus — fuer die neueste Fassung oder einen ungespeicherten Entwurf (
template). Der Editor holt die Vorschau vom Server und baut das Layout nicht nach: eine zweite Fassung des Satzes waere der Fehler, den niemand bemerkt, bis die Vorschau etwas verspricht, das der Drucker nicht haelt.Ein Entwurf geht durch dieselbe Pruefung wie
PUT /v1/templates/{id}: Schema (400); Platzhalter ohne Variable, ein Zeichen, das der Satz nicht kennt, und ein Text, der schon leer nicht auf die Seite passt (422 am Feldtemplate.text). Gespeichert wird nichts.Im Fenster steht
sender, wenn er mitkommt — etwa der Absender einer Kampagne —, sonst ein erkennbar erfundener Musterabsender. Ein Absender, der das Anschriftfeld sprengt, ist 422 am Feldsender.Ueber die Kopfzeile
Acceptwaehlt der Aufrufer die Form:application/pdfliefert genau das Artefakt, das spaeter gedruckt wird;image/pngdieselbe Seite gerastert, aus der PDF. Ohne Angabe kommt PDF. Die Seite ist fluechtig und wird nirgends gespeichert.valuesist freiwillig, und Pflichtvariablen werden hier nicht erzwungen. Was fehlt, bleibt leer; nur eine mehrzeilige Variable (TEXT) ohne Wert zeigt einen Mustertext, damit die Seite nicht leer ist — die Standardvorlage besteht aus nichts als{{text}}. Ein ausdrueckliches""bleibt leer.422 an
values.<name>:unknown-variable,unsupported-character(ein Zeichen, das sich nicht drucken laesst, ein Zeilenumbruch in einer einzeiligen Variable) undbody-too-long, wenn sich der Ueberlauf genau einer mehrzeiligen Variable zuschreiben laesst, sonst anvalues. Passt die Seite nicht, kommt 422 und kein Bild.Fehler kommen wie ueberall als
application/problem+json, siehe das SchemaProblem: 400, 401, 403, 404 und 422. Der Vertrag fuehrt nur den Erfolgsfall, weilproducesfuer alle Antworten einer Route gilt.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· PflichtAlle Felder sind freiwillig.
templateist ein ungespeicherter Entwurf, in derselben Form wie Text und Variablen im Rumpf vonPUT /v1/templates/{id}. Ist er da, wird er statt der neuesten Fassung gesetzt und genauso geprueft; gespeichert wird nichts.senderist der Absender im Fenster, etwa der einer Kampagne. Fehlt er, steht dort ein erkennbar erfundener Musterabsender: der Absender gehoert zur Kampagne und nicht zur Vorlage.recipientist die Anschrift im Fenster. Fehlt sie, steht dort eine erkennbar erfundene Musteranschrift.- templateTemplateContentInput · optional
Text und Variablen einer Vorlage, wie der Aufrufer sie schreibt.
Dieselbe Form und dieselbe Pruefung bei der Anlage, bei der Aenderung und als Entwurf der Musterseite. Was die Musterseite als Entwurf setzt, nimmt die Aenderung auch an.
Felder von TemplateContentInput
- textstring · Pflicht
Der Text mit Variablen als {{name}}. Ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; der Umbruch innerhalb eines Absatzes entsteht beim Satz. Die Grenze ist die grobe Schranke — ob der Text wirklich auf die Seite passt, entscheidet die Satzrechnung mit 422
- 1 bis 5000 Zeichen
- Beispiel
{{anrede}}, Ihr Konto weist ein Guthaben von {{betrag}} aus.
- variablesTemplateVariableInput[] · optional
Die Variablen, in der Reihenfolge, in der der Editor sie zeigt
- höchstens 50 Einträge
- Vorgabe
[]
Felder je Eintrag von TemplateVariableInput
- namestring · Pflicht
Der Name, wie er in der Vorlage steht: {{anrede}}. Kleinbuchstaben, Ziffern und Unterstrich, beginnend mit einem Buchstaben, hoechstens 40 Zeichen
- Muster
^[a-z][a-z0-9_]{0,39}$ - Beispiel
anrede
- Muster
- requiredboolean · Pflicht
Pflicht heisst: ein mailItem ohne diesen Wert wird abgelehnt. Optional heisst: die Stelle bleibt leer. Vorgabewerte kommen spaeter
- kindTemplateVariableKindInput · optional
Die Art einer Variable. Ein Client entscheidet daran, wie er den Wert erfasst.
Wert Bedeutung LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt ( unsupported-characteram Wert)TEXTfreier Text: ein Zeilenumbruch beginnt eine neue Zeile, eine Leerzeile einen neuen Absatz; so lang, wie die Seite traegt Jede Vorlage darf TEXT-Variablen verwenden. Ob der Text passt, entscheidet je Brief die Satzrechnung; zu lang macht nur diesen einen Brief unbrauchbar.
- Werte
LINE,TEXT - Vorgabe
LINE
- Werte
- valuesobject · optional
Die Werte je Variablenname. Was hier fehlt, bleibt leer; eine TEXT-Variable ohne Wert zeigt einen Mustertext
- Namen frei, je Wert
string - Namen nach Muster
^[a-z][a-z0-9_]{0,39}$ - höchstens 5000 Zeichen je Wert
- Vorgabe
{} - Beispiel
{"anrede":"Sehr geehrte Frau Mustermann","betrag":"12,50 Euro"}
- Namen frei, je Wert
- recipientRecipientInput · optional
Die Anschrift, an die der Brief geht
Felder von RecipientInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
- senderSenderInput · optional
Der Absender der Kampagne. Steht als Ruecksendeangabe im Anschriftfeld und wird mit gesetzt — ein zu langer Firmenname wird deshalb mit 422 abgelehnt, ein Steuerzeichen in irgendeinem Feld ebenso
Felder von SenderInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
Antworten
- 200Erfolgstring (binary) als application/pdf oder image/png
Die gesetzte Seite, als PDF oder als PNG
Kampagnen
Eine Kampagne ist ein Absender und die Fassung einer Vorlage, die sie druckt
GET/
v1/ campaignsKampagnen blaettern Neueste zuerst, immer nur die des eigenen Kontos und der eigenen Umgebung.
templateIdgrenzt auf die Kampagnen ein, die eine Fassung dieser Vorlage drucken.v1 liefert ausschliesslich Kampagnen mit
product: LETTER_STANDARD. Postkarten-Kampagnen aus K1 sind bis v1.1 geparkt und erscheinen hier nicht — der Vertrag fuehrt fuer sie derzeit keine Gestalt.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
- statusCampaignStatusInput · Abfrage · optional
Stand der Kampagne.
Wert Bedeutung wer setzt ihn ACTIVEbedienbar: Fassung wechseln, Absender aendern, verschicken die Anlage ARCHIVEDstillgelegt, nimmt keinen Versandauftrag mehr an der Kunde selbst CANCELLEDvom Betreiber stillgelegt nur der Betreiber Es gibt bewusst keinen Entwurf und keinen Wartezustand. Eine Brief-Kampagne ist mit der Anlage versandbereit: es gibt nichts zu bestellen und auf nichts zu warten.
Archivieren gibt die Kennung nicht frei. Eine Luecke in einer Reihe, die Menschen vorlesen und abtippen, waere schlimmer als eine hohe Zahl.
- Werte
ACTIVE,ARCHIVED,CANCELLED
- Werte
- productProductInput · Abfrage · optional
Das Produkt, das eine Kampagne herstellen laesst.
LETTER_STANDARD: Standardbrief. Eine DIN-A4-Seite, einseitig, schwarzweiss, im Fensterumschlag DIN lang. Ohne Auflage — gedruckt wird auf Abruf, ein Brief oder tausende.POSTCARD_MAXI: Maxi Postkarte ohne Fenster. Mit Auflage — das Motiv wird vorab in Stueckzahl gedruckt, der Versand verbraucht den Vorrat.
Der Unterschied zwischen beiden ist genau einer, und alles Weitere folgt daraus: hat die Kampagne eine Auflage? Welches Feld fuer welches Produkt gilt, setzen CHECK-Bedingungen in der Datenbank durch.
Diese Aufzaehlung ist nicht abgeschlossen. Jedes kuenftige Produkt ist ein Wert mehr und keine neue Route; ein Aufrufer, der einen unbekannten Wert wie einen Fehler behandelt, bricht bei der naechsten Erweiterung.
- Werte
LETTER_STANDARD,POSTCARD_MAXI
- templateIdstring (uuid) · Abfrage · optional
Nur Kampagnen, die eine Fassung dieser Vorlage drucken
Antworten
- 200Erfolg{ data: Campaign[], next_cursor: string | null }
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ campaignsKampagne anlegen Legt eine Kampagne an.
productist die Weiche im Rumpf: v1 kenntLETTER_STANDARD, den Standardbrief.Eine Brief-Kampagne ist ein Absender und die Fassung einer Vorlage:
templateIdnennt die Vorlage, gedruckt wird deren neueste Fassung. FehlttemplateId, gilt die Standardvorlage des Kontos. Eine spaetere Fassung erreicht die Kampagne erst ueberPUT /v1/campaigns/{id}/template-version. Die Kampagne kostet nichts und ist sofort versandbereit — es gibt nichts zu bestellen und auf nichts zu warten.Eine Kampagne anzulegen braucht nur
campaigns:write, auch wenn sie eine Vorlage nennt: sie liest nur, welche Fassung die neueste ist.Die Kopfzeile
Idempotency-Keyist trotzdem Pflicht. Hier fliesst kein Geld, aber jede Kampagne verbraucht eine laufende Nummer aus einer Reihe, die Menschen vorlesen und abtippen; ein Timeout darf daraus keine zwei machen. Derselbe Schluessel ergibt dieselbe Kampagne; die Wiederholung traegt den Status des ersten Aufrufs und die KopfzeileIdempotent-Replay: true.Der Absender wird gesetzt, nicht gezaehlt. Er geht durch dieselbe Satzrechnung, die spaeter druckt: sprengt er das Anschriftfeld oder traegt er ein Zeichen, das sich nicht drucken laesst, kommt 422 am Feld
sender. Ein Steuerzeichen ist dasselbe 422 in jedem Feld des Absenders, auch im Zusatz und im Namen neben einer Firma, die nicht in der Ruecksendeangabe stehen. Den Text hat schon das Speichern der Fassung geprueft.Weitere 422:
unknown-template(die Vorlage gibt es in diesem Konto nicht) undtemplate-not-active(die Vorlage ist archiviert), beide am FeldtemplateId.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idempotency-keystring · Kopfzeile · Pflicht
Je Auftrag eindeutig, am besten eine UUID. Pflicht, weil dieser Aufruf Geld kostet: derselbe Schluessel ergibt denselben Vorgang und bucht kein zweites Mal. Die Wiederholung ist an der Kopfzeile Idempotent-Replay: true zu erkennen. Gueltig 24 Stunden; danach ist derselbe Schluessel wieder ein neuer Auftrag.
- 8 bis 255 Zeichen
- Beispiel
9f1c2f7e-6f7a-4a1e-9a2b-1c9f0d3e5b77
Anfrage-Rumpf
application/json· Pflicht- productstring · Pflicht
- Wert
LETTER_STANDARD
- Wert
- namestring · Pflicht
Frei gewaehlt, zur Wiedererkennung in Listen. Ohne Steuerzeichen
- 1 bis 120 Zeichen
- Beispiel
Fruehjahrsaktion 2026
- senderSenderInput · Pflicht
Der Absender der Kampagne. Steht als Ruecksendeangabe im Anschriftfeld und wird mit gesetzt — ein zu langer Firmenname wird deshalb mit 422 abgelehnt, ein Steuerzeichen in irgendeinem Feld ebenso
Felder von SenderInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
- templateIdstring (uuid) · optional
Die Vorlage. Die Kampagne druckt deren neueste Fassung. Fehlt das Feld, gilt die Standardvorlage des Kontos
Antworten
- 200ErfolgCampaign
- 201AngelegtCampaign
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
GET/
v1/ campaigns/ {id}Eine Kampagne mit der Fassung, die sie druckt Nur Kampagnen des eigenen Kontos und der eigenen Umgebung. Eine Kampagne aus der jeweils anderen Umgebung ist ein 404 und kein 403: dass es sie gibt, geht den Aufrufer nichts an.
letter.templatenennt Vorlage, Fassung und deren Inhalt, dazunewerVersionAvailable, wenn die Vorlage inzwischen eine neuere Fassung hat.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgCampaign
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
PATCH/
v1/ campaigns/ {id}Name oder Absender aendern Aendert, was sich aendern laesst: den Namen zur Wiedererkennung und den Absender. Kennung, Produkt und Umgebung sind unveraenderlich; die Fassung wechselt
PUT /v1/campaigns/{id}/template-version.Auch der Absender geht durch die Satzpruefung. Er steht als Ruecksendeangabe im Fenster, und ein zu langer Firmenname sprengt das Layout — das faellt sonst erst auf dem Kuvertiertisch auf. Ein Steuerzeichen ist in jedem Feld des Absenders 422 am Feld
sender.Haelt ein anderer Vorgang die Kampagne laenger als 5 s, etwa die Annahme eines grossen Versandauftrags: 409
campaign-busy, dann wiederholen.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· Pflicht- namestring · optional
Ohne Steuerzeichen
- 1 bis 120 Zeichen
- senderSenderInput · optional
Der Absender der Kampagne. Steht als Ruecksendeangabe im Anschriftfeld und wird mit gesetzt — ein zu langer Firmenname wird deshalb mit 422 abgelehnt, ein Steuerzeichen in irgendeinem Feld ebenso
Felder von SenderInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
Antworten
- 200ErfolgCampaign
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
PUT/
v1/ campaigns/ {id}/ template-versionDie Fassung wechseln — der gepruefte Vorgang Stellt die Kampagne auf eine andere Fassung um: eine neuere derselben Vorlage, eine aeltere, oder eine Fassung einer anderen Vorlage des Kontos (
templateId). OhnetemplateIdbleibt es die Vorlage, die die Kampagne schon druckt.Gedruckt wird die Fassung, auf die die Kampagne beim Stapelbau zeigt — auch fuer Briefe, die vorher angenommen wurden. Damit das die Zusage der Annahme nicht bricht, werden die wartenden Briefe gegen die neue Fassung durchgerechnet, und der Wechsel wird abgelehnt, wenn er einen bezahlten Brief beschaedigen wuerde: der Text laeuft aus der Seite, eine neue Pflichtvariable hat bei den Wartenden keinen Wert, oder eine Variable wird einzeilig und ein Wartender traegt dort einen Zeilenumbruch. Harmlose Wechsel gehen jederzeit durch.
Die Ablehnung ist 422 mit je einem Eintrag in
errors[]je Grund, beide am Feldversion:queued-item-not-printableundqueued-item-missing-value. Genannt werden Anzahlen, keine Briefe. Die Kampagne bleibt dann auf ihrer Fassung; wer trotzdem wechseln will, storniert die wartenden Auftraege.Werte einer Variable, die die neue Fassung nicht kennt, werden aus den wartenden Briefen entfernt. Eine spaeter wieder erklaerte Variable gleichen Namens ist bei ihnen leer.
Weitere 422:
unknown-template(FeldtemplateId),template-not-active(eine andere, archivierte Vorlage; zwischen den Fassungen ihrer eigenen Vorlage darf eine Kampagne auch dann wechseln, wenn die archiviert ist),unknown-template-version(Feldversion) undcampaign-not-activefuer eine archivierte oder stornierte Kampagne. Dieselbe Fassung noch einmal ist kein Fehler.Braucht nur
campaigns:write. Haelt ein anderer Vorgang die Kampagne laenger als 5 s, etwa die Annahme eines grossen Versandauftrags: 409campaign-busy, dann wiederholen.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· Pflicht · Schema TemplateVersionChangeInput- templateIdstring (uuid) · optional
Die Vorlage der Fassung. Fehlt das Feld, bleibt es die Vorlage, die die Kampagne schon druckt
- versioninteger · Pflicht
Die Fassung, die die Kampagne kuenftig druckt
- 1 bis 2147483647
- Beispiel
3
Antworten
- 200ErfolgCampaign
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ campaigns/ {id}/ archiveKampagne stilllegen Legt die Kampagne still: sie nimmt keinen Versandauftrag mehr an und wechselt ihre Fassung nicht mehr. Bereits angenommene Briefe sind davon unberuehrt — sie sind bezahlt und werden gedruckt. Die Vorlage bleibt, wie sie ist.
Das darf der Kunde selbst, anders als bei der Postkarte: eine Kampagne ohne Auflage hat kein bezahltes Material, das jemand erklaeren muesste.
Zweimal archivieren ist derselbe Zustand und kein Fehler. Der Aufruf braucht deshalb keinen
Idempotency-Key.Die Kennung wird nicht frei. Eine Luecke in einer Reihe, die Menschen vorlesen und abtippen, waere schlimmer als eine hohe Zahl.
Haelt ein anderer Vorgang die Kampagne laenger als 5 s, etwa die Annahme eines grossen Versandauftrags: 409
campaign-busy, dann wiederholen.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgCampaign
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
POST/
v1/ campaigns/ {id}/ previewDie Musterseite der Kampagne Die Fassung, die die Kampagne druckt, mit ihrem Absender gesetzt: Werte rein, gesetzte Seite raus. Der Editor holt die Vorschau vom Server und baut das Layout nicht nach — eine zweite Fassung des Satzes waere der Fehler, den niemand bemerkt, bis die Vorschau etwas verspricht, das der Drucker nicht haelt.
Einen Entwurf setzt diese Route nicht; das tut
POST /v1/templates/{id}/preview, dort auch mit einem Absender nach Wahl.Die Seite ist fluechtig. Sie wird nirgends gespeichert, und es gibt keine Einzel-PDF je Brief: das Artefakt der Produktion ist die Stapel-PDF.
Ueber die Kopfzeile
Acceptwaehlt der Aufrufer die Form:application/pdfliefert genau das Artefakt, das spaeter gedruckt wird;image/pngliefert dieselbe Seite gerastert. Das PNG entsteht aus der PDF und nicht daneben. Ohne Angabe kommt PDF.valuesist freiwillig, und Pflichtvariablen werden hier nicht erzwungen: die Vorschau zeigt, was gesetzt wuerde. Was fehlt, bleibt leer; nur eine mehrzeilige Variable (TEXT) ohne Wert zeigt einen Mustertext, damit die Seite nicht leer ist. Ein ausdrueckliches""bleibt leer.422 an
values.<name>:unknown-variable(die Fassung kennt den Namen nicht — sonst waere der Wert stillschweigend wirkungslos),unsupported-character(ein Zeichen, das sich nicht drucken laesst, ein Zeilenumbruch in einer einzeiligen Variable) undbody-too-long, wenn sich der Ueberlauf genau einer mehrzeiligen Variable zuschreiben laesst, sonst anvalues. Passt die Seite nicht, kommt 422 und kein Bild: ein Blatt, das sich nicht drucken laesst, waere genau die Zusage, die diese Route verhindern soll.Fehler kommen wie ueberall als
application/problem+json, siehe das SchemaProblem: 400, 401, 403, 404 (Kampagne fehlt, gehoert einem anderen Konto oder liegt in der anderen Umgebung) und 422. Der Vertrag fuehrt nur den Erfolgsfall, weilproducesfuer alle Antworten einer Route gilt und die Fehler sonst faelschlich als PDF und PNG ausgewiesen waeren.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· PflichtAlle Felder sind freiwillig.
recipientist die Anschrift im Fenster. Fehlt sie, steht dort eine erkennbar erfundene Musteranschrift.- valuesobject · optional
Die Werte je Variablenname. Was hier fehlt, bleibt leer; eine TEXT-Variable ohne Wert zeigt einen Mustertext
- Namen frei, je Wert
string - Namen nach Muster
^[a-z][a-z0-9_]{0,39}$ - höchstens 5000 Zeichen je Wert
- Vorgabe
{} - Beispiel
{"anrede":"Sehr geehrte Frau Mustermann","betrag":"12,50 Euro"}
- Namen frei, je Wert
- recipientRecipientInput · optional
Die Anschrift, an die der Brief geht
Felder von RecipientInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
Antworten
- 200Erfolgstring (binary) als application/pdf oder image/png
Die gesetzte Seite, als PDF oder als PNG
Versandauftraege
Versandauftraege gegen eine Kampagne einreichen, lesen, stornieren
GET/
v1/ campaigns/ {id}/ shipmentsVersandauftraege einer Kampagne Die Auftraege einer Kampagne, neueste zuerst, ohne ihre mailItems. Geblaettert wird mit
cursorausnext_cursorder vorigen Seite.Eine Kampagne, die es in diesem Konto und dieser Umgebung nicht gibt, ist 404 — auch dann, wenn die Liste ohnehin leer waere.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200ErfolgShipmentPage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
POST/
v1/ campaigns/ {id}/ shipmentsVersandauftrag einreichen Nimmt 1 bis 5000 Briefe gegen eine Brief-Kampagne an: je Zeile eine Anschrift und die Werte der Vorlage. Bepreist und in LIVE abgebucht wird der Auftrag als Ganzes,
unitCreditsder geltenden Preisversion mal Anzahl der Zeilen. Abgebucht wird, was zuerst ablaeuft.Ganz oder gar nicht. Ist eine Zeile nicht verwendbar, wird der ganze Auftrag mit 422 abgelehnt, und
errors[]nennt alle unbrauchbaren Zeilen auf einmal, aufsteigend alsitems.<i>mit dem Codeitem-not-usable. Der Trockenlauf daneben antwortet in derselben Form. Was nicht zum Schema passt, ist dagegen 400 mit genauem Feldpfad.Gruende nennt die Antwort nur an einzelnen Werten: direkt hinter
items.<i>steht dann je Wert ein Eintragitems.<i>.letter.values.<name>mitunsupported-character(ein Zeichen, das sich nicht drucken laesst, ein Zeilenumbruch in einer einzeiligen Variable) oderbody-too-long(der Wert treibt den Brief aus der Seite). Anschrift, Sperrliste, fehlender Pflichtwert und unbekannte Variable bleiben ohne Grund. Hoechstens 5000 solcher Wertbefunde je Antwort.Die Kopfzeile
Idempotency-Keyist Pflicht: derselbe Schluessel mit demselben Rumpf ergibt denselben Auftrag und bucht kein zweites Mal; die Wiederholung traegt den Status des ersten Aufrufs undIdempotent-Replay: true. Nach einer Ablehnung ist der Schluessel wieder frei:- 402
insufficient-funds: es fehlen Credits. Aufladen und mit demselben Schluessel wiederholen. - 409
campaign-changed: Fassung oder Absender haben sich geaendert, waehrend der Auftrag geprueft wurde. Mit demselben Schluessel wiederholen; geprueft wird dann gegen den neuen Stand. - 409
campaign-busy: ein anderer Vorgang haelt die Kampagne laenger als 5 s, etwa ein Fassungswechsel. Mit demselben Schluessel wiederholen.
In TEST wird alles geprueft und angelegt, aber nie gebucht und nie gedruckt. Der Rumpf darf bis zu 16 MiB gross sein (413).
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
- idempotency-keystring · Kopfzeile · Pflicht
Je Auftrag eindeutig, am besten eine UUID. Pflicht, weil dieser Aufruf Geld kostet: derselbe Schluessel ergibt denselben Vorgang und bucht kein zweites Mal. Die Wiederholung ist an der Kopfzeile Idempotent-Replay: true zu erkennen. Gueltig 24 Stunden; danach ist derselbe Schluessel wieder ein neuer Auftrag.
- 8 bis 255 Zeichen
- Beispiel
9f1c2f7e-6f7a-4a1e-9a2b-1c9f0d3e5b77
Anfrage-Rumpf
application/json· Pflicht · Schema ShipmentRequestInputDie Zeilen eines Versandauftrags. Ihre Reihenfolge ist die
positiondes mailItems, und auf sie beziehen sich die Feldpfadeitems.<i>.Grenzen: 1 bis 5000 Zeilen (400); je Wert und je eingesetztem Brieftext 5000 Zeichen (400 bzw. 422); eingesetzter Brieftext aller Zeilen zusammen 15 000 000 Zeichen (422
text-volume-exceeded); Rumpf 16 MiB (413).- itemsShipmentItemInput[] · Pflicht
- 1 bis 5000 Einträge
Felder je Eintrag von ShipmentItemInput
- recipientRecipientInput · Pflicht
Die Anschrift, an die der Brief geht
Felder von RecipientInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
- letterLetterItemValuesInput · Pflicht
Was ein Brief ueber seine Anschrift hinaus braucht: die Werte der Vorlage
Felder von LetterItemValuesInput
- valuesobject · optional
Die Werte je Variablenname. Ein Name, den die Vorlage nicht kennt, oder ein fehlender Pflichtwert macht die Zeile unbrauchbar
- Namen frei, je Wert
string - Namen nach Muster
^[a-z][a-z0-9_]{0,39}$ - höchstens 5000 Zeichen je Wert
- Vorgabe
{} - Beispiel
{"anrede":"Sehr geehrte Frau Mustermann","betrag":"12,50 Euro"}
- Namen frei, je Wert
Antworten
- 200ErfolgShipment
- 201AngelegtShipment
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 402Guthaben reicht nichtProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 413Anfrage zu großProblem
- 422Inhaltlich nicht verwendbarProblem
- 503Vorübergehend nicht verfügbarProblem
- 402
POST/
v1/ campaigns/ {id}/ shipments/ previewVersandauftrag pruefen, ohne ihn einzureichen Der echte Aufruf ohne Wirkung: dieselbe Pruefung wie die Annahme, aber nichts wird angelegt, nichts gebucht, und es braucht keinen
Idempotency-Key. Der Bereich ist trotzdemshipments:write, weil die Antwort sagt, was die Annahme taete.Antwortet immer 200 mit dem Preis, auch wenn der Auftrag abgelehnt wuerde.
rejectionsnennt dieselben Codes wieerrors[]der Annahme, unbrauchbare Zeilen alsitems.<i>, Gruende nur an einzelnen Werten alsitems.<i>.letter.values.<name>wie bei der Annahme. Fehlendes Guthaben ist keine Ablehnung, nursufficientFunds: false.balanceCreditssteht nur fuer Sitzungen und Schluessel mitbalance:readdarin, sonstnull.Eine Momentaufnahme. Sperrliste, Preis und Vorlage koennen sich bis zur Annahme aendern; verbindlich ist erst die Annahme.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Anfrage-Rumpf
application/json· Pflicht · Schema ShipmentRequestInputDie Zeilen eines Versandauftrags. Ihre Reihenfolge ist die
positiondes mailItems, und auf sie beziehen sich die Feldpfadeitems.<i>.Grenzen: 1 bis 5000 Zeilen (400); je Wert und je eingesetztem Brieftext 5000 Zeichen (400 bzw. 422); eingesetzter Brieftext aller Zeilen zusammen 15 000 000 Zeichen (422
text-volume-exceeded); Rumpf 16 MiB (413).- itemsShipmentItemInput[] · Pflicht
- 1 bis 5000 Einträge
Felder je Eintrag von ShipmentItemInput
- recipientRecipientInput · Pflicht
Die Anschrift, an die der Brief geht
Felder von RecipientInput
- namestring · Pflicht
Person oder Ansprechpartner
- 1 bis 120 Zeichen
- companystring · optional
- 1 bis 120 Zeichen
- streetstring · Pflicht
- 1 bis 120 Zeichen
- Beispiel
Musterweg 1
- addressExtrastring · optional
Zusatz wie "c/o Meier" oder "Wohnung 4"
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
- 1 bis 16 Zeichen
- citystring · Pflicht
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
- letterLetterItemValuesInput · Pflicht
Was ein Brief ueber seine Anschrift hinaus braucht: die Werte der Vorlage
Felder von LetterItemValuesInput
- valuesobject · optional
Die Werte je Variablenname. Ein Name, den die Vorlage nicht kennt, oder ein fehlender Pflichtwert macht die Zeile unbrauchbar
- Namen frei, je Wert
string - Namen nach Muster
^[a-z][a-z0-9_]{0,39}$ - höchstens 5000 Zeichen je Wert
- Vorgabe
{} - Beispiel
{"anrede":"Sehr geehrte Frau Mustermann","betrag":"12,50 Euro"}
- Namen frei, je Wert
Antworten
- 200ErfolgShipmentPreview
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 413Anfrage zu großProblem
- 503Vorübergehend nicht verfügbarProblem
GET/
v1/ shipmentsVersandauftraege des Kontos Alle Auftraege des Kontos in der Umgebung des Aufrufers, ueber alle Kampagnen, neueste zuerst, ohne ihre mailItems. Filter gibt es heute keine.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200ErfolgShipmentPage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
GET/
v1/ shipments/ {id}Ein Versandauftrag Der Beleg, wie ihn die Annahme zurueckgegeben hat, mit dem heutigen Status. Die mailItems stehen unter
/v1/shipments/{id}/items.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgShipment
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
GET/
v1/ shipments/ {id}/ itemsDie mailItems eines Versandauftrags Die Stuecke in der Reihenfolge, in der sie eingereicht wurden, mit Anschrift und Werten.
indexist dieselbe Zahl wieitems.<i>einer Ablehnung. Geblaettert wird mitcursorausnext_cursor.Nach Ablauf der Loeschfrist wird die Liste geleert;
itemCountbleibt.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200ErfolgMailItemPage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
POST/
v1/ shipments/ {id}/ cancelVersandauftrag stornieren Storniert den ganzen Auftrag, solange er auf
QUEUEDwartet. Ist er einem Stapel zugeteilt, ist er auf dem Weg zum Druck und laesst sich nicht mehr zurueckholen: 422shipment-not-cancellable. Einzelne mailItems lassen sich nicht stornieren.In LIVE kommt der volle Betrag zurueck, sichtbar als
refundedCreditsund alsSHIPMENT_REFUNDim Kontoauszug. Die Credits gehen in die Posten zurueck, aus denen sie kamen, mit deren Ablauf; ist einer inzwischen abgelaufen, verfaellt der Teil sofort wieder und steht alsCREDIT_EXPIRYim Auszug. Ein Auftrag von vor 3.0.0 wird in Cent gutgeschrieben (legacyRefundedCents). Ein schon stornierter Auftrag kommt unveraendert zurueck und wird nicht ein zweites Mal gutgeschrieben. Dieser Aufruf braucht deshalb keinenIdempotency-Key: er ist von sich aus wiederholbar.Aendert sich der Auftrag waehrend des Aufrufs, etwa weil er gerade einem Stapel zugeteilt wird, kommt 409 mit demselben Code; dann den Auftrag neu lesen.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 200ErfolgShipment
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
- 409Konflikt mit dem aktuellen StandProblem
- 422Inhaltlich nicht verwendbarProblem
Sperrliste
Empfaenger, an die nicht geschrieben wird. Je Konto und global
GET/
v1/ blocklistSperrliste blaettern Neueste zuerst. Globale Eintraege des Betreibers sind daran zu erkennen, dass ihr scope GLOBAL ist.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
- scopeBlocklistScopeInput · Abfrage · optional
ACCOUNT gilt nur fuer das eigene Konto, GLOBAL fuer alle. Globale Eintraege setzt nur der Betreiber und sie lassen sich nicht aus dem Konto heraus entfernen
- Werte
ACCOUNT,GLOBAL
- Werte
Antworten
- 200Erfolg{ data: BlocklistEntry[], next_cursor: string | null }
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
POST/
v1/ blocklistEmpfaenger sperren Verglichen wird auf der normalisierten Anschrift: Leerraum zusammengezogen, klein geschrieben. Ausdruecklich ohne Abkuerzungsaufloesung — "Musterstr. 1" und "Musterstrasse 1" sind zwei Eintraege. Wer sicher sperren will, sperrt die Schreibweise, die er auch versendet.
Derselbe Empfaenger ein zweites Mal ergibt denselben Eintrag und 200 statt 201.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Anfrage-Rumpf
application/json· Pflicht- namestring · Pflicht
Ohne Steuerzeichen
- 1 bis 120 Zeichen
- companystring · optional
Ohne Steuerzeichen
- 1 bis 120 Zeichen
- streetstring · Pflicht
Ohne Steuerzeichen
- 1 bis 120 Zeichen
- postalCodestring · Pflicht
Ohne Steuerzeichen
- 1 bis 16 Zeichen
- citystring · Pflicht
Ohne Steuerzeichen
- 1 bis 120 Zeichen
- countrystring · optional
ISO 3166-1 alpha-2. Heute ist nur DE moeglich: der Standardbrief kennt nur Inlandsformat und Inlandspreis
- Wert
DE - Vorgabe
DE
- Wert
- reasonstring · optional
Warum gesperrt, z.B. "Werbewiderspruch vom 03.09.". Ohne Steuerzeichen
- 1 bis 200 Zeichen
Antworten
- 200ErfolgBlocklistEntry
- 201AngelegtBlocklistEntry
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
DELETE/
v1/ blocklist/ {id}Sperre aufheben Nur eigene Eintraege. Eine globale Sperre hebt allein der Betreiber auf, und das ist der Punkt an ihr.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- idstring (uuid) · Pfad · Pflicht
Antworten
- 204Erfolg, ohne Inhaltohne Inhalt
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
- 404Nicht gefundenProblem
Guthaben
Kontostand und Buchungen
GET/
v1/ balanceGuthaben des Kontos Die verfuegbaren Credits und der naechste Ablauf.
balanceCreditszaehlt nur, was jetzt noch gilt. Ein Credit, dessen Ablauf erreicht ist, zaehlt nicht mehr mit, auch wenn sein Verfall im Kontoauszug erst etwas spaeter alsCREDIT_EXPIRYerscheint.Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Antworten
- 200ErfolgBalance
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
GET/
v1/ ledgerBuchungen blaettern Neueste zuerst. Jede Buchung fuehrt den Kontostand mit, den sie hinterlassen hat:
balanceAfterCredits. Zwei aufeinanderfolgende Buchungen in Credits passen immer zusammen; geblaettert wird ueber die Buchungsnummer und nicht ueber die Uhrzeit.Buchungen von vor 3.0.0 stehen weiter da, in Cent (
legacy*), als eigene Kette neben der in Credits. Umgerechnet wird nichts.Versandauftraege in TEST erscheinen nicht, sie kosten nichts.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200Erfolg{ data: LedgerEntry[], next_cursor: string | null }
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem
GET/
v1/ credit-lotsOffene Posten blaettern Die Posten mit verfuegbarem Rest, was zuerst ablaeuft zuerst. Verbraucht wird ebenfalls nach dem Ablauf, bei gleichem Ablauf aber zuerst der aeltere Posten (
acquiredAt); die Liste ordnet einen solchen Gleichstand nur nachid. Zusammen ergeben ihre RestebalanceCreditsausGET /v1/balance.Ein verbrauchter oder abgelaufener Posten erscheint hier nicht mehr; seine Geschichte steht im Kontoauszug.
Zugang
Mit API-Schlüssel oder Sitzung aus der Anmeldung.
Parameter
- cursorstring · Abfrage · optional
- limitinteger · Abfrage · optional
- 1 bis 100
- Vorgabe
25
Antworten
- 200ErfolgCreditLotPage
- 400Anfrage passt nicht zum SchemaProblem
- 401Nicht angemeldet oder Zugang ungültigProblem
- 403Nicht erlaubt: Bereich oder Rolle fehltProblem