API-Dokumentation

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.

Einführung

Base-URL
https://app.einfach-news.de/api
Content-Type
application/json für Anfragen & Antworten
Authentifizierung
Bearer-Token im Header:
Authorization: Bearer {token}
Rate-Limits
60 Anfragen/Minute (auth. Endpunkte)
30 Anfragen/Minute (Subscribe, per IP)
Fehlerformat

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).

Authentifizierung

Alle geschützten Endpunkte erfordern ein Sanctum-Token. Token werden pro Gerät ausgestellt und können jederzeit widerrufen werden.

POST /api/auth/token 🌍 Öffentlich

Erzeugt ein neues persönliches Zugriffstoken. Das Token erscheint nur einmalig in der Antwort.

Request-Body
FeldTypPflichtBeschreibung
emailstring✓E-Mail-Adresse des Nutzers
passwordstring✓Passwort des Nutzers
device_namestring✓Gerätename, max. 255 Zeichen
// POST /api/auth/token
{
  "email": "nutzer@beispiel.de",
  "password": "geheim123",
  "device_name": "Mein Server"
}
Antwort 200
{
  "token": "1|abc123xyz...",
  "user": {
    "id": 1,
    "name": "Max Mustermann",
    "email": "nutzer@beispiel.de"
  }
}
200Token erzeugt
401Anmeldedaten ungültig
422Validierungsfehler
POST /api/auth/logout 🔒 Auth erforderlich

Widerruft das aktuell verwendete Token. Kein Request-Body erforderlich.

Antwort 200
{
  "message": "Token wurde widerrufen."
}

Öffentliche Anmelde-API

Diese Endpunkte sind für eingebettete Anmeldeformulare konzipiert. Der {token} ist der subscribe_form_token einer Empfängerliste mit aktivierter öffentlicher Anmeldung.

GET /api/subscribe/{token}/meta 🌍 Öffentlich

Gibt Metadaten der Liste zurück, um das Anmeldeformular clientseitig zu rendern.

Antwort 200
{
  "name": "Newsletter Q4",
  "description": "Vierteljährlicher Überblick",
  "double_opt_in": true,
  "doi_subject": "Bitte bestätigen Sie Ihre Anmeldung"
}
200Metadaten zurückgegeben
404Liste nicht gefunden oder nicht öffentlich
POST /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.

Request-Body
FeldTypPflichtBeschreibung
emailstring✓E-Mail-Adresse, max. 255 Zeichen
namestring–Vollständiger Name, max. 255 Zeichen
first_namestring–Vorname, max. 100 Zeichen
last_namestring–Nachname, max. 100 Zeichen
// POST /api/subscribe/abc123
{
  "email": "maria@beispiel.de",
  "first_name": "Maria",
  "last_name": "Muster"
}
Antwort 200
// Double-Opt-in aktiv
{ "status": "pending", "message": "Bitte bestätigen Sie Ihre Anmeldung per E-Mail." }

// Direkt eingetragen
{ "status": "subscribed", "message": "Erfolgreich angemeldet!" }
200Anmeldung akzeptiert (pending oder subscribed)
404Liste nicht gefunden oder nicht öffentlich
422E-Mail ungültig oder Validierungsfehler
429Rate-Limit überschritten (30/min)

Teams

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.

