Docs durchsuchen

Guides und API-Endpunkte durchsuchen

Referenz

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.

Verfügbar
GET

/v1/templates

Alle Templates des Kunden mit Art, Status, Herkunft und Parameter-Vertrag (name, label, type, required, fallback, example). Ein Portal, das ein fertiges Template anbietet, holt hier die Felder, die der Nutzer füllen soll — eine KI kann sie aus Bezeichnung und Beispiel vorausfüllen. Scope reporting.

Request · Next.js

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates`, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
    },
});
const data = await res.json();

Response 200

{
  "data": [
    {
      "id": "00000000-0000-4000-8000-0000000000f3",
      "name": "Einladung (Beyond)",
      "subject": "{{titel}}",
      "kind": "transaktional",
      "status": "active",
      "origin": "admin",
      "from": null,
      "reply_to": null,
      "params": [
        { "name": "titel", "label": "Überschrift", "type": "string", "required": true, "fallback": null, "example": "Dein Zugang zum Dashboard" },
        { "name": "link",  "label": "Einladungslink", "type": "url", "required": true, "fallback": null, "example": "https://example.com/einladung?token=BEISPIEL" }
      ],
      "created_at": "2026-09-02T11:00:00Z",
      "updated_at": "2026-09-03T09:12:00Z"
    }
  ],
  "request_id": "…"
}
POST

/v1/templates

Speichert den Stapel des Builders als eigenes Newsletter-Template (origin customer). Blöcke über block_id aus GET /v1/blocks, values wie bei der Vorschau — feste Werte, {{platzhalter}} darin werden je Empfänger beim Versandjob gefüllt. Kein Footer im Stapel: Der kommt aus dem Rahmen des Kunden. Werte müssen Parameter des Blocks sein. status active nur, wenn beim Kunden ein Newsletter-Footer hinterlegt ist. Scope full, idempotent.

Body-Parameter

NameTypPflichtBeschreibung
namestringerforderlichAnzeigename im Portal und Dashboard. z. B. Sommer-Newsletter
subjectstringerforderlichBetreff; {{platzhalter}} erlaubt. z. B. Hallo {{vorname}}, das Sommerprogramm ist da
blocksobject[]erforderlich[{ block_id, values }] in Reihenfolge. block_id aus GET /v1/blocks; values nur für Parameter des Blocks, zusammengesetzte als Objekt ({ url, alt }). z. B. [{"block_id":"…","values":{"titel":"Hallo {{vorname}}"}}]
statusenumoptionaldraft (Standard) oder active. z. B. draft

Request · Next.js

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      name: "Sommer-Newsletter",
      subject: "Hallo {{vorname}}, das Sommerprogramm ist da",
      blocks: [{"block_id":"…","values":{"titel":"Hallo {{vorname}}"}}],
      status: "draft",
    }),
});
const data = await res.json();

Response 200

{
  "data": {
    "id": "b33be79b-…",
    "name": "Sommer-Newsletter",
    "kind": "newsletter",
    "status": "draft",
    "origin": "customer",
    "params": [],
    "blocks": [ { "block_id": "0d384008-…", "block_slug": "beyond-hero", "values": { "titel": "Hallo {{vorname}}", "…": "…" } } ],
    "created_at": "2026-09-03T17:00:00Z"
  },
  "request_id": "…"
}

422 bei Footer im Stapel, unbekannten Werten oder einem Abmeldelink im Stapel; 403, wenn ein Block nicht freigeschaltet ist; 409 beim Aktivieren ohne Newsletter-Footer.

GET

/v1/templates/{id}

Wie die Liste, zusätzlich der Stapel (blocks mit values). Scope reporting.

Path-Parameter

NameTypPflichtBeschreibung
idstring (UUID)erforderlichDie Template-ID. z. B. b33be79b-90b1-44ca-bfae-5901cdc6713c

Request · Next.js

const id = "b33be79b-90b1-44ca-bfae-5901cdc6713c";

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates/${id}`, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
    },
});
const data = await res.json();

Response 200

{
  "data": { "id": "b33be79b-…", "name": "Sommer-Newsletter", "kind": "newsletter", "status": "active", "origin": "customer", "params": [], "blocks": [ "…" ] },
  "request_id": "…"
}
PUT

/v1/templates/{id}

Ändert Name, Betreff, Stapel oder Status eines aus dem Portal gespeicherten Templates — alle Felder optional. Templates aus dem Dashboard (origin admin) sind über die API nur lesbar (403). Scope full.

Path-Parameter

NameTypPflichtBeschreibung
idstring (UUID)erforderlichDie Template-ID. z. B. b33be79b-90b1-44ca-bfae-5901cdc6713c

Body-Parameter

