smartchat

Einen Newsletter senden

Du brauchst einen Schlüssel mit diesen Rechten: newsletters:write zum Vorbereiten, templates:submit, um die Vorlage an WhatsApp zu geben, newsletters:test zum Testen und newsletters:send zum Senden. Lies zuerst Sicher senden.

Ein Newsletter wird als WhatsApp-Vorlage gesendet, und WhatsApp muss die Vorlage genehmigen, bevor etwas gesendet wird. Die Reihenfolge ist also: Entwurf, Genehmigung, Vorschau, Test, Senden. Alle Antworten auf dieser Seite gehören zu einer Geschichte: dem Newsletter "Autumn menu".

#1. Den Entwurf anlegen

Der Text darf den Platzhalter {{first_name}} enthalten. Er wird durch den Vornamen jedes Kontakts ersetzt. Es ist der einzige Platzhalter, den ein Newsletter erlaubt. Der Text darf nicht mit einem Platzhalter beginnen oder enden.

curl -X POST "https://api.smartchat.marketing/v1/newsletters" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Autumn menu",
  "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week.",
  "audience": {
    "tags": [
      "vip"
    ]
  }
}'
import os
import uuid
import requests

response = requests.post(
    "https://api.smartchat.marketing/v1/newsletters",
    headers={
        "Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "title": "Autumn menu",
        "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week.",
        "audience": {
            "tags": [
                "vip",
            ],
        },
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/newsletters", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "title": "Autumn menu",
    "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week.",
    "audience": {
      "tags": [
        "vip"
      ]
    }
  }),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (201):

{
  "object": "newsletter",
  "id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "title": "Autumn menu",
  "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week.",
  "language": "en",
  "button": {
    "type": "url",
    "text": "See the menu",
    "url": "https://example.com/menu"
  },
  "audience": {
    "tags": [
      "vip"
    ],
    "mode": "any",
    "sources": []
  },
  "status": "draft",
  "template_id": "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
  "template_status": "draft",
  "ready_to_send": false,
  "not_ready_reason": "template_not_approved",
  "recipients": 412,
  "scheduled_at": null,
  "sent_at": null,
  "created_at": "2026-10-25T09:41:07Z",
  "updated_at": "2026-10-25T09:41:07Z"
}

Der Newsletter ist ein Entwurf. Er hat eine eigene Vorlage (template_id) und die Vorlage ist auch noch ein draft, deshalb ist ready_to_send gleich false und not_ready_reason gleich template_not_approved. Den Newsletter kannst du ändern (update_newsletter), bis er geplant ist.

#2. Die Vorlage genehmigen lassen

WhatsApp entscheidet, ob eine Vorlage genutzt werden darf. Du gibst sie mit create_template_submissions ab. Das braucht das Recht templates:submit und besteht aus zwei Aufrufen mit verschiedenen Idempotency-Key-Werten.

Erster Aufruf: eine Vorschau. Nichts wird eingereicht. Die Antwort zeigt, was passieren würde, und gibt eine plan_id, die 10 Minuten gilt.

curl -X POST "https://api.smartchat.marketing/v1/template-submissions" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "template_ids": [
    "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
  ]
}'
import os
import uuid
import requests

response = requests.post(
    "https://api.smartchat.marketing/v1/template-submissions",
    headers={
        "Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "template_ids": [
            "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
        ],
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/template-submissions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "template_ids": [
      "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
    ]
  }),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (200):

{
  "object": "template_submission_plan",
  "plan_id": "pln_9a8b7c6d5e4f43a2b1c0d9e8f7a6b5c4",
  "expires_at": "2026-10-25T09:52:00Z",
  "templates": [
    {
      "template_id": "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
      "name": "Autumn menu",
      "status": "draft",
      "outcome": "would_submit",
      "issues": [],
      "error_code": null
    }
  ],
  "submitted_at": null
}

Zweiter Aufruf: Sende dieselben template_ids mit der plan_id. Jetzt geht die Vorlage an WhatsApp.

curl -X POST "https://api.smartchat.marketing/v1/template-submissions" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "template_ids": [
    "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
  ],
  "plan_id": "pln_9a8b7c6d5e4f43a2b1c0d9e8f7a6b5c4"
}'
import os
import uuid
import requests

response = requests.post(
    "https://api.smartchat.marketing/v1/template-submissions",
    headers={
        "Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "template_ids": [
            "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
        ],
        "plan_id": "pln_9a8b7c6d5e4f43a2b1c0d9e8f7a6b5c4",
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/template-submissions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "template_ids": [
      "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234"
    ],
    "plan_id": "pln_9a8b7c6d5e4f43a2b1c0d9e8f7a6b5c4"
  }),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (200):

{
  "object": "template_submission",
  "plan_id": null,
  "expires_at": null,
  "templates": [
    {
      "template_id": "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
      "name": "Autumn menu",
      "status": "pending",
      "outcome": "submitted",
      "issues": [],
      "error_code": null
    }
  ],
  "submitted_at": "2026-10-25T09:42:10Z"
}