MethodeEndpunktAktion
GET/api/teamsAlle Teams des Nutzers
POST/api/teamsNeues Team erstellen
GET/api/teams/{team}Team anzeigen
PUT/api/teams/{team}Team aktualisieren
DELETE/api/teams/{team}Team löschen (nur Eigentümer)
POST /api/teams — Request-Body
FeldTypPflichtBeschreibung
namestring✓Team-Name, max. 100 Zeichen
Antwort – Team-Objekt
{
  "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).

E-Mail-Anbieter

Konfigurieren Sie SMTP, Amazon SES, Mailgun oder SendGrid als Versandanbieter. Alle Operationen sind auf das aktuelle Team beschränkt.

MethodeEndpunktAktion
GET/api/providersAlle Anbieter (inkl. Regeln)
POST/api/providersAnbieter erstellen
GET/api/providers/{provider}Anbieter anzeigen
PUT/api/providers/{provider}Anbieter aktualisieren
DELETE/api/providers/{provider}Anbieter löschen
Request-Body (POST / PUT)
FeldTypPflichtBeschreibung
namestring✓Anzeigename, max. 255
typestring✓smtp | ses | mailgun | sendgrid
from_addressstring✓Absender-E-Mail
from_namestring✓Absendername
hoststring–SMTP-Host
portinteger–SMTP-Port (1–65535)
usernamestring–SMTP-Benutzername
passwordstring–SMTP-Passwort (verschlüsselt gespeichert)
api_keystring–API-Key (SES/Mailgun/SendGrid)
api_regionstring–Region (z.B. für Mailgun EU)
encryptionstring–tls | ssl | none
activeboolean–Anbieter aktiv schalten
priorityinteger–Priorität (min. 1)
metaobject–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
}

Anbieter-Regeln

Versandlimits und Domain-Gruppen pro Anbieter. Regeln werden vom internen Throttling-System in Echtzeit ausgewertet.

MethodeEndpunktAktion
GET/api/providers/{provider}/rulesAlle Regeln
POST/api/providers/{provider}/rulesRegel 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
Request-Body (POST)
FeldTypPflichtBeschreibung
namestring✓Regelname, max. 100 Zeichen
limit_per_minuteinteger✓Max. Nachrichten pro Minute (min. 1)
limit_per_hourinteger✓Max. Nachrichten pro Stunde (min. 1)
domain_groupsarray–Domänengruppen, auf die diese Regel greift

PUT unterstützt partielle Aktualisierung (sometimes-Validierung). DELETE gibt 204 zurück.

Empfängerlisten

Listen bündeln Empfänger für Kampagnen. Jede Liste kann ein eigenes Double-Opt-in-Verfahren und einen öffentlichen Anmeldetoken besitzen.

MethodeEndpunktAktion
GET/api/listsAlle Listen (mit subscribed_count)
POST/api/listsListe erstellen
GET/api/lists/{list}Liste anzeigen
PUT/api/lists/{list}Liste aktualisieren
DELETE/api/lists/{list}Liste löschen
Request-Body (POST / PUT)
FeldTypPflichtBeschreibung
namestring✓Listenname, max. 255
descriptionstring–Beschreibung, max. 1000
double_opt_inboolean–DOI-Prozess aktivieren
doi_subjectstring–Betreff der DOI-Bestätigungsmail
doi_templatestring–HTML-Inhalt der DOI-Mail
doi_redirect_urlstring–URL nach Bestätigung, max. 500
public_subscribeboolean–Öffentliche Anmeldung erlauben
sender_modestring–original | fixed | fallback
sender_namestring–Fester Absendername
sender_emailstring–Feste Absender-E-Mail
add_unsubscribe_footerboolean–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

Empfänger werden einer Liste zugeordnet. Das Löschen eines Eintrags setzt den Status auf unsubscribed — der Datensatz bleibt für Auditzwecke erhalten.

MethodeEndpunktAktion
GET/api/lists/{list}/recipientsPaginiert (50/Seite)
POST/api/lists/{list}/recipientsEinzelnen Empfänger hinzufügen
POST/api/lists/{list}/recipients/bulkMassenimport (max. 1000)
DELETE/api/lists/{list}/recipients/{recipient}Abmelden (soft)
POST — Einzelner Empfänger
FeldTypPflichtBeschreibung
emailstring✓Gültige E-Mail-Adresse
namestring–Vollständiger Name
first_namestring–Vorname, max. 100
last_namestring–Nachname, max. 100
POST /bulk — Request-Body
// POST /api/lists/3/recipients/bulk
{
  "recipients": [
    { "email": "anna@beispiel.de", "name": "Anna Schmidt" },
    { "email": "ben@beispiel.de" }
  ]
}
Antwort 200
{ "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.

Templates

E-Mail-Vorlagen mit automatischer Versionierung. Jede Aktualisierung erhöht die version-Zahl.

MethodeEndpunktAktion
GET/api/templatesAlle Top-Level-Templates
POST/api/templatesTemplate erstellen
GET/api/templates/{template}Template anzeigen
PUT/api/templates/{template}Template aktualisieren (+Version)
DELETE/api/templates/{template}Template löschen
Request-Body (POST / PUT)
FeldTypPflichtBeschreibung
namestring✓Template-Name, max. 255
subjectstring✓Standard-Betreff, max. 255
preheaderstring–Preheader-Text, max. 255
editor_typestring–grapesjs | mjml | quill | html
content_jsonstring–Editor-Daten als JSON-String
html_renderedstring–Gerendertes HTML
text_versionstring–Plaintext-Fallback
variablesarray–Verfügbare Template-Variablen
is_publishedboolean–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"
  }
]

