Staging
Zum Inhalt springen

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.

Lebenszeichen
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.

Dokumentation

Die von der API ausgelieferte Fassung, immer zur laufenden Version.

https://api.staging.orbitsend.de/docs

Öffnen

OpenAPI 3.1

Das Dokument selbst. Aus ihm entstehen die Typen dieser Oberfläche.

https://api.staging.orbitsend.de/v1/openapi.json

Öffnen

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
    clientExtensionResultsobject · Pflicht
    • Namen frei, je Wert beliebig
    typestring · Pflicht
    • Wert public-key

    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
    clientExtensionResultsobject · Pflicht
    • Namen frei, je Wert beliebig
    typestring · Pflicht
    • Wert public-key

    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
    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: unitCredits je mailItem, Porto inbegriffen. Ein Versandauftrag kostet unitCredits * 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. status grenzt 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.

    WertBedeutung
    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

    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 Variable betrag, 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-Key ist 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 und Idempotent-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 TemplateRequestInput

    Eine 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
    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.

    WertBedeutung
    LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt (unsupported-character am 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

    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 ueber PUT /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.

    baseVersion nennt die Fassung, auf der die Aenderung aufsetzt. Ist inzwischen eine neuere entstanden, oder war ein gleichzeitiger Aufruf schneller, kommt 409 template-version-conflict statt eines stillen Ueberschreibens.

    baseVersion schuetzt 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 TemplateUpdateRequestInput

    Die 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
    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.

    WertBedeutung
    LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt (unsupported-character am 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
    baseVersioninteger · optional

    Die Fassung, auf der diese Aenderung aufsetzt. Ist inzwischen eine neuere entstanden, 409 template-version-conflict statt 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 templateId bekommt 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 Feld template.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 Feld sender.

    Ueber die Kopfzeile Accept waehlt der Aufrufer die Form: application/pdf liefert genau das Artefakt, das spaeter gedruckt wird; image/png dieselbe Seite gerastert, aus der PDF. Ohne Angabe kommt PDF. Die Seite ist fluechtig und wird nirgends gespeichert.

    values ist 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) und body-too-long, wenn sich der Ueberlauf genau einer mehrzeiligen Variable zuschreiben laesst, sonst an values. Passt die Seite nicht, kommt 422 und kein Bild.

    Fehler kommen wie ueberall als application/problem+json, siehe das Schema Problem: 400, 401, 403, 404 und 422. Der Vertrag fuehrt nur den Erfolgsfall, weil produces fuer alle Antworten einer Route gilt.

    Zugang

    Mit API-Schlüssel oder Sitzung aus der Anmeldung.

    Parameter

    idstring (uuid) · Pfad · Pflicht

    Anfrage-Rumpf

    application/json · Pflicht

    Alle Felder sind freiwillig.

    template ist ein ungespeicherter Entwurf, in derselben Form wie Text und Variablen im Rumpf von PUT /v1/templates/{id}. Ist er da, wird er statt der neuesten Fassung gesetzt und genauso geprueft; gespeichert wird nichts.

    sender ist 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.

    recipient ist 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
    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.

    WertBedeutung
    LINEein kurzer Wert ohne Zeilenumbruch, etwa Anrede, Gutscheincode oder Betrag. Ein Umbruch im Wert wird abgelehnt (unsupported-character am 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
    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"}
    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
    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

    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. templateId grenzt 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.

    WertBedeutungwer setzt ihn
    ACTIVEbedienbar: Fassung wechseln, Absender aendern, verschickendie Anlage
    ARCHIVEDstillgelegt, nimmt keinen Versandauftrag mehr ander Kunde selbst
    CANCELLEDvom Betreiber stillgelegtnur 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
    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. product ist die Weiche im Rumpf: v1 kennt LETTER_STANDARD, den Standardbrief.

    Eine Brief-Kampagne ist ein Absender und die Fassung einer Vorlage: templateId nennt die Vorlage, gedruckt wird deren neueste Fassung. Fehlt templateId, gilt die Standardvorlage des Kontos. Eine spaetere Fassung erreicht die Kampagne erst ueber PUT /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-Key ist 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 Kopfzeile Idempotent-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) und template-not-active (die Vorlage ist archiviert), beide am Feld templateId.

    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
    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
    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.template nennt Vorlage, Fassung und deren Inhalt, dazu newerVersionAvailable, 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

    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). Ohne templateId bleibt 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 Feld version: queued-item-not-printable und queued-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 (Feld templateId), 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 (Feld version) und campaign-not-active fuer 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: 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 · 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 Accept waehlt der Aufrufer die Form: application/pdf liefert genau das Artefakt, das spaeter gedruckt wird; image/png liefert dieselbe Seite gerastert. Das PNG entsteht aus der PDF und nicht daneben. Ohne Angabe kommt PDF.

    values ist 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) und body-too-long, wenn sich der Ueberlauf genau einer mehrzeiligen Variable zuschreiben laesst, sonst an values. 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 Schema Problem: 400, 401, 403, 404 (Kampagne fehlt, gehoert einem anderen Konto oder liegt in der anderen Umgebung) und 422. Der Vertrag fuehrt nur den Erfolgsfall, weil produces fuer 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 · Pflicht

    Alle Felder sind freiwillig.

    recipient ist 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"}
    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

    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 cursor aus next_cursor der 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, unitCredits der 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 als items.<i> mit dem Code item-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 Eintrag items.<i>.letter.values.<name> mit unsupported-character (ein Zeichen, das sich nicht drucken laesst, ein Zeilenumbruch in einer einzeiligen Variable) oder body-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-Key ist Pflicht: derselbe Schluessel mit demselben Rumpf ergibt denselben Auftrag und bucht kein zweites Mal; die Wiederholung traegt den Status des ersten Aufrufs und Idempotent-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 ShipmentRequestInput

    Die Zeilen eines Versandauftrags. Ihre Reihenfolge ist die position des mailItems, und auf sie beziehen sich die Feldpfade items.<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
    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"}

    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
  • 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 trotzdem shipments:write, weil die Antwort sagt, was die Annahme taete.

    Antwortet immer 200 mit dem Preis, auch wenn der Auftrag abgelehnt wuerde. rejections nennt dieselben Codes wie errors[] der Annahme, unbrauchbare Zeilen als items.<i>, Gruende nur an einzelnen Werten als items.<i>.letter.values.<name> wie bei der Annahme. Fehlendes Guthaben ist keine Ablehnung, nur sufficientFunds: false. balanceCredits steht nur fuer Sitzungen und Schluessel mit balance:read darin, sonst null.

    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 ShipmentRequestInput

    Die Zeilen eines Versandauftrags. Ihre Reihenfolge ist die position des mailItems, und auf sie beziehen sich die Feldpfade items.<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
    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"}

    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. index ist dieselbe Zahl wie items.<i> einer Ablehnung. Geblaettert wird mit cursor aus next_cursor.

    Nach Ablauf der Loeschfrist wird die Liste geleert; itemCount bleibt.

    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 QUEUED wartet. Ist er einem Stapel zugeteilt, ist er auf dem Weg zum Druck und laesst sich nicht mehr zurueckholen: 422 shipment-not-cancellable. Einzelne mailItems lassen sich nicht stornieren.

    In LIVE kommt der volle Betrag zurueck, sichtbar als refundedCredits und als SHIPMENT_REFUND im 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 als CREDIT_EXPIRY im 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 keinen Idempotency-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

    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
    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.

    balanceCredits zaehlt nur, was jetzt noch gilt. Ein Credit, dessen Ablauf erreicht ist, zaehlt nicht mehr mit, auch wenn sein Verfall im Kontoauszug erst etwas spaeter als CREDIT_EXPIRY erscheint.

    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 nach id. Zusammen ergeben ihre Reste balanceCredits aus GET /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