NameTypPflichtBeschreibung
namestringoptionalNeuer Name. z. B. Sommer-Newsletter v2
subjectstringoptionalNeuer Betreff. z. B. Das Sommerprogramm ist da
blocksobject[]optionalDer ganze Stapel neu, wie beim Anlegen. z. B. [{"block_id":"…","values":{}}]
statusenumoptionaldraft oder active. z. B. active

Request · Next.js

const id = "b33be79b-90b1-44ca-bfae-5901cdc6713c";

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates/${id}`, {
    method: "PUT",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      name: "Sommer-Newsletter v2",
      subject: "Das Sommerprogramm ist da",
      blocks: [{"block_id":"…","values":{}}],
      status: "active",
    }),
});
const data = await res.json();

Response 200

{
  "data": { "id": "b33be79b-…", "status": "active", "…": "…" },
  "request_id": "…"
}
DELETE

/v1/templates/{id}

Löscht ein aus dem Portal gespeichertes Template. Laufende Versandjobs behalten ihre gerenderte Mail. Dashboard-Templates: 403. Scope full.

Path-Parameter

NameTypPflichtBeschreibung
idstring (UUID)erforderlichDie Template-ID. z. B. b33be79b-90b1-44ca-bfae-5901cdc6713c

Request · Next.js

const id = "b33be79b-90b1-44ca-bfae-5901cdc6713c";

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates/${id}`, {
    method: "DELETE",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
    },
});
const data = await res.json();

Response 200

{ "data": { "deleted": true }, "request_id": "…" }
POST

/v1/templates/{id}/send

Versendet die transaktionale Mail des Templates {id} — es muss dem aufrufenden Kunden gehören und die Art transaktional haben; Newsletter gehen als Versandjob raus. Der Client übergibt einen einzelnen Empfänger und die Werte der Template-Parameter. Unbekannte Parameter werden abgelehnt; Pflicht-Parameter sind erzwungen. Pflicht-Parameter dürfen auch aus den Marken-Parametern des Kunden (Logo, Impressum …) gedeckt werden. Scope full, idempotent.

Path-Parameter

NameTypPflichtBeschreibung
idstring (UUID)erforderlichID des Templates (im Kunden-Detail unter Templates kopierbar). z. B. 00000000-0000-4000-8000-0000000000f3

Body-Parameter

NameTypPflichtBeschreibung
tostring (E-Mail)erforderlichEmpfängeradresse. Gespeichert wird nur ihr Hash. z. B. mira@example.com
paramsobjectoptionalWerte der Template-Parameter (der komplette Personalisierungs-Vertrag des Templates). {{platzhalter}} in festen Texten werden aus denselben Werten gefüllt. z. B. {"titel":"Dein Zugang zum Dashboard","name":"Mira","link":"https://kunde.de/einladung?token=…"}
fromobjectoptionalAbsender-Ausnahme { email, name }. Standard ist die No-Reply-Adresse des Kunden; der Teil vor dem @ ist frei, die Domain muss beim Kunden hinterlegt sein. z. B. {"email":"lena.berger@kunde.de","name":"Lena Berger"}
reply_tostring (E-Mail)optionalAntwort-Adresse; leer = wie Absender. z. B. support@kunde.de

Request · Next.js

const id = "00000000-0000-4000-8000-0000000000f3";

const res = await fetch(`https://api.newsletterkit.ventureon.io/v1/templates/${id}/send`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.NEWSLETTERKIT_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      to: "mira@example.com",
      params: {"titel":"Dein Zugang zum Dashboard","name":"Mira","link":"https://kunde.de/einladung?token=…"},
      from: {"email":"lena.berger@kunde.de","name":"Lena Berger"},
      reply_to: "support@kunde.de",
    }),
});
const data = await res.json();

Response 200

{
  "data": {
    "message_id": "b7e3…",
    "status": "accepted",
    "mode": "live",
    "template_id": "00000000-0000-4000-8000-0000000000f3"
  },
  "request_id": "…"
}

Synchron: Die Antwort kommt, wenn Postmark geantwortet hat. status accepted = angenommen und gezählt; suppressed = Empfänger bei Postmark gesperrt; invalid = Adresse ungültig. Idempotent über Idempotency-Key (kein doppelter Versand bei Retries; gleicher Key mit anderem Body → 409; antwortet Postmark nicht, bleibt der Key belegt und die Wiederholung bekommt dieselbe 500-Antwort samt message_id statt einer zweiten Mail). Nur aktive Templates des eigenen Kunden (sonst 409/404); Newsletter-Templates → 422; Monatslimit erreicht → 429 quota_exceeded; Versand nicht freigeschaltet → 403. Im Sandbox-Modus nimmt Postmark an, stellt nichts zu und zählt nichts.