Die Vorlage ist pending. Lies den Newsletter ab und zu (get_newsletter), bis template_status den Wert approved und ready_to_send den Wert true hat. Lehnt WhatsApp die Vorlage ab, ist template_status gleich rejected; ändere den Text und reiche sie noch einmal ein.

curl "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY"
import os
import requests

response = requests.get(
    "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
    headers={"Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"]},
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
  },
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (200):

{
  "object": "newsletter",
  "id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "title": "Autumn menu",
  "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week.",
  "language": "en",
  "button": {
    "type": "url",
    "text": "See the menu",
    "url": "https://example.com/menu"
  },
  "audience": {
    "tags": [
      "vip"
    ],
    "mode": "any",
    "sources": []
  },
  "status": "draft",
  "template_id": "tpl_0f8c1a2e4b7d4c3e9a5b6d7e8f901234",
  "template_status": "approved",
  "ready_to_send": true,
  "not_ready_reason": null,
  "recipients": 412,
  "scheduled_at": null,
  "sent_at": null,
  "created_at": "2026-10-25T09:41:07Z",
  "updated_at": "2026-10-25T10:05:00Z"
}

#3. Die Vorschau ansehen

Die Vorschau liest und rechnet. Sie sendet nichts.

curl "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send-preview?when=now" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY"
import os
import requests

response = requests.get(
    "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send-preview",
    headers={"Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"]},
    params={
        "when": "now",
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send-preview?when=now", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
  },
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (200):

{
  "object": "newsletter_send_preview",
  "newsletter_id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "when": "now",
  "can_send": true,
  "blocked_by": [],
  "recipients": 412,
  "audience_total": 938,
  "excluded": {
    "opted_out": 12,
    "not_confirmed": 30,
    "suppressed": 2,
    "no_phone": 3,
    "outside_audience": 524
  },
  "estimated_days": 1,
  "daily_limit": 1000,
  "text": "Hi {{first_name}}, our autumn menu is here. Book a table for this week."
}

Prüfe die Zahl der Empfänger, die ausgeschlossenen Kontakte und den Beispieltext. Nur Kontakte mit bestätigtem Opt-in sind dabei. daily_limit ist das Tageslimit deiner WhatsApp-Nummer (wie vielen neuen Personen WhatsApp pro Tag schreiben lässt, oder null, wenn es keines gibt) und estimated_days ist die Zahl der Tage, die der Versand deshalb dauert. Hier passen die 412 Empfänger in einen Tag.

#4. Einen Test senden

Ein Test geht an die Telefonnummer, die du nennst. Er nutzt nur genehmigte Vorlagen und geht nie an einen Kontakt, der sich abgemeldet hat. Er braucht einen Idempotency-Key.

curl -X POST "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/test-send" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "to": "+4915112345678"
}'
import os
import uuid
import requests

response = requests.post(
    "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/test-send",
    headers={
        "Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "to": "+4915112345678",
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/test-send", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "to": "+4915112345678"
  }),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (202):

{
  "object": "newsletter_test_send",
  "newsletter_id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "to": "+4915112345678",
  "status": "handed_to_whatsapp"
}

#5. Senden

Das Senden ist ein Schritt. Es braucht das Recht newsletters:send und einen Idempotency-Key. Fällt das Netz aus, wiederhole den Aufruf mit demselben Key: Der Newsletter wird nicht doppelt gesendet.

curl -X POST "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send" \
  -H "Authorization: Bearer $SMARTCHAT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "when": "now"
}'
import os
import uuid
import requests

response = requests.post(
    "https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send",
    headers={
        "Authorization": "Bearer " + os.environ["SMARTCHAT_API_KEY"],
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json={
        "when": "now",
    },
)
response.raise_for_status()
print(response.json())
const response = await fetch("https://api.smartchat.marketing/v1/newsletters/nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b/send", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMARTCHAT_API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "when": "now"
  }),
});
if (!response.ok) throw new Error(await response.text());
console.log(await response.json());

Response (202):

{
  "object": "newsletter_send",
  "id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "newsletter_id": "nwl_3c9e1f7a5b2d4e8f9a0b1c2d3e4f5a6b",
  "status": "sending",
  "recipients": 412,
  "scheduled_at": null
}

Die Antwort ist 202: Der Newsletter steht in der Warteschlange. Prüfe den Fortschritt mit get_newsletter. Die Ereignisseite zeigt, welche Ereignisse es für Newsletter gibt und ob sie schon verfügbar sind.

#Wenn etwas schiefgeht

CodeBedeutung
template_not_approvedDie Vorlage ist noch nicht genehmigt. Geh zurück zu Schritt 2 und warte auf die Genehmigung.
audience_emptyDie Zielgruppe hat keine erreichbaren Kontakte.
newsletter_lockedDer Newsletter ist schon geplant oder gesendet.
idempotency_key_requiredDu hast den Header Idempotency-Key nicht gesendet.
plan_expiredDie plan_id aus Schritt 2 ist älter als 10 Minuten. Rufe die Vorschau noch einmal auf.

Um einen laufenden Newsletter anzuhalten oder abzubrechen, nutze control_newsletter.