Vollständige Referenz der Einfach-News REST-API. Alle Endpunkte sind unter
https://app.einfach-news.de/api erreichbar.
Authentifizierung via Laravel Sanctum — Bearer-Token im
Authorization-Header.
Antwortformat durchgehend JSON.
https://app.einfach-news.de/api
application/json für Anfragen & Antworten
Authorization: Bearer {token}
Bei Validierungsfehlern (422) gibt die API folgendes zurück:
// HTTP 422 Unprocessable Entity { "message": "The given data was invalid.", "errors": { "email": ["The email field is required."] } }
Autorisierungsfehler liefern 401 (nicht eingeloggt) oder 403 (keine Berechtigung).
Alle geschützten Endpunkte erfordern ein Sanctum-Token. Token werden pro Gerät ausgestellt und können jederzeit widerrufen werden.
/api/auth/token
🌍 Öffentlich
Erzeugt ein neues persönliches Zugriffstoken. Das Token erscheint nur einmalig in der Antwort.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | string | ✓ | E-Mail-Adresse des Nutzers |
password | string | ✓ | Passwort des Nutzers |
device_name | string | ✓ | Gerätename, max. 255 Zeichen |
// POST /api/auth/token { "email": "nutzer@beispiel.de", "password": "geheim123", "device_name": "Mein Server" }
{
"token": "1|abc123xyz...",
"user": {
"id": 1,
"name": "Max Mustermann",
"email": "nutzer@beispiel.de"
}
}
| 200 | Token erzeugt |
| 401 | Anmeldedaten ungültig |
| 422 | Validierungsfehler |
/api/auth/logout
🔒 Auth erforderlich
Widerruft das aktuell verwendete Token. Kein Request-Body erforderlich.
{
"message": "Token wurde widerrufen."
}
Diese Endpunkte sind für eingebettete Anmeldeformulare konzipiert. Der {token} ist der subscribe_form_token einer Empfängerliste mit aktivierter öffentlicher Anmeldung.
/api/subscribe/{token}/meta
🌍 Öffentlich
Gibt Metadaten der Liste zurück, um das Anmeldeformular clientseitig zu rendern.
{
"name": "Newsletter Q4",
"description": "Vierteljährlicher Überblick",
"double_opt_in": true,
"doi_subject": "Bitte bestätigen Sie Ihre Anmeldung"
}
| 200 | Metadaten zurückgegeben |
| 404 | Liste nicht gefunden oder nicht öffentlich |
/api/subscribe/{token}
🌍 Öffentlich
30/min
Meldet eine E-Mail-Adresse an der Liste an. Bei aktiviertem Double-Opt-in wird eine Bestätigungsmail verschickt.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | string | ✓ | E-Mail-Adresse, max. 255 Zeichen |
name | string | – | Vollständiger Name, max. 255 Zeichen |
first_name | string | – | Vorname, max. 100 Zeichen |
last_name | string | – | Nachname, max. 100 Zeichen |
// POST /api/subscribe/abc123 { "email": "maria@beispiel.de", "first_name": "Maria", "last_name": "Muster" }
// Double-Opt-in aktiv { "status": "pending", "message": "Bitte bestätigen Sie Ihre Anmeldung per E-Mail." } // Direkt eingetragen { "status": "subscribed", "message": "Erfolgreich angemeldet!" }
| 200 | Anmeldung akzeptiert (pending oder subscribed) |
| 404 | Liste nicht gefunden oder nicht öffentlich |
| 422 | E-Mail ungültig oder Validierungsfehler |
| 429 | Rate-Limit überschritten (30/min) |
Ein Team bündelt alle Ressourcen (Anbieter, Listen, Kampagnen). Jeder Nutzer kann mehreren Teams angehören. Die aktuelle Team-Kontext wird über current_team_id im Nutzer-Profil gesteuert.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/teams | Alle Teams des Nutzers |
| POST | /api/teams | Neues Team erstellen |
| GET | /api/teams/{team} | Team anzeigen |
| PUT | /api/teams/{team} | Team aktualisieren |
| DELETE | /api/teams/{team} | Team löschen (nur Eigentümer) |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Team-Name, max. 100 Zeichen |
{
"id": 1,
"name": "Mein Unternehmen",
"slug": "mein-unternehmen-x7k2f1",
"owner_id": 5,
"members_count": 3,
"created_at": "2024-01-15T10:00:00Z"
}
DELETE gibt 204 No Content zurück. Nur der Team-Eigentümer darf ein Team löschen (sonst 403).
Konfigurieren Sie SMTP, Amazon SES, Mailgun oder SendGrid als Versandanbieter. Alle Operationen sind auf das aktuelle Team beschränkt.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/providers | Alle Anbieter (inkl. Regeln) |
| POST | /api/providers | Anbieter erstellen |
| GET | /api/providers/{provider} | Anbieter anzeigen |
| PUT | /api/providers/{provider} | Anbieter aktualisieren |
| DELETE | /api/providers/{provider} | Anbieter löschen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Anzeigename, max. 255 |
type | string | ✓ | smtp | ses | mailgun | sendgrid |
from_address | string | ✓ | Absender-E-Mail |
from_name | string | ✓ | Absendername |
host | string | – | SMTP-Host |
port | integer | – | SMTP-Port (1–65535) |
username | string | – | SMTP-Benutzername |
password | string | – | SMTP-Passwort (verschlüsselt gespeichert) |
api_key | string | – | API-Key (SES/Mailgun/SendGrid) |
api_region | string | – | Region (z.B. für Mailgun EU) |
encryption | string | – | tls | ssl | none |
active | boolean | – | Anbieter aktiv schalten |
priority | integer | – | Priorität (min. 1) |
meta | object | – | Zusätzliche Provider-Konfiguration |
// POST /api/providers { "name": "Mailgun EU", "type": "mailgun", "api_key": "key-xxxxxxxx", "api_region": "eu", "from_address": "noreply@meinedomain.de", "from_name": "Mein Newsletter", "active": true }
Versandlimits und Domain-Gruppen pro Anbieter. Regeln werden vom internen Throttling-System in Echtzeit ausgewertet.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/providers/{provider}/rules | Alle Regeln |
| POST | /api/providers/{provider}/rules | Regel erstellen |
| GET | /api/providers/{provider}/rules/{rule} | Regel anzeigen |
| PUT | /api/providers/{provider}/rules/{rule} | Regel aktualisieren |
| DELETE | /api/providers/{provider}/rules/{rule} | Regel löschen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Regelname, max. 100 Zeichen |
limit_per_minute | integer | ✓ | Max. Nachrichten pro Minute (min. 1) |
limit_per_hour | integer | ✓ | Max. Nachrichten pro Stunde (min. 1) |
domain_groups | array | – | Domänengruppen, auf die diese Regel greift |
PUT unterstützt partielle Aktualisierung (sometimes-Validierung). DELETE gibt 204 zurück.
Listen bündeln Empfänger für Kampagnen. Jede Liste kann ein eigenes Double-Opt-in-Verfahren und einen öffentlichen Anmeldetoken besitzen.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/lists | Alle Listen (mit subscribed_count) |
| POST | /api/lists | Liste erstellen |
| GET | /api/lists/{list} | Liste anzeigen |
| PUT | /api/lists/{list} | Liste aktualisieren |
| DELETE | /api/lists/{list} | Liste löschen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Listenname, max. 255 |
description | string | – | Beschreibung, max. 1000 |
double_opt_in | boolean | – | DOI-Prozess aktivieren |
doi_subject | string | – | Betreff der DOI-Bestätigungsmail |
doi_template | string | – | HTML-Inhalt der DOI-Mail |
doi_redirect_url | string | – | URL nach Bestätigung, max. 500 |
public_subscribe | boolean | – | Öffentliche Anmeldung erlauben |
sender_mode | string | – | original | fixed | fallback |
sender_name | string | – | Fester Absendername |
sender_email | string | – | Feste Absender-E-Mail |
add_unsubscribe_footer | boolean | – | Abmeldelink im Footer |
// GET /api/lists — Antwort [ { "id": 3, "name": "Kunden-Newsletter", "double_opt_in": true, "public_subscribe": true, "subscribed_count": 1248, "updated_at": "2024-03-10T14:22:00Z" } ]
Empfänger werden einer Liste zugeordnet. Das Löschen eines Eintrags setzt den Status auf unsubscribed — der Datensatz bleibt für Auditzwecke erhalten.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/lists/{list}/recipients | Paginiert (50/Seite) |
| POST | /api/lists/{list}/recipients | Einzelnen Empfänger hinzufügen |
| POST | /api/lists/{list}/recipients/bulk | Massenimport (max. 1000) |
| DELETE | /api/lists/{list}/recipients/{recipient} | Abmelden (soft) |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | string | ✓ | Gültige E-Mail-Adresse |
name | string | – | Vollständiger Name |
first_name | string | – | Vorname, max. 100 |
last_name | string | – | Nachname, max. 100 |
// POST /api/lists/3/recipients/bulk { "recipients": [ { "email": "anna@beispiel.de", "name": "Anna Schmidt" }, { "email": "ben@beispiel.de" } ] }
{ "imported": 2, "skipped": 0 }
Ungültige E-Mail-Adressen werden stillschweigend übersprungen. Die Quelle wird für Importdatensätze als api bzw. api_bulk gespeichert.
E-Mail-Vorlagen mit automatischer Versionierung. Jede Aktualisierung erhöht die version-Zahl.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/templates | Alle Top-Level-Templates |
| POST | /api/templates | Template erstellen |
| GET | /api/templates/{template} | Template anzeigen |
| PUT | /api/templates/{template} | Template aktualisieren (+Version) |
| DELETE | /api/templates/{template} | Template löschen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Template-Name, max. 255 |
subject | string | ✓ | Standard-Betreff, max. 255 |
preheader | string | – | Preheader-Text, max. 255 |
editor_type | string | – | grapesjs | mjml | quill | html |
content_json | string | – | Editor-Daten als JSON-String |
html_rendered | string | – | Gerendertes HTML |
text_version | string | – | Plaintext-Fallback |
variables | array | – | Verfügbare Template-Variablen |
is_published | boolean | – | Template veröffentlichen |
// GET /api/templates — Antwort (Listenformat) [ { "id": 7, "name": "Willkommens-Mail", "subject": "Herzlich willkommen!", "editor_type": "grapesjs", "is_published": true, "version": 3, "updated_at": "2024-04-01T09:15:00Z" } ]
Eine Kampagne verknüpft Template + Empfängerliste + Anbieter und steuert den Versandprozess. Antworten enthalten den CampaignResource-Satz.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/campaigns | Paginiert (20/Seite) |
| POST | /api/campaigns | Kampagne erstellen |
| GET | /api/campaigns/{campaign} | Kampagne anzeigen |
| PUT | /api/campaigns/{campaign} | Kampagne aktualisieren |
| DELETE | /api/campaigns/{campaign} | Kampagne löschen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
list_id | integer | ✓ | ID der Empfängerliste |
template_id | integer | ✓ | ID des Templates |
name | string | ✓ | Kampagnenname, max. 255 |
provider_id | integer | – | Fester Versandanbieter |
subject_override | string | – | Betreff überschreiben |
from_name_override | string | – | Absendername überschreiben |
from_email_override | string | – | Absender-E-Mail überschreiben |
provider_strategy | string | – | single | round_robin | preferred |
schedule_at | datetime | – | Versandzeitpunkt (ISO 8601, muss in der Zukunft liegen) |
batch_size | integer | – | Nachrichten pro Batch (10–1000) |
utm_tags | object | – | UTM-Parameter (utm_source etc.) |
notes | string | – | Interne Notizen, max. 2000 |
{
"id": 12,
"name": "Frühjahrs-Aktion 2024",
"status": "scheduled",
"subject": "Jetzt sparen!",
"schedule_at": "2024-04-15T08:00:00Z",
"started_at": null,
"completed_at": null,
"provider_strategy": "round_robin",
"total_recipients": 5200,
"sent_count": 0,
"delivery_rate": 0.0,
"open_rate": 0.0,
"click_rate": 0.0,
"utm_tags": { "utm_source": "newsletter" },
"list": { "id": 3, "name": "Kunden-Newsletter" },
"template": { "id": 7, "name": "Willkommens-Mail" },
"provider": { "id": 2, "name": "Mailgun EU", "type": "mailgun" },
"created_at": "2024-04-01T12:00:00Z",
"updated_at": "2024-04-01T12:00:00Z"
}
/api/campaigns/{campaign}/schedule
🔒 Auth
Plant den Kampagnenversand für einen zukünftigen Zeitpunkt. Setzt Status auf scheduled.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
schedule_at | datetime | ✓ | ISO-8601-Zeitstempel, muss in der Zukunft liegen |
/api/campaigns/{campaign}/pause
🔒 Auth
Pausiert einen laufenden Versand. Kein Request-Body erforderlich. Gibt die aktualisierte Kampagne zurück.
/api/campaigns/{campaign}/resume
🔒 Auth
Setzt eine pausierte Kampagne fort. Kein Request-Body erforderlich.
/api/campaigns/{campaign}/events
🔒 Auth
Gibt paginierte (50/Seite) Zustellereignisse zurück. Optionaler Query-Parameter: ?status=sent|failed|opened|clicked|bounced
// GET /api/campaigns/12/events?status=bounced { "data": [ { "id": 884, "status": "bounced", "bounce_type": "hard", "bounce_code": "550", "bounce_message": "User does not exist", "sent_at": "2024-04-15T08:02:11Z", "bounced_at": "2024-04-15T08:02:45Z", "recipient": { "id": 302, "email": "alt@beispiel.de", "name": null } } ], "links": { "next": "https://app.einfach-news.de/api/campaigns/12/events?page=2" } }
/api/campaigns/{campaign}/stats
🔒 Auth
Aggregierte Kampagnen-Statistiken.
{
"total_recipients": 5200,
"sent": 5188,
"failed": 12,
"opened": 1872,
"clicked": 543,
"bounced": 37,
"complained": 2,
"open_rate": 36.1,
"click_rate": 10.5,
"bounce_rate": 0.7,
"delivery_rate": 99.8
}
Unterdrückte E-Mail-Adressen oder Domains werden beim Kampagnenversand automatisch übersprungen. Paginiert mit 50 Einträgen pro Seite.
| Methode | Endpunkt | Aktion |
|---|---|---|
| GET | /api/suppressions | Paginiert (50/Seite, neueste zuerst) |
| POST | /api/suppressions | Eintrag hinzufügen |
| GET | /api/suppressions/{suppression} | Eintrag anzeigen |
| PUT | /api/suppressions/{suppression} | Notizen/Ablaufdatum ändern |
| DELETE | /api/suppressions/{suppression} | Eintrag entfernen |
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | string | Wenn kein domain | E-Mail-Adresse |
domain | string | Wenn kein email | Domain (z.B. spam.de) |
type | string | ✓ | email | domain |
reason | string | ✓ | hard_bounce | complaint | manual | unsubscribe | disposable |
notes | string | – | Interne Notizen, max. 500 |
expires_at | date | – | Ablaufdatum (ISO 8601) |
// POST /api/suppressions { "email": "beschwerde@beispiel.de", "type": "email", "reason": "complaint", "notes": "Manuell nach Beschwerde gesperrt" } // PUT /api/suppressions/{id} — nur notes + expires_at änderbar { "notes": "Bis Q3 gesperrt", "expires_at": "2024-09-30" }
| 201 | Eintrag erstellt |
| 200 | Eintrag aktualisiert |
| 204 | Eintrag gelöscht |
| 422 | Validierungsfehler (z.B. weder email noch domain angegeben) |