# NewsletterKit API > Interne Middleware zwischen Kundenplattformen und Postmark. Verschickt wird > immer ein Template — im Dashboard gebaut oder aus dem Builder des Portals > gespeichert. Transaktional einzeln und synchron, Newsletter als Versandjob. > Jede Mail hat eine ID; Auswertung und Sperren liegen bei NewsletterKit, das > Portal fragt ab. Die Einwilligung liegt im CRM des Kunden. Der API-Key > bestimmt den Kunden; der Postmark-Server-Token verlässt nie den Server. Base URL: https://api.newsletterkit.ventureon.io/v1 Docs: https://docs.newsletterkit.ventureon.io Auth: Authorization: Bearer (Scopes: full | reporting) Version: v1 ## Guides - Einführung (https://docs.newsletterkit.ventureon.io/docs#einfuehrung) - Quickstart (https://docs.newsletterkit.ventureon.io/docs#quickstart) - Auth & Header (https://docs.newsletterkit.ventureon.io/docs#auth) - Konventionen (https://docs.newsletterkit.ventureon.io/docs#konventionen) - Fehler (https://docs.newsletterkit.ventureon.io/docs#fehler) - Zugang (https://docs.newsletterkit.ventureon.io/docs#zugang) - Webhooks (https://docs.newsletterkit.ventureon.io/docs#webhooks) - Einwilligung & Sperren (https://docs.newsletterkit.ventureon.io/docs#einwilligung) - Versionierung (https://docs.newsletterkit.ventureon.io/docs#versionierung) ## Integrationspfad — die fünf Abläufe ### Transaktionale Mail Ein fertiges Template des Kunden, ein Empfänger, sofort. Die Antwort trägt unsere Mail-ID — sie gehört an die Bestellung oder den Nutzer, damit das Portal später den Status nachfragen kann. 1. GET /v1/templates — Template der Art transaktional wählen, params lesen (name, label, type, required, example). 2. POST /v1/templates/{id}/send mit to und params; Idempotency-Key gegen doppelten Versand bei Retries. 3. Bei Bedarf GET /v1/messages/{id}: zugestellt oder gebounct, mit Grund. ### Newsletter aus fertigem Template Das Portal zeigt die Newsletter-Templates des Kunden, der Nutzer füllt die Parameter (eine KI kann sie aus Bezeichnung und Beispiel vorausfüllen), wählt Empfänger aus dem CRM und schickt ab. Verschickt wird als Job. 1. GET /v1/templates — Art newsletter, params lesen. 2. POST /v1/render/preview zum Prüfen — oder GET /v1/templates/{id} und die Blöcke mit den Werten rendern lassen. 3. POST /v1/send-jobs mit template_id, params, optional scheduled_at. 4. POST /v1/send-jobs/{id}/recipients — Kontakte aus dem CRM, gefiltert nach Einwilligung UND keiner Sperre, in Blöcken bis 5.000, je Empfänger data für {{platzhalter}}. 5. POST /v1/send-jobs/{id}/start, danach GET /v1/send-jobs/{id} alle paar Sekunden, bis status completed ist. ### Newsletter aus dem Builder Der Nutzer stapelt Blöcke im Canvas des Portals und füllt sie mit Inhalt. Das Portal rendert nie selbst: Jede Vorschau und jede Kachel kommt fertig aus NewsletterKit, mit den Design-Regeln des Kunden dieses Moments. Am Ende wird der Stapel als eigenes Template gespeichert und wie ein fertiges verschickt. 1. GET /v1/blocks — Blöcke mit Parameter-Schema und tile_url; Kacheln über GET /v1/blocks/{id}/tile in iframes mit srcdoc. 2. Bei jeder Änderung (entprellt, ~300 ms): POST /v1/render/preview mit dem Stapel — HTML in ein iframe. 3. Bilder: POST /v1/assets → PUT an upload.url → POST /v1/assets/{id}/complete; die url in Bild-Parameter setzen. 4. POST /v1/templates speichert den Stapel als Template (Art newsletter; kein Footer im Stapel, der kommt aus dem Rahmen des Kunden). 5. Weiter wie beim fertigen Template: Job anlegen, Empfänger anhängen, starten. ### Sperren ins CRM Die Einwilligung liegt im CRM, die Sperre bei Postmark. NewsletterKit spiegelt die Sperren; das CRM holt sie ab und leitet daraus ab, wer eine Mail bekommen darf. Ein Cron alle paar Minuten reicht — beim Versand sperrt Postmark ohnehin zuletzt. 1. Cron: GET /v1/suppressions?since=, Seiten über paging.after; je Eintrag das Sperrfeld des Kontakts setzen (active=true) oder aufheben (active=false). 2. Einzelfall: POST /v1/suppressions/lookup mit bis zu 500 Adressen. 3. Nach neuem Double-Opt-in: POST /v1/suppressions/reactivate — 409 bei Spam-Beschwerde, die bleibt. ### Auswertungsseite Die Auswertung liegt bei NewsletterKit, das Portal rendert nur: drei Aufrufe, fertige Zahlen. Öffnungen und Klicks laufen noch Tage nach dem Versand ein. 1. GET /v1/send-jobs/{id} — Zähler je Ergebnis, stats (Summen) und timeline (je Stunde). 2. GET /v1/send-jobs/{id}/messages?status=bounced — wer nicht erreicht wurde, über Mail-IDs. 3. GET /v1/send-jobs/{id}/links — Klicks je Link. ## Einwilligung & Sperren Regeln für die Einbindung in ein Kundensystem (CRM, Newsletter-Builder): - Die Einwilligung liegt im Kundensystem. Die Werbeeinwilligung ist ein dokumentierter Akt: Double-Opt-in mit Zeitpunkt, Text und Herkunft. NewsletterKit und Postmark kennen sie nicht und fragen nie danach. Das Feld gehört dem Kundensystem, und nur das Kundensystem schreibt es. - Die Sperre liegt bei Postmark. Abmeldung, Hard Bounce und Spam-Beschwerde entstehen bei Postmark und werden dort durchgesetzt: Ein gesperrter Empfänger wird je Nachricht abgewiesen, egal was das Kundensystem über ihn glaubt. NewsletterKit spiegelt Sperren und gibt sie weiter; übersteuern kann sie niemand. - „Darf E-Mails empfangen“ ist eine Ableitung, kein Feld. Einwilligung vorhanden UND keine aktive Sperre. Im CRM sind das zwei getrennte Felder: marketing_consent schreibt nur das Kundensystem, email_suppressed schreibt nur der Abgleich mit NewsletterKit. Wer beide zu einem Boolean verschmilzt, verliert die Wiederkehr: Ein Abgemeldeter, der sich neu einträgt, hätte wieder Einwilligung, bliebe aber bei Postmark gesperrt. - Abgleich durch Abholen. Das Kundensystem ruft regelmäßig GET /v1/suppressions?since= und schreibt die Antwort in sein Sperrfeld — gesetzte wie aufgehobene Sperren. Ein Cron alle paar Minuten reicht: Beim Versand sperrt Postmark ohnehin zuletzt, ein verspäteter Abgleich kostet höchstens eine abgewiesene Nachricht. - Wiederkehr nur nach neuem Double-Opt-in. Wer sich abgemeldet hat und später neu einträgt, bleibt bei Postmark gesperrt, bis das Kundensystem POST /v1/suppressions/reactivate ruft. Das geschieht nach der Bestätigung, nie beim Setzen eines Hakens. Nach einer Spam-Beschwerde gibt es keine Reaktivierung; die Adresse bleibt dauerhaft gesperrt. - Der Abmeldelink kommt von Postmark. Newsletter enthalten den Abmeldelink über den Footer des Kunden; die Adresse dahinter setzt Postmark je Empfänger ein, und die Abmeldung führt auf Postmarks Abmeldeseite. Der Aufrufer übergibt keinen unsubscribe_url. Eine Abmeldung gilt für alle Newsletter dieses Kunden — Listen und Segmente kennt Postmark nicht. - Transaktionale Mails bleiben erreichbar. Sperren gelten je Stream. Ein abgemeldeter Empfänger bekommt weiterhin transaktionale Mails wie Double-Opt-in, Bestellbestätigung oder Passwort-Reset; gesperrt sind nur Newsletter. - Listen und Segmente gehören dem Kundensystem. NewsletterKit kennt keine Listen. Welche Kontakte einen Newsletter bekommen, entscheidet das Kundensystem beim Zusammenstellen der Empfänger — gefiltert nach Einwilligung und Sperre. Adressen reisen nur mit dem Versandjob und werden nach dessen Abschluss gelöscht; es bleibt der Hash und die Mail-ID. ## Endpoints ### System Verbindung & Health. Der einfachste Endpunkt — prüft API-Key und Erreichbarkeit. - GET /v1/health — Authentifizierter Health-Check ### Blöcke Liefert die für den Kunden freigeschalteten MJML-Blöcke samt Parameter-Schema. Welche Blöcke ein Template verwenden darf, kommt aus dieser Liste — referenziert wird ein Block immer über seine unveränderliche id (UUID), nicht über den slug. Blöcke selbst werden ausschließlich im Admin gepflegt. - GET /v1/blocks — Freigeschaltete Blöcke + Param-Schema - GET /v1/blocks/{id}/tile — Kachel eines Blocks (HTML im Kundendesign) ### Design-Regeln Liefert das vollständige, aufgelöste Design-Token-Set des Kunden (Flächen-/Text-/Akzent-/Status-Farben, Typografie, Abstände, Komponenten). Diese Tokens werden beim Render in jedes MJML-Dokument injiziert und erzwingen ein konsistentes Erscheinungsbild über alle Newsletter hinweg. Das vollständige Regelwerk (welches Token wofür) steht unter /docs/design-rules. - GET /v1/design-rules — Design-Tokens des Kunden ### Rendering Rendert einen Block-Stapel serverseitig zu MJML + kompiliertem, responsivem HTML — die Live-Vorschau des Builders im Kundenportal, zustandslos und ohne etwas zu versenden. MJML-Templates unterstützen bedingte Abschnitte {{#param}}…{{/param}}, die nur bei nicht-leerem Wert rendern (optionale Elemente wie Logo oder AGB-Link verschwinden sonst). - POST /v1/render/preview — Live-Vorschau (MJML + HTML) ### Templates Verschickt wird immer ein Template. Es gehört dem Kunden — im Dashboard gebaut (origin admin, mit Parameter-Vertrag) oder aus dem Builder des Kundenportals gespeichert (origin customer, feste Werte, {{platzhalter}} je Empfänger). Struktur und Blöcke liegen serverseitig fest, das Aussehen kommt aus den Design-Regeln des Kunden, der Footer aus seinem Rahmen. - GET /v1/templates — Templates des Kunden mit Vertrag - POST /v1/templates — Stapel aus dem Builder als Template speichern - GET /v1/templates/{id} — Ein Template mit Stapel - PUT /v1/templates/{id} — Kunden-Template ändern - DELETE /v1/templates/{id} — Kunden-Template löschen - POST /v1/templates/{id}/send — Mail aus Template versenden ### Verbrauch Zeigt die versendeten Mengen: laufender Monat, Hochrechnung, Vormonate. Keine Beträge — abgerechnet wird nach Staffel in Stripe. - GET /v1/usage — Versandmengen ### Bilder Bilder für Newsletter: Das Portal lädt sie über NewsletterKit hoch und bekommt eine öffentliche, unveränderliche https-Adresse zurück — optimiert für Mail-Clients (höchstens 1360 px breit, JPEG oder PNG, unter 400 KB, ohne Metadaten). Zwei Schritte, weil ein Aufruf höchstens 4,5 MB annimmt: anmelden, Datei an die signierte Adresse schicken, abschließen. - POST /v1/assets — Bild anmelden, Upload-Adresse bekommen - POST /v1/assets/{id}/complete — Upload abschließen: optimieren, veröffentlichen - GET /v1/assets — Fertige Bilder des Kunden - GET /v1/assets/{id} — Ein Bild - DELETE /v1/assets/{id} — Bild löschen ### Versandjobs Ein Newsletter geht an viele Empfänger und wird als Versandjob verschickt: anlegen (Template, Parameter, Absender, optionaler Startzeitpunkt), Empfänger in Blöcken anhängen, starten, abfragen. Ein Worker rendert einmal, schickt Batches an Postmark und hält je Empfänger das Ergebnis fest. Die Empfängerliste baut das Kundensystem aus seinem CRM — gefiltert nach Einwilligung und Sperre. - POST /v1/send-jobs — Versandjob anlegen - POST /v1/send-jobs/{id}/recipients — Empfänger anhängen (bis 5.000) - POST /v1/send-jobs/{id}/start — Job starten - POST /v1/send-jobs/{id}/cancel — Job abbrechen - GET /v1/send-jobs/{id} — Status, Zähler und Auswertung - GET /v1/send-jobs/{id}/messages — Mails eines Jobs nach Status - GET /v1/send-jobs/{id}/links — Klicks je Link - GET /v1/send-jobs — Jobs des Kunden ### Mails Der Status einer einzelnen Mail. Jede Mail bekommt beim Versand eine ID von uns; das Portal schreibt sie an seine Bestellung oder seinen Kontakt und fragt hier nach — zugestellt, geöffnet, gebounct mit Grund, gesperrt. Die Adresse steht nirgends in der Antwort. - GET /v1/messages/{id} — Status einer Mail als Verlauf ### Sperren Der Sperrspiegel: Abmeldung, Hard Bounce und Spam-Beschwerde entstehen bei Postmark und werden dort je Nachricht durchgesetzt. Hier holt das Kundensystem die Änderungen ab, prüft Adressen und hebt Sperren nach neuem Double-Opt-in auf. Die Einwilligung selbst liegt im CRM des Kunden — „darf E-Mails empfangen“ ist die Ableitung aus beidem. - GET /v1/suppressions — Sperränderungen seit Zeitpunkt - POST /v1/suppressions/lookup — Adressen prüfen - POST /v1/suppressions/reactivate — Sperre aufheben ### Webhooks (geplant) Zustellung von Ereignissen ans Kundenportal — geplant. Heute holt das Portal Job-Status (GET /v1/send-jobs/{id}), Mail-Status (GET /v1/messages/{id}) und Sperren (GET /v1/suppressions) ab; das reicht für Builder, Versand und Auswertung. Die Zustellung kommt später als Zusatz auf dieselben Daten: job.completed, message.bounced, suppression.changed. Die Registrierung einer URL ist schon möglich, die Zustellung noch nicht. - POST /v1/webhooks — Webhook-URL registrieren (Zustellung folgt) [geplant] - POST /api/postmark/webhook — Postmark-Events empfangen (intern)