NetSendo REST-API-Referenz
Alle Endpunkte der öffentlichen API mit Authentifizierung, Scopes, Rate Limits, Fehlern und Beispielen.
Geschrieben für NetSendo 2.7.0 und mit dem Quellcode abgeglichen (Routen, Controller und das API-Schlüssel-Modell).
Überblick
Die API ist Teil jeder NetSendo-Installation, bei SILVER wie bei GOLD. Sie läuft auf deinem eigenen Server unter https://your-domain.com/api/v1, spricht JSON und arbeitet mit dem Konto, dem der API-Schlüssel gehört. Der MCP-Server und der n8n-Node nutzen dieselben Endpunkte. Die wenigen Aufrufe für GOLD-Funktionen, etwa A/B-Tests, antworten ohne aktive GOLD-Lizenz mit 402.
Sende bei jeder Anfrage Authorization: Bearer mit deinem Schlüssel und Accept: application/json, damit Validierungsfehler als JSON zurückkommen, bei Anfragen mit Body außerdem Content-Type: application/json.
Schlüssel prüfen
GET /api/v1/account liefert das Konto hinter dem Schlüssel und die NetSendo-Version. Integrationen nutzen den Endpunkt für den Verbindungstest.
curl https://your-domain.com/api/v1/account \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Accept: application/json"
# 200 OK
{
"data": {
"id": 1,
"name": "Anna Admin",
"email": "admin@example.com",
"version": "2.7.0"
}
}Authentifizierung und API-Schlüssel
Schlüssel erstellst du im NetSendo-Panel unter Einstellungen → API-Schlüssel. Gib jedem Schlüssel einen Namen, wähle seine Scopes und bei Bedarf ein Ablaufdatum. Der Schlüssel wird nur einmal angezeigt, beim Erstellen; NetSendo speichert nur seinen SHA-256-Hash und hält fest, wann er zuletzt verwendet wurde.
Schlüssel bestehen aus ns_live_, gefolgt von 32 zufälligen Zeichen. Übergib den Schlüssel im Header Authorization als Bearer-Token. Schlüssel im Query-String werden nicht akzeptiert.
Authorization: Bearer ns_live_YOUR_KEYAktiviere beim Schlüssel die Option MCP-Schlüssel, damit der integrierte MCP-Verbindungstest ihn verwenden kann. Wie du KI-Assistenten anbindest, steht in der Dokumentation zum MCP-Server.
Wenn die Authentifizierung fehlschlägt
Die API antwortet mit 401 und einer dieser Meldungen:
Missing or invalid Authorization header. Use: Bearer <api_key>Invalid API key format. Key should start with ns_live_Invalid API keyAPI key has expired
Scopes
Jeder Schlüssel hat eine Reihe von Scopes. Ein Endpunkt, der einen Scope verlangt, den der Schlüssel nicht hat, antwortet mit 403 Forbidden.
| Scope | Erlaubt |
|---|---|
| subscribers:read | Sperrliste lesen, Listenmitglieder direkt in der Antwort exportieren, Aktivitätsverlauf eines Abonnenten lesen |
| subscribers:write | Abonnenten anlegen, ändern und löschen, Massenanlage, Tags eines Abonnenten ersetzen, Adressen zur Sperrliste hinzufügen und daraus entfernen |
| lists:read | Hygieneberichte und Adressprüfung, Importvorschau, Aktivität und Engagement einer Liste, Versandplan, Listenvorgaben, Formulare, System-E-Mails und Systemseiten |
| lists:write | Listen anlegen, ändern und löschen; Import; Bereinigung und Deduplizierung; Massenänderungen der Mitgliedschaft; Tags und benutzerdefinierte Felder; Versandplan und Listenvorgaben; Formulare; System-E-Mails und -Seiten |
| tags:read | Auswählbar; in 2.7.0 verlangt ihn kein Endpunkt (zum Lesen von Tags reicht ein gültiger Schlüssel) |
| notifications:write | Benachrichtigungen im Benachrichtigungscenter des Kontoinhabers anlegen |
| webhooks:read | Auswählbar; in 2.7.0 verlangt ihn kein Endpunkt (zum Lesen von Webhooks reicht ein gültiger Schlüssel) |
| webhooks:write | Webhooks anlegen, ändern, löschen und testen sowie ihr Signatur-Secret neu erzeugen |
| email:read | Status der über die API gesendeten E-Mails, Liste der Absender-Postfächer |
| email:write | Einzel- und Massen-E-Mails senden |
| sms:read | Status der über die API gesendeten SMS, Liste der SMS-Anbieter |
| sms:write | Einzel- und Massen-SMS senden |
| messages:read | Kampagnenvorschau und Empfängerzahl, E-Mail-Vorlagen, Vorlagenkategorien und gespeicherte Blöcke |
| messages:write | Kampagnen anlegen, ändern, löschen, planen, senden, testen und duplizieren; A/B-Tests; Vorlagen und gespeicherte Blöcke |
| funnels:read | Automatisierungsregeln, ihre Optionen und Protokolle |
| funnels:write | Funnels und ihre Schritte anlegen, ändern, löschen, aktivieren und pausieren, Abonnenten aufnehmen; Automatisierungsregeln anlegen und ändern |
- Ein Schreib-Scope umfasst den Lese-Scope derselben Ressource: Ein Schlüssel mit
lists:writekann auch Endpunkte aufrufen, dielists:readverlangen. - Ein Schlüssel, bei dessen Erstellung kein Scope ausgewählt wurde, erhält alle 16 Scopes.
- Endpunkte, die in den Tabellen unten mit jeder gültige Schlüssel markiert sind, prüfen nur, ob der Schlüssel gültig und nicht abgelaufen ist. Dazu gehört das Auflisten und Lesen von Abonnenten, Listen, Tags, benutzerdefinierten Feldern, Kampagnen, Funnels, A/B-Tests und Webhooks. Jeder Endpunkt liefert nur die Daten des Kontos, dem der Schlüssel gehört.
Rate Limits
Die API erlaubt 3.000 Anfragen pro Minute und API-Schlüssel. Routen ohne Schlüssel (die Endpunkte für die Listenanmeldung und der signierte Export-Download) werden pro IP-Adresse mit demselben Limit gezählt.
Antworten enthalten X-RateLimit-Limit und X-RateLimit-Remaining. Über dem Limit antwortet die API mit 429 Too Many Requests und dem Header Retry-After in Sekunden.
Nutze für große Aufgaben die Batch-Endpunkte statt vieler Einzelaufrufe: bis zu 1.000 Abonnenten pro POST /subscribers/batch, 5.000 Zeilen pro Import und 5.000 Kontakte pro Mitgliedschaftsoperation.
Fehler
Fehler sind JSON-Objekte mit einem kurzen Label error und einer lesbaren message:
{
"error": "Forbidden",
"message": "API key does not have subscribers:write permission"
}Validierungsfehler nutzen das Standardformat von Laravel: eine message und ein Objekt errors mit einem Array von Meldungen pro Feld. Sende Accept: application/json; ohne diesen Header kann eine fehlgeschlagene Validierung mit einer Weiterleitung statt mit JSON antworten.
{
"message": "The email field must be a valid email address.",
"errors": {
"email": ["The email field must be a valid email address."]
}
}Seit NetSendo 2.4.0 antworten Aufrufe für GOLD-Funktionen ohne aktive GOLD-Lizenz (kein Schlüssel, SILVER oder abgelaufenes GOLD) mit 402 Payment Required. Die Antwort nennt die abgelehnte Funktion; message ist in der Standardsprache der Instanz (APP_LOCALE):
{
"error": "Payment Required",
"code": "gold_required",
"message": "“A/B tests” requires the GOLD licence. Upgrade on the Licence page to use it.",
"feature": "ab_tests",
"required_plan": "GOLD",
"upgrade_url": "https://your-domain.com/license"
}| Status | Bedeutung |
|---|---|
| 200 | Erfolg |
| 201 | Angelegt |
| 202 | Angenommen und eingereiht (E-Mails, SMS, CSV-Export) |
| 401 | API-Schlüssel fehlt, ist falsch formatiert, unbekannt oder abgelaufen |
| 402 | Der Aufruf nutzt eine GOLD-Funktion, und die Installation hat keine aktive GOLD-Lizenz |
| 403 | Dem Schlüssel fehlt der Scope, den der Endpunkt verlangt |
| 404 | Die Ressource existiert in diesem Konto nicht |
| 409 | Konflikt, etwa beim Löschen einer Liste mit Mitgliedern ohne confirm=1 oder beim Starten eines Funnels oder A/B-Tests im falschen Zustand |
| 422 | Validierung fehlgeschlagen oder Ressource nicht bereit (Kampagne ohne Listen, Postfach oder Inhalt) |
| 429 | Rate Limit überschritten |
| 500 | Serverfehler; Details stehen im Log der Instanz |
Pagination
Endpunkte, die Sammlungen zurückgeben, liefern standardmäßig Seiten mit 25 Einträgen (Tags: 50). Die Größe änderst du mit per_page, die Seite mit page. Die Antwort enthält die Einträge in data, Seitenlinks in links und Zähler wie current_page, per_page und total in meta. Der direkte Listenexport paginiert stattdessen mit einem Cursor: Übergib limit (höchstens 5.000) und, solange has_more true ist, den zurückgegebenen next_cursor.
Endpunkte
Alle Pfade unten sind relativ zu deiner Instanz, zum Beispiel https://your-domain.com/api/v1/subscribers. Ersetze die Teile in geschweiften Klammern durch IDs aus deinem Konto. Mit GOLD markierte Zeilen brauchen eine aktive GOLD-Lizenz und antworten ohne sie mit 402; die Beschreibungen der Gruppen nennen die Aufrufe, die GOLD nur für bestimmte Werte brauchen.
- Konto und Verbindungstest
- Abonnenten
- Kontaktlisten
- Import und Export
- Listenhygiene
- Listenmitgliedschaft (Massenaktionen)
- Aktivität und Engagement
- Sperrliste
- Tags und benutzerdefinierte Felder
- E-Mail-Versand
- SMS-Versand
- Kampagnen (messages)
- A/B-Tests
- Funnels
- Automatisierungsregeln
- Webhooks
- Vorlagen und gespeicherte Blöcke
- System-E-Mails und Systemseiten
- Anmeldeformulare
- Benachrichtigungen
- Hilfs-Endpunkte für Integrationen
- NetSendo Brain
- Endpunkte für die Listenanmeldung
Konto und Verbindungstest
Ermittle das Konto hinter einem Schlüssel. /api/mcp/test ist der Verbindungstest, den MCP-Clients verwenden.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/account | jeder gültige Schlüssel |
| GET | /api/mcp/test | jeder gültige Schlüssel |
Abonnenten
Kontakte anlegen, lesen, ändern und löschen. POST /subscribers verlangt contact_list_id sowie email für eine E-Mail-Liste oder phone für eine SMS-Liste; optionale Felder sind first_name, last_name, status, source, tags (Tag-IDs), custom_fields, ip_address, user_agent und device. Existiert die Adresse bereits, wird sie der Liste hinzugefügt oder reaktiviert statt dupliziert. Filtere GET /subscribers mit contact_list_id, status, email (Teilübereinstimmung), tag_id, sort_by und sort_order. POST /subscribers/{id}/tags ersetzt alle Tags des Abonnenten. Gelöscht wird per Soft Delete.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/subscribers | jeder gültige Schlüssel |
| POST | /api/v1/subscribers | subscribers:write |
| POST | /api/v1/subscribers/batch | subscribers:write |
| GET | /api/v1/subscribers/{id} | jeder gültige Schlüssel |
| GET | /api/v1/subscribers/by-email/{email} | jeder gültige Schlüssel |
| PUT, PATCH | /api/v1/subscribers/{id} | subscribers:write |
| DELETE | /api/v1/subscribers/{id} | subscribers:write |
| POST | /api/v1/subscribers/{id}/tags | subscribers:write |
| GET | /api/v1/subscribers/{id}/activity | subscribers:read |
Kontaktlisten
Verwalte E-Mail- und SMS-Listen. PUT führt Einstellungen zusammen: Felder, die du weglässt, bleiben unverändert. Zu den Einstellungen gehören double_opt_in, default_mailbox_id, default_sms_provider_id, max_subscribers, resubscription_behavior, signups_blocked, webhook_url und webhook_events. Das Löschen einer Liste mit Mitgliedern antwortet mit 409, bis du confirm=1 übergibst; die Abonnenten selbst bleiben erhalten. /stats liefert Mitglieder nach Status, Engagement, Wachstum über 30 Tage und die Einstellungen, die den Versand beeinflussen.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/lists | jeder gültige Schlüssel |
| POST | /api/v1/lists | lists:write |
| GET | /api/v1/lists/{id} | jeder gültige Schlüssel |
| PUT, PATCH | /api/v1/lists/{id} | lists:write |
| DELETE | /api/v1/lists/{id} | lists:write |
| GET | /api/v1/lists/{id}/stats | jeder gültige Schlüssel |
| GET | /api/v1/lists/{id}/subscribers | jeder gültige Schlüssel |
| GET | /api/v1/lists/{id}/cron-settings | lists:read |
| PUT | /api/v1/lists/{id}/cron-settings | lists:write |
| GET | /api/v1/settings/list-defaults | lists:read |
| PUT | /api/v1/settings/list-defaults | lists:write |
Import und Export
Importiere CSV, TSV, JSON oder eine einfache Adressliste (bis zu 5.000 Zeilen pro Anfrage) mit Spaltenzuordnung und Sicherheitsoptionen, etwa um ungültige, Wegwerf-, gesperrte oder Rollenadressen zu überspringen und Tippfehler in Domains zu korrigieren. Prüfe vorher die Vorschau mit /import/preview. GET /export liefert Mitglieder direkt als JSON, CSV oder NDJSON mit Cursor-Pagination; POST /export reiht einen vollständigen CSV-Export ein und sendet dem Kontoinhaber einen Download-Link.
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/import/preview | lists:read |
| POST | /api/v1/lists/{id}/import | lists:write |
| GET | /api/v1/lists/{id}/export | subscribers:read |
| GET | /api/v1/lists/{id}/export/fields | jeder gültige Schlüssel |
| POST | /api/v1/lists/{id}/export | jeder gültige Schlüssel |
| GET | /api/v1/exports/download | keiner (signierte URL) |
Listenhygiene
GET /hygiene bewertet eine Liste von 0 bis 100 und zählt Problemkategorien wie ungültige Syntax, Tippfehler-Domains, Wegwerf-Domains, Rollenadressen, Duplikate, Hard Bounces, nie aktive und ruhende Kontakte. clean meldet ausgewählte Kategorien ab, entfernt sie von der Liste, versieht sie mit Tags, löscht oder sperrt sie; dedupe führt Kontakte zusammen, die zum selben Postfach führen; verify prüft Syntax und MX-Einträge. clean und dedupe laufen standardmäßig mit dry_run=true, und destruktive Aktionen verlangen confirm=true.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/lists/hygiene-options | jeder gültige Schlüssel |
| GET | /api/v1/lists/{id}/hygiene | lists:read |
| POST | /api/v1/lists/{id}/hygiene/clean | lists:write |
| POST | /api/v1/lists/{id}/hygiene/dedupe | lists:write |
| POST | /api/v1/lists/{id}/hygiene/verify | lists:read |
Listenmitgliedschaft (Massenaktionen)
Füge bestehende Kontakte einer Liste hinzu, entferne sie, ändere ihren Status, verschiebe oder kopiere sie in eine andere Liste oder füge Tags hinzu und entferne sie, für bis zu 5.000 Kontakte pro Aufruf. Wähle Kontakte über subscriber_ids, emails oder einen filter (Status, Tags, Engagement, Anmeldedatum). Verschieben und Kopieren übertragen nur Kontakte, die auf der Quellliste aktiv sind, und verlangen Listen desselben Kanals. Übergib trigger_automations: false, um Personen zu verschieben, ohne Willkommensserien neu zu starten.
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/members | lists:write |
| POST | /api/v1/lists/{id}/members/remove | lists:write |
| POST | /api/v1/lists/{id}/members/status | lists:write |
| POST | /api/v1/lists/{id}/members/move | lists:write |
| POST | /api/v1/lists/{id}/members/copy | lists:write |
| POST | /api/v1/lists/{id}/members/tags | lists:write |
Aktivität und Engagement
/activity führt Anmeldungen, Bestätigungen, Abmeldungen, Öffnungen, Klicks und Versandergebnisse einer Liste in einem Feed zusammen, filterbar über days, limit und types[]. /engagement liefert Zusammensetzung, Wachstum und Abwanderung der Empfänger mit Tageswerten, Öffnungs- und Klickraten, Top-Nachrichten und -Links sowie die Größe des inaktiven Teils der Liste.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/lists/{id}/activity | lists:read |
| GET | /api/v1/lists/{id}/engagement | lists:read |
Sperrliste
Eine kontoweite Liste von Adressen, die keine Mails erhalten dürfen; jeder Import beachtet sie. POST nimmt emails[], einen optionalen reason und unsubscribe_existing (Standard true, meldet die Adresse von allen Listen ab). DELETE hebt die Sperre auf, meldet aber niemanden wieder an.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/suppressions | subscribers:read |
| POST | /api/v1/suppressions | subscribers:write |
| DELETE | /api/v1/suppressions | subscribers:write |
E-Mail-Versand
POST /email/send reiht eine E-Mail ein: email, subject und content (HTML) sind Pflicht; preheader, plain_text, mailbox_id, subscriber_id, schedule_at, tracking_enabled und zusätzliche headers sind optional. POST /email/batch sendet eine Nachricht an eine Liste (list_id oder contact_list_ids), an tag_ids oder an subscriber_ids, optional mit excluded_list_ids. Beide antworten mit 202 und einer ID, die du an /email/status/{id} übergeben kannst.
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/email/send | email:write |
| POST | /api/v1/email/batch | email:write |
| GET | /api/v1/email/status/{id} | email:read |
| GET | /api/v1/email/mailboxes | email:read |
SMS-Versand
POST /sms/send reiht eine SMS ein: phone und message (bis zu 1.600 Zeichen) sind Pflicht; provider_id, subscriber_id und schedule_at sind optional. POST /sms/batch sendet an eine list_id, an tag_ids oder an subscriber_ids. Platzhalter wie [[fname]] werden pro Empfänger befüllt.
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/sms/send | sms:write |
| POST | /api/v1/sms/batch | sms:write |
| GET | /api/v1/sms/status/{id} | sms:read |
| GET | /api/v1/sms/providers | sms:read |
Kampagnen (messages)
Kampagnen heißen in der API messages, und jeder Pfad unter /messages funktioniert auch unter /campaigns. Lege eine Kampagne mit subject, channel (email oder sms) und type (broadcast oder autoresponder) an, setze dann Empfängerlisten und Ausschlüsse und sende oder plane sie. Senden und Planen antworten mit 422, solange die Kampagne keine Liste, kein Postfach (E-Mail) oder keinen Inhalt hat. schedule nimmt scheduled_at und eine optionale timezone. Filtere die Kampagnenliste mit channel, type, status und search. Eine Kampagne mit aktivem ab_test_config und mindestens zwei Varianten zu speichern braucht GOLD; ohne Lizenz antwortet die API mit 402, bevor etwas gespeichert wird.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/messages | jeder gültige Schlüssel |
| POST | /api/v1/messages | messages:write |
| GET | /api/v1/messages/{id} | jeder gültige Schlüssel |
| PUT, PATCH | /api/v1/messages/{id} | messages:write |
| DELETE | /api/v1/messages/{id} | messages:write |
| POST | /api/v1/messages/{id}/lists | messages:write |
| POST | /api/v1/messages/{id}/exclusions | messages:write |
| POST | /api/v1/messages/{id}/schedule | messages:write |
| POST | /api/v1/messages/{id}/send | messages:write |
| POST | /api/v1/messages/{id}/test | messages:write |
| GET, POST | /api/v1/messages/{id}/preview | messages:read |
| GET | /api/v1/messages/{id}/stats | jeder gültige Schlüssel |
| GET | /api/v1/messages/{id}/recipients-count | messages:read |
| POST | /api/v1/messages/{id}/duplicate | messages:write |
| POST | /api/v1/messages/{id}/toggle-active | messages:write |
| POST | /api/v1/messages/{id}/resend-failed | messages:write |
| POST | /api/v1/messages/{id}/send-to-missed | messages:write |
A/B-Tests
Lege einen Test für eine Kampagne an, füge Varianten hinzu, starte und beende ihn und lies die Ergebnisse. Anlegen, Varianten hinzufügen und Starten brauchen GOLD; Beenden, Ergebnisse lesen und Löschen gehen in jedem Plan, sodass ein laufender Test auch nach dem Ende einer GOLD-Lizenz zu Ende läuft.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/ab-tests | jeder gültige Schlüssel |
| POST | /api/v1/ab-tests | messages:writeGOLD |
| GET | /api/v1/ab-tests/{id} | jeder gültige Schlüssel |
| POST | /api/v1/ab-tests/{id}/variants | messages:writeGOLD |
| POST | /api/v1/ab-tests/{id}/start | messages:writeGOLD |
| POST | /api/v1/ab-tests/{id}/end | messages:write |
| GET | /api/v1/ab-tests/{id}/results | jeder gültige Schlüssel |
| DELETE | /api/v1/ab-tests/{id} | messages:write |
Funnels
Automatisierungssequenzen aus Schritten. Ein Funnel startet bei list_signup, tag_added, form_submit oder manual. Füge Schritte hinzu, ändere und entferne sie, aktiviere oder pausiere den Funnel, nimm einen Abonnenten manuell auf (der Funnel muss aktiv sein, sonst 409) und lies seine Statistiken. Funnels gehören zu SILVER; einen Schritt vom Typ split (A/B-Aufteilung) hinzuzufügen oder einen Schritt dazu zu machen braucht GOLD, vorhandene Split-Schritte bleiben bearbeitbar.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/funnels | jeder gültige Schlüssel |
| POST | /api/v1/funnels | funnels:write |
| GET | /api/v1/funnels/{id} | jeder gültige Schlüssel |
| PUT, PATCH | /api/v1/funnels/{id} | funnels:write |
| DELETE | /api/v1/funnels/{id} | funnels:write |
| POST | /api/v1/funnels/{id}/steps | funnels:write |
| PUT | /api/v1/funnels/{id}/steps/{step} | funnels:write |
| DELETE | /api/v1/funnels/{id}/steps/{step} | funnels:write |
| POST | /api/v1/funnels/{id}/subscribers | funnels:write |
| POST | /api/v1/funnels/{id}/activate | funnels:write |
| POST | /api/v1/funnels/{id}/pause | funnels:write |
| GET | /api/v1/funnels/{id}/stats | jeder gültige Schlüssel |
Automatisierungsregeln
Regeln nach dem Muster: Tritt ein Auslöser ein und passen die Bedingungen, werden Aktionen ausgeführt. /automations/options listet die verfügbaren Auslöser, Bedingungen und Aktionen. Regeln lassen sich ein- und ausschalten und duplizieren, und ihre Ausführungsprotokolle lassen sich lesen.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/automations/options | funnels:read |
| GET | /api/v1/automations | funnels:read |
| POST | /api/v1/automations | funnels:write |
| GET | /api/v1/automations/{id} | funnels:read |
| PUT, PATCH | /api/v1/automations/{id} | funnels:write |
| DELETE | /api/v1/automations/{id} | funnels:write |
| POST | /api/v1/automations/{id}/toggle | funnels:write |
| POST | /api/v1/automations/{id}/duplicate | funnels:write |
| GET | /api/v1/automations/{id}/logs | funnels:read |
Webhooks
Registriere URLs, die signierte Ereignisbenachrichtigungen erhalten. Das Signatur-Secret wird nur beim Anlegen des Webhooks oder beim Neuerzeugen des Secrets zurückgegeben. /webhooks/events listet die Ereignisnamen, /test sendet eine Testzustellung. Die Webhook-Dokumentation beschreibt jedes Ereignis, seinen Payload und die Prüfung der Signaturen.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/webhooks/events | jeder gültige Schlüssel |
| GET | /api/v1/webhooks | jeder gültige Schlüssel |
| POST | /api/v1/webhooks | webhooks:write |
| GET | /api/v1/webhooks/{id} | jeder gültige Schlüssel |
| PUT, PATCH | /api/v1/webhooks/{id} | webhooks:write |
| DELETE | /api/v1/webhooks/{id} | webhooks:write |
| POST | /api/v1/webhooks/{id}/test | webhooks:write |
| POST | /api/v1/webhooks/{id}/regenerate-secret | webhooks:write |
Vorlagen und gespeicherte Blöcke
E-Mail-Vorlagen, ihre Kategorien und die gespeicherten Blöcke des E-Mail-Builders. /templates/{id}/preview rendert eine Vorlage.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/templates | messages:read |
| POST | /api/v1/templates | messages:write |
| GET | /api/v1/templates/{id} | messages:read |
| PUT, PATCH | /api/v1/templates/{id} | messages:write |
| DELETE | /api/v1/templates/{id} | messages:write |
| POST | /api/v1/templates/{id}/duplicate | messages:write |
| POST | /api/v1/templates/{id}/preview | messages:read |
| GET | /api/v1/template-categories | messages:read |
| GET | /api/v1/template-blocks/types | messages:read |
| GET | /api/v1/template-blocks | messages:read |
| POST | /api/v1/template-blocks | messages:write |
| PUT, PATCH | /api/v1/template-blocks/{id} | messages:write |
| DELETE | /api/v1/template-blocks/{id} | messages:write |
System-E-Mails und Systemseiten
Die E-Mails und Seiten, die NetSendo rund um Anmeldung, Bestätigung und Abmeldung zeigt, adressiert per Slug. Ohne list_id arbeitest du an der globalen Vorgabe; mit list_id legt der erste Schreibzugriff eine eigene Version für diese Liste an, und DELETE entfernt sie wieder, sodass die Liste auf die Vorgabe zurückfällt. Globale Vorgaben lassen sich nicht löschen.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/system-emails | lists:read |
| GET | /api/v1/system-emails/{slug} | lists:read |
| PUT | /api/v1/system-emails/{slug} | lists:write |
| PUT | /api/v1/system-emails/{slug}/active | lists:write |
| DELETE | /api/v1/system-emails/{slug} | lists:write |
| GET | /api/v1/system-pages | lists:read |
| GET | /api/v1/system-pages/{slug} | lists:read |
| PUT | /api/v1/system-pages/{slug} | lists:write |
| DELETE | /api/v1/system-pages/{slug} | lists:write |
Anmeldeformulare
Lege die Anmeldeformulare deiner Listen an, ändere, dupliziere und lösche sie.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/forms | lists:read |
| POST | /api/v1/forms | lists:write |
| GET | /api/v1/forms/{id} | lists:read |
| PUT, PATCH | /api/v1/forms/{id} | lists:write |
| DELETE | /api/v1/forms/{id} | lists:write |
| POST | /api/v1/forms/{id}/duplicate | lists:write |
Benachrichtigungen
Lege Benachrichtigungen im Benachrichtigungscenter des Kontoinhabers an: title (Pflicht), message, type (info, success, warning oder error), list_id oder action_url und frei strukturierte data. An Abonnenten wird nichts gesendet.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/notifications | jeder gültige Schlüssel |
| POST | /api/v1/notifications | notifications:write |
Hilfs-Endpunkte für Integrationen
Endpunkte, die die Plugins für WordPress, WooCommerce und andere nutzen: externe Seiten, Versionsprüfungen der Plugins und Verbindungen. /api/webhooks/purchase empfängt Käufe aus E-Commerce-Integrationen und verlangt einen gültigen API-Schlüssel.
| Methode | Pfad | Scope |
|---|---|---|
| GET | /api/v1/external-pages | jeder gültige Schlüssel |
| GET | /api/v1/plugin/check-version | jeder gültige Schlüssel |
| POST | /api/v1/plugin/heartbeat | jeder gültige Schlüssel |
| GET | /api/v1/plugin/connections | jeder gültige Schlüssel |
| DELETE | /api/v1/plugin/connections/{id} | jeder gültige Schlüssel |
| POST | /api/v1/plugin/connections/{id}/disconnect | jeder gültige Schlüssel |
| POST | /api/webhooks/purchase | jeder gültige Schlüssel |
NetSendo Brain
Der in NetSendo integrierte KI-Assistent: Chat, Unterhaltungen, Wissensdatenbank, Aktionspläne und ihre Freigabe, Einstellungen und die Telegram-Verbindung. POST /brain/chat nimmt eine message mit bis zu 5.000 Zeichen und eine optionale conversation_id. Der Chat im manuellen Modus gehört zu SILVER. Selbstständiges Arbeiten von Brain braucht GOLD: PUT /brain/settings antwortet mit 402 bei work_mode semi_auto oder autonomous, nicht manuellen agent_modes, einem telegram_bot_token oder Recherche-Schlüsseln (perplexity_api_key, serpapi_api_key). Einträge der Wissensdatenbank fassen bis zu 10.000 Zeichen, mit GOLD bis zu 100.000; mit GOLD findet GET /brain/knowledge?search= Einträge auch nach Bedeutung (semantische Suche, seit 2.7.0).
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/brain/chat | jeder gültige Schlüssel |
| GET | /api/v1/brain/conversations | jeder gültige Schlüssel |
| GET | /api/v1/brain/conversations/{id} | jeder gültige Schlüssel |
| GET | /api/v1/brain/knowledge | jeder gültige Schlüssel |
| POST | /api/v1/brain/knowledge | jeder gültige Schlüssel |
| PUT | /api/v1/brain/knowledge/{id} | jeder gültige Schlüssel |
| DELETE | /api/v1/brain/knowledge/{id} | jeder gültige Schlüssel |
| GET | /api/v1/brain/plans | jeder gültige Schlüssel |
| GET | /api/v1/brain/plans/{id} | jeder gültige Schlüssel |
| POST | /api/v1/brain/plans/{id}/approve | jeder gültige Schlüssel |
| GET | /api/v1/brain/settings | jeder gültige Schlüssel |
| PUT | /api/v1/brain/settings | jeder gültige Schlüssel |
| POST | /api/v1/brain/telegram/link-code | jeder gültige SchlüsselGOLD |
| POST | /api/v1/brain/telegram/disconnect | jeder gültige Schlüssel |
| POST | /api/v1/brain/telegram/test | jeder gültige SchlüsselGOLD |
| POST | /api/v1/brain/telegram/set-webhook | jeder gültige SchlüsselGOLD |
Endpunkte für die Listenanmeldung
Für Website-Formulare und einfache Integrationen, die nur eine Liste erreichen sollen. Diese Endpunkte nehmen keinen Konto-API-Schlüssel an: Authentifiziere dich mit dem eigenen Schlüssel der Liste, den du in den Listeneinstellungen unter Integration → Listen-API-Schlüssel erzeugst. subscribe nimmt email (oder phone bei einer SMS-Liste), first_name und last_name; unsubscribe nimmt email. Eine Liste, die keine Anmeldungen annimmt, antwortet mit 403. Fehler haben hier die Form success: false mit error oder errors.
| Methode | Pfad | Scope |
|---|---|---|
| POST | /api/v1/lists/{id}/subscribe | eigener API-Schlüssel der Liste |
| POST | /api/v1/lists/{id}/unsubscribe | eigener API-Schlüssel der Liste |
Beispiele
curl -X POST https://your-domain.com/api/v1/subscribers \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "anna@example.com",
"contact_list_id": 5,
"first_name": "Anna",
"tags": [1, 3],
"custom_fields": { "city": "Berlin" }
}'
# 201 Created (200 when the address already existed)
{
"data": {
"id": 456,
"email": "anna@example.com",
"first_name": "Anna",
"status": "active",
"contact_list_id": 5,
"contact_list_ids": [5],
"source": "api",
"tags": [{ "id": 1, "name": "VIP", ... }, { "id": 3, "name": "Newsletter", ... }],
"custom_fields": { "email": "anna@example.com", "fname": "Anna", ..., "city": "Berlin" },
"subscribed_at": "2026-11-07T10:30:00.000000Z",
"created_at": "2026-11-07T10:30:00.000000Z",
...
}
}curl -X POST https://your-domain.com/api/v1/email/send \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"email": "anna@example.com",
"subject": "Your order is on its way",
"content": "<p>Hi [[fname]], your order has shipped.</p>",
"subscriber_id": 456,
"mailbox_id": 1
}'
# 202 Accepted
{
"data": {
"id": 123,
"email": "anna@example.com",
"subject": "Your order is on its way",
"status": "queued",
"mailbox": "Main mailbox",
"scheduled_at": null
},
"message": "Email queued successfully"
}# 1. Create a draft email campaign for list 5
curl -X POST https://your-domain.com/api/v1/messages \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"subject": "November news",
"channel": "email",
"type": "broadcast",
"content": "<h1>Hello [[fname]]</h1>",
"contact_list_ids": [5],
"mailbox_id": 1
}'
# 2a. Send it now (42 = the id returned in step 1)
curl -X POST https://your-domain.com/api/v1/messages/42/send \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Accept: application/json"
# 2b. Or schedule it in a given time zone
curl -X POST https://your-domain.com/api/v1/messages/42/schedule \
-H "Authorization: Bearer ns_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "scheduled_at": "2026-11-20 09:00", "timezone": "Europe/Warsaw" }'const res = await fetch(
"https://your-domain.com/api/v1/subscribers?status=active&per_page=50",
{
headers: {
Authorization: `Bearer ${process.env.NETSENDO_API_KEY}`,
Accept: "application/json",
},
}
)
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") ?? 60)
// try again after `wait` seconds
}
const { data, meta } = await res.json()
console.log(meta.total, data.map((s) => s.email))curl -X POST https://your-domain.com/api/v1/lists/5/subscribe \
-H "Authorization: Bearer YOUR_LIST_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "email": "anna@example.com", "first_name": "Anna" }'
# 201 Created
{
"success": true,
"message": "Successfully subscribed",
"subscriber_id": 456,
"status": "new"
}OpenAPI-Spezifikation in deiner Instanz
Jede NetSendo-Installation erzeugt außerdem eine OpenAPI-Beschreibung ihrer API. Melde dich im Panel an und öffne https://your-domain.com/docs/api für die interaktive Referenz oder /docs/api.json für die reine Spezifikation. Beide sind nur für angemeldete Benutzer sichtbar.

Häufige Fragen
Wie authentifiziere ich mich bei der NetSendo-API?
Erstelle im NetSendo-Panel unter Einstellungen → API-Schlüssel einen API-Schlüssel und sende ihn im Header Authorization als Bearer-Token: Authorization: Bearer ns_live_… Der Schlüssel wird nur einmal angezeigt, beim Erstellen.
Wie hoch ist das Rate Limit der NetSendo-API?
3.000 Anfragen pro Minute und API-Schlüssel. Über dem Limit antwortet die API mit 429 Too Many Requests und einem Retry-After-Header. Batch-Endpunkte nehmen bis zu 1.000 Abonnenten pro Anfrage an.
Welchen Scope braucht ein Schlüssel, um Abonnenten hinzuzufügen?
subscribers:write für POST /api/v1/subscribers und POST /api/v1/subscribers/batch. Importe und Massenänderungen der Mitgliedschaft auf einer Liste verlangen lists:write. Ein Schreib-Scope gewährt auch den passenden Lese-Scope.
Gibt es eine OpenAPI-Spezifikation für die NetSendo-API?
Ja. Jede Installation erzeugt eine: Melde dich im Panel an und öffne /docs/api für die interaktive Referenz oder /docs/api.json für die Spezifikation.
Wie kann ein Website-Formular Abonnenten ohne Konto-API-Schlüssel hinzufügen?
Erzeuge in den Einstellungen der Liste unter Integration → Listen-API-Schlüssel einen Schlüssel und sende die Formulardaten per POST an /api/v1/lists/{id}/subscribe, mit diesem Schlüssel als Bearer-Token. Der Schlüssel gilt nur für diese Liste.
Was ist der Unterschied zwischen /messages und /campaigns?
Keiner. /campaigns ist ein Alias von /messages: Beide Pfade führen zu denselben Kampagnen-Endpunkten mit denselben Scopes.