Kampagnen

Eine Kampagne verknüpft Template + Empfängerliste + Anbieter und steuert den Versandprozess. Antworten enthalten den CampaignResource-Satz.

MethodeEndpunktAktion
GET/api/campaignsPaginiert (20/Seite)
POST/api/campaignsKampagne erstellen
GET/api/campaigns/{campaign}Kampagne anzeigen
PUT/api/campaigns/{campaign}Kampagne aktualisieren
DELETE/api/campaigns/{campaign}Kampagne löschen
Request-Body (POST / PUT)
FeldTypPflichtBeschreibung
list_idinteger✓ID der Empfängerliste
template_idinteger✓ID des Templates
namestring✓Kampagnenname, max. 255
provider_idinteger–Fester Versandanbieter
subject_overridestring–Betreff überschreiben
from_name_overridestring–Absendername überschreiben
from_email_overridestring–Absender-E-Mail überschreiben
provider_strategystring–single | round_robin | preferred
schedule_atdatetime–Versandzeitpunkt (ISO 8601, muss in der Zukunft liegen)
batch_sizeinteger–Nachrichten pro Batch (10–1000)
utm_tagsobject–UTM-Parameter (utm_source etc.)
notesstring–Interne Notizen, max. 2000
CampaignResource — Felder
{
  "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"
}

Kampagnen-Aktionen & Statistiken

POST /api/campaigns/{campaign}/schedule 🔒 Auth

Plant den Kampagnenversand für einen zukünftigen Zeitpunkt. Setzt Status auf scheduled.

FeldTypPflichtBeschreibung
schedule_atdatetime✓ISO-8601-Zeitstempel, muss in der Zukunft liegen
POST /api/campaigns/{campaign}/pause 🔒 Auth

Pausiert einen laufenden Versand. Kein Request-Body erforderlich. Gibt die aktualisierte Kampagne zurück.

POST /api/campaigns/{campaign}/resume 🔒 Auth

Setzt eine pausierte Kampagne fort. Kein Request-Body erforderlich.

GET /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" }
}
GET /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ückungsliste

Unterdrückte E-Mail-Adressen oder Domains werden beim Kampagnenversand automatisch übersprungen. Paginiert mit 50 Einträgen pro Seite.

MethodeEndpunktAktion
GET/api/suppressionsPaginiert (50/Seite, neueste zuerst)
POST/api/suppressionsEintrag hinzufügen
GET/api/suppressions/{suppression}Eintrag anzeigen
PUT/api/suppressions/{suppression}Notizen/Ablaufdatum ändern
DELETE/api/suppressions/{suppression}Eintrag entfernen
Request-Body (POST)
FeldTypPflichtBeschreibung
emailstringWenn kein domainE-Mail-Adresse
domainstringWenn kein emailDomain (z.B. spam.de)
typestring✓email | domain
reasonstring✓hard_bounce | complaint | manual | unsubscribe | disposable
notesstring–Interne Notizen, max. 500
expires_atdate–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"
}
201Eintrag erstellt
200Eintrag aktualisiert
204Eintrag gelöscht
422Validierungsfehler (z.B. weder email noch domain angegeben)