{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailpro™ CRM API v3",
    "version": "3",
    "description": "Die Mailpro™ CRM API v3 ermöglicht es Ihnen, Kontakte, Listen, Tags,\nbenutzerdefinierte Felder, E-Mail-Vorlagen und Kampagnen programmatisch zu verwalten —\nund sowohl Massen-Marketing-E-Mails als auch einzelne transaktionale E-Mails sowie SMS zu versenden.\n\n## Authentifizierung\n\nAlle Endpunkte (außer `POST /token` und den OAuth-Endpunkten) akzeptieren **drei\nAuthentifizierungsmethoden**. Verwenden Sie diejenige, die zu Ihrem Stack passt.\n\n- **OAuth 2.0** (authorization_code + PKCE oder client_credentials) — die\n  moderne Wahl für Drittanbieter-Apps und Integrationsplattformen\n  (Zapier, Make, n8n), die im Auftrag eines Mailpro-Benutzers handeln. Stellt scope-basierte,\n  widerrufbare Access Tokens aus. **Die einzige Methode, die granulare Scopes mitführt\n  und die Sie sicher an Dritte weitergeben können.**\n- **Bearer JWT** (Legacy) — ein HMAC-HS256-Token von `POST /token`. Sieht\n  wie OAuth aus, ist jedoch an einen einzelnen Kontozugang gebunden und nicht scope-basiert.\n- **IdClient + ApiKey** (Legacy) — Ihre Client-ID + Ihr API-Schlüssel in HTTP-Headern.\n\n> Legacy Bearer JWT und IdClient+ApiKey sind **nicht scope-gesteuert** — sie behalten\n> vollen Zugriff auf jeden Endpunkt, den sie bereits erreichen konnten. Nur OAuth 2.0\n> Access Tokens unterliegen den endpunktspezifischen Scope-Prüfungen, die in jeder\n> nachstehenden Operation aufgeführt sind (ein Token, dem der Scope fehlt, erhält **403 `insufficient_scope`**).\n\n### Methode 1 — OAuth 2.0 (empfohlen für Integrationen)\n\nMailpro betreibt **einen** OAuth 2.0 Authorization Server für sämtliche APIs,\nbereitgestellt über eine einzige versionsneutrale Oberfläche: **`https://api.mailpro.com/oauth/`**.\nEin Server, ein Token — **derselbe** Access Token funktioniert über CRM v3,\nEmail v2 und SMS hinweg. Welche Endpunkte ein Token aufrufen darf, wird durch die\n**Scopes** des Tokens gesteuert, nicht durch die API-Basis-URL, die Sie aufrufen. Es gibt keinen\nversionsspezifischen OAuth-Endpunkt (kein `/v3/oauth`, `/v2/oauth` oder `/sms/oauth`).\n\n| Endpunkt | URL |\n|----------|-----|\n| Authorize | `GET https://api.mailpro.com/oauth/authorize` |\n| Token / Refresh | `POST https://api.mailpro.com/oauth/token` |\n| JWKS (Signaturen verifizieren) | `GET https://api.mailpro.com/oauth/.well-known/jwks` |\n| Discovery | `GET https://api.mailpro.com/oauth/.well-known/openid-configuration` |\n\nIssuer (der `iss`-Claim in jedem Token): `https://api.mailpro.com/oauth/`.\n\n**Unterstützte Grants**\n\n- `authorization_code` **+ PKCE** (`code_challenge_method=S256` ist\n  **verpflichtend**) — der Browser-Einwilligungsflow „Mailpro verbinden\". Liefert einen\n  Access Token **und** ein rotierendes Refresh Token zurück.\n- `client_credentials` — Maschine-zu-Maschine, ohne Benutzer. Liefert ausschließlich einen\n  Access Token zurück.\n- `refresh_token` — tauschen Sie ein Refresh Token gegen ein neues Access-/Refresh-Paar\n  ein. **Refresh Tokens rotieren**: jede Verwendung invalidiert das alte.\n\n**Token-Lebensdauern**\n\n| Token | TTL |\n|-------|-----|\n| Access Token (RS256 JWT) | **20 Minuten** |\n| Refresh Token (gleitend, Einmalverwendung) | **30 Tage** |\n| Authorization Code | **60 Sekunden** |\n\n**Authorization Code + PKCE — Schritt für Schritt**\n\n1. Generieren Sie `code_verifier` (43–128 zufällige Zeichen) und\n   `code_challenge = base64url(sha256(code_verifier))`.\n2. Leiten Sie den Benutzer weiter zu:\n   ```\n   GET https://api.mailpro.com/oauth/authorize\n     ?response_type=code\n     &client_id=YOUR_CLIENT_ID\n     &redirect_uri=https://yourapp.example.com/callback\n     &scope=contacts:read contacts:write\n     &state=RANDOM_CSRF_TOKEN\n     &code_challenge=CODE_CHALLENGE\n     &code_challenge_method=S256\n   ```\n3. Der Benutzer bestätigt die Einwilligung auf dem Mailpro-Einwilligungsbildschirm; Mailpro leitet zurück\n   mit `?code=…&state=…`. Verifizieren Sie `state` (CSRF-Schutz).\n4. Tauschen Sie den Code gegen Tokens:\n   ```\n   POST https://api.mailpro.com/oauth/token\n   Content-Type: application/x-www-form-urlencoded\n\n   grant_type=authorization_code&code=AUTH_CODE\n   &redirect_uri=https://yourapp.example.com/callback\n   &client_id=YOUR_CLIENT_ID&code_verifier=CODE_VERIFIER\n   ```\n   ```json\n   { \"access_token\": \"eyJ…\", \"token_type\": \"Bearer\",\n     \"expires_in\": 1200, \"refresh_token\": \"…\" }\n   ```\n5. Rufen Sie jede Mailpro-API auf mit `Authorization: Bearer ACCESS_TOKEN`.\n6. Wenn er abläuft, erneuern Sie ihn mit `grant_type=refresh_token` und speichern Sie das\n   **neue** Refresh Token (das alte ist nun ungültig).\n\n**client_credentials**\n\n```\nPOST https://api.mailpro.com/oauth/token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials&client_id=YOUR_CLIENT_ID\n&client_secret=YOUR_CLIENT_SECRET&scope=contacts:read email:send\n```\n\nDerselbe OAuth Access Token wird auch von den APIs Email v2\n(`api.mailpro.com/v2`) und SMS (`api.mailpro.com/sms`) akzeptiert — einmal authentifizieren,\njede beliebige API aufrufen. Vollständiger Scope-Katalog: siehe **OAuth 2.0 Scopes** unten.\n\n### OAuth 2.0 in wenigen Minuten testen — Schnellstart\n\nDer schnellste Weg, OAuth auszuprobieren, ist der **client_credentials**-Grant\n(Server-zu-Server, kein Browser, kein Benutzer). Sie benötigen ein `client_id` /\n`client_secret`-Paar (fragen Sie Ihren Mailpro-Ansprechpartner oder erstellen Sie eines unter **Einstellungen →\nAPI-Zugriff**). Ersetzen Sie die Platzhalter unten — **committen Sie niemals ein echtes\nSecret**.\n\n**1. Einen Access Token abrufen**\n\n```bash\ncurl -X POST https://api.mailpro.com/oauth/token \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=YOUR_CLIENT_ID\" \\\n  -d \"client_secret=YOUR_CLIENT_SECRET\" \\\n  -d \"scope=contacts:read\"\n```\n\n```json\n{ \"access_token\": \"eyJhbGciOiJSUzI1Ni…\", \"token_type\": \"Bearer\",\n  \"expires_in\": 1200 }\n```\n\n**2. Einen Ressourcen-Endpunkt mit dem Token aufrufen**\n\n```bash\ncurl https://api.mailpro.com/v3/List \\\n  -H \"Authorization: Bearer eyJhbGciOiJSUzI1Ni…\"\n```\n\n**Derselbe** Token funktioniert auch auf Email v2 (`…/v2/…`) und SMS (`…/sms/…`) —\nsolange er den von jedem Endpunkt benötigten Scope enthält. Ein Token, dem der\nerforderliche Scope fehlt, wird mit **403 `insufficient_scope`** abgewiesen.\n\n**Interaktives „Mailpro verbinden\" (authorization_code + PKCE)** — wenn Sie im Auftrag\neines *Benutzers* handeln (Zapier/Make/n8n, Partner-Apps): leiten Sie den Benutzer weiter zu\n`GET https://api.mailpro.com/oauth/authorize` mit `response_type=code`,\n`client_id`, `redirect_uri`, `scope`, `state`, `code_challenge` und\n`code_challenge_method=S256`; der Benutzer stimmt zu; Sie tauschen den zurückgegebenen\n`code` an `POST https://api.mailpro.com/oauth/token` mit dem passenden\n`code_verifier` ein. Vollständige Anleitung oben; Scopes in **OAuth 2.0 Scopes** unten.\n\n> Tokens sind **RS256 JWTs** — Access Tokens leben **20 Minuten**, Refresh\n> Tokens **30 Tage** (gleitend, Einmalverwendung: jede Erneuerung rotiert den Token).\n> Verifizieren Sie Signaturen gegen das JWKS unter\n> `https://api.mailpro.com/oauth/.well-known/jwks` und validieren Sie den Scope\n> jeder Anfrage gegen die nachstehende Scope-Matrix.\n\n### Methode 2 — Bearer JWT (Legacy)\n\n```\nAuthorization: Bearer <access_token>\n```\n\nHolen Sie sich einen Token über `POST /token` (siehe unten). Standardmäßig **30 Tage** gültig;\nverwenden Sie `grant_type=refresh_token`, um ohne erneute Authentifizierung zu erneuern. Einfacher\neinzurichten, aber an einen einzelnen Kontozugang gebunden und **kann nicht** scope-basiert oder\nan Dritte weitergegeben werden — bevorzugen Sie OAuth 2.0 für jede installierbare Integration.\n\n### Methode 3 — IdClient + ApiKey (einfacher)\n\nSenden Sie Ihre Client-ID und Ihren API-Schlüssel als **HTTP-Header** (bevorzugt) oder als\n**Query-Parameter**:\n\n```\nIdClient: 12345\nApiKey:   a1b2c3d4-e5f6-7890-abcd-ef1234567890\n```\n\nDieselben Zugangsdaten wie bei den v2- / SMS-APIs — per Copy-Paste aus\n**Einstellungen → API-Zugriff**. Kein Token-Austauschschritt. Die Header-Form wird empfohlen,\nda URLs von IIS / Cloudflare / Proxys protokolliert werden.\n\n### Token-Endpunkt (password grant)\n```\nPOST /token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=password&username=YOUR_USERNAME&password=YOUR_API_KEY\n```\n- `username` — Ihr Mailpro-Benutzername (E-Mail)\n- `password` — Ihr API-Schlüssel (GUID), zu finden unter **Einstellungen → API-Zugriff**\n\n### Token-Endpunkt (client_credentials grant)\n```\nPOST /token\nContent-Type: application/x-www-form-urlencoded\n\ngrant_type=client_credentials&client_id=YOUR_CLIENT_ID\n```\n\n> Der von `POST /v3/token` ausgestellte Token ist auch auf der Email v2 API\n> (`api.mailpro.com/v2`) und der SMS API (`api.mailpro.com/sms`) gültig. Einmal authentifizieren,\n> jede beliebige API aufrufen.\n\n## OAuth 2.0 Scopes\n\nWenn Ihre App einen OAuth Access Token anfordert, deklariert sie eine Reihe von **Scopes** —\nBerechtigungen, die genau definieren, was der Token tun darf. Der Benutzer sieht eine\nallgemein verständliche Beschreibung jedes angeforderten Scopes auf dem Einwilligungsbildschirm.\nScopes sind im `scope`-Parameter durch Leerzeichen getrennt\n(`scope=contacts:read email:send`). Fordern Sie nur an, was Sie benötigen.\n\nScopes folgen dem Muster `<resource>:<action>` und sind **hierarchisch unabhängig** —\n`contacts:write` impliziert **nicht** `contacts:read`; fordern Sie bei Bedarf beide an.\n\n| Scope | Erlaubt |\n|-------|--------|\n| `contacts:read` | Anzeigen Ihrer Kontakte, Listen, Tags, Segmente und benutzerdefinierten Felder. |\n| `contacts:write` | Erstellen, Bearbeiten und Löschen Ihrer Kontakte, Listen, Tags und benutzerdefinierten Felder. |\n| `email:send` | Versenden transaktionaler und kampagnenbezogener E-Mails in Ihrem Auftrag. |\n| `email:read` | Anzeigen von Zustellstatistiken, Öffnungen, Klicks und Bounce-Historie. |\n| `email:templates:read` | Anzeigen Ihrer E-Mail-Vorlagen (Betreff, HTML-, Plain-Text-Body). |\n| `email:templates:write` | Erstellen, Bearbeiten und Löschen Ihrer E-Mail-Vorlagen. |\n| `sms:send` | Versenden transaktionaler und kampagnenbezogener SMS-Nachrichten in Ihrem Auftrag. |\n| `sms:read` | Anzeigen des SMS-Guthabens und der Nachrichtenhistorie. |\n| `sms:contacts:read` | Anzeigen Ihres SMS-Telefonbuchs. |\n| `sms:contacts:write` | Erstellen, Bearbeiten und Löschen von Einträgen in Ihrem SMS-Telefonbuch. |\n| `webhooks:manage` | Abonnieren, Bearbeiten und Entfernen von Webhook-Endpunkten für Ihr Konto. |\n| `account:read` | Anzeigen Ihrer Konto-Credits, Limits und des Abonnementstatus. |\n\n### Scope-Erzwingung pro Endpunkt\n\nScope-Prüfungen erfolgen **live** und werden für OAuth-ausgestellte Tokens pro Endpunkt erzwungen\n(Legacy-Authentifizierung ist ausgenommen). Jede Operation in dieser Referenz listet ihren erforderlichen\nScope unter **Authorization** auf. Zusammenfassung für die CRM v3-Oberfläche:\n\n| Endpunkte | Erforderlicher Scope |\n|-----------|----------------|\n| `GET /Contact/{id}`, `GET /List`, `GET /List/{id}`, `GET /List/{id}/Contact`, `GET /List/{listId}/Unsubscribers`, `GET /Tag`, `GET /Tag/{id}`, `GET /Tag/{id}/Contact`, `GET /Segment`, Segment-Zugehörigkeitsprüfung | `contacts:read` |\n| `POST /Contact`, `POST /Contact/Multiple`, `PUT`/`DELETE /Contact/{id}`, Tag oder Liste an einem Kontakt hinzufügen/entfernen, `POST`/`PUT`/`DELETE /List`, `POST`/`PUT`/`DELETE /Tag` | `contacts:write` |\n\n> Endpunkte in dieser Spezifikation, die **nicht** oben aufgeführt sind (z. B. `GET /Field`,\n> Kampagnen, transaktionaler Versand, SMS-Versand, Nachrichtenvorlagen, Kontoinformationen),\n> sind heute mit jedem gültigen Token erreichbar — sie sind auf der CRM v3-Oberfläche\n> noch nicht scope-gesteuert. Die Email v2- und SMS-APIs schützen zusätzlich ihre eigenen\n> Send- / Template- / Contacts- / Account-Endpunkte (siehe entsprechende Spezifikationen).\n\nEine Scope-Ablehnung liefert **403** mit\n`{ \"error\": \"insufficient_scope\", \"required_scope\": \"…\" }` (RFC 6750 §3.1).\n\n## Datenformat\n\n- Alle Request-/Response-Bodies verwenden **JSON**\n- Eigenschaftsnamen sind in **snake_case**\n- Kontakt-IDs sind **UUIDs**\n- IDs von Listen, Tags und Feldern sind **Integer (int64)**\n\n## Paginierung\n\n**Gleiche Regel für die drei Mailpro-APIs** (Email v2, CRM v3, SMS): **5.000 Einträge pro Seite,\nstandardmäßig und maximal.**\n- `numberOfRecords` — Einträge pro Seite. Fehlend, `0` oder über 5.000 = 5.000.\n- `pageNumber` — Seitennummer ab 1 (Standard 1).\n- Beide werden als Query-Parameter **oder** als HTTP-Header akzeptiert.\n- Eine volle Seite bedeutet, dass es weitere geben kann: Fordern Sie die nächste Seite an, bis\n  eine unvollständige Seite zurückkommt.\n- Ausnahme: Nachrichten und Verlauf mit ihrem HTML (`includeBodyHTML=true`) liefern standardmäßig\n  10 Einträge pro Seite.\n- Eine leere Seite oder eine Suche ohne Treffer liefert `200` mit einer leeren Liste `[]`.\n  `404` bedeutet, dass die Ressource selbst (Liste, Tag, Segment, Kampagne…) nicht existiert.\n\n**Unbekannte Parameter** werden ignoriert, nie abgelehnt. Enthält eine Anfrage einen Parameter, den die API\nnicht kennt, enthält die Antwort `X-Ignored-Parameters` (die Namen) und `X-Documentation` (einen Link zu\ndieser Seite), damit ein Tippfehler nicht unbemerkt bleibt.\n\n## Geschäftsfehler-Codes\n\nVerstöße gegen Geschäftsregeln liefern HTTP **406** mit einem JSON-Body:\n```json\n{ \"Message\": \"Contact cannot be created. Email cannot be empty.\" }\n```\n\nHäufige 406-Gründe:\n- `Email cannot be empty` — E-Mail ist erforderlich\n- `Email has an invalid format` — keine gültige E-Mail-Adresse\n- `A contact already exist with the same Email` — Verstoß gegen die E-Mail-Eindeutigkeit\n- `The email address was unsubscribed permanently` — Adresse auf der Sperrliste\n- `The email address has identified has a hard bounce` — Adresse ist gebounced\n- `The email address has identified has a spam trap` — Spam-Falle erkannt\n- `At least one List is necessary` — Kontakte müssen mindestens einer Liste angehören\n- `One or more lists have reached the contact limit` — maximal 1 Mio. Kontakte pro Liste\n- `Invalid Phone Number` — Formatfehler bei der Telefonnummer\n- `Invalid country code for Phone Number` — nicht unterstützter Ländervorwahl\n- `Length exceeded for Phone Number (12)` — Telefonnummer zu lang\n\n### Zurückgegebene Statuscodes\n\n| Code | Bedeutung |\n|------|-----------|\n| `400` | Fehlerhafte Anfrage (ungültiges JSON, Nachricht über dem SMS-Teil-Limit) |\n| `401` | Fehlende, ungültige oder abgelaufene Anmeldedaten |\n| `402` | Nicht genügend Guthaben für den Versand |\n| `403` | Durch Ihre Anmeldedaten erlaubt, aber abgelehnt — Konto für SMS-Versand gesperrt |\n| `404` | Das referenzierte Objekt existiert nicht (Kontakt, Liste, Tag, Feld, Kampagne) |\n| `406` | Verstoß gegen eine Kontakt-Geschäftsregel (siehe Liste oben) |\n| `422` | Eingabe durch Validierung abgelehnt oder Kontolimit erreicht |\n\n> **Geändert:** Einige dieser Fälle gaben früher `404` zurück. Unzureichendes\n> Guthaben gibt jetzt **402** zurück, Validierungsfehler und Kontolimits geben\n> **422** zurück, und ein für SMS gesperrtes Konto gibt **403** zurück. `404`\n> wird jetzt nur noch für „dieses Objekt existiert nicht\" verwendet, konsistent\n> mit der SMS-API. Wenn Ihre Integration in diesen Fällen auf `404` verzweigt,\n> aktualisieren Sie sie auf die obigen Codes.\n\n## Format von Telefonnummern\n\nTelefonnummern werden automatisch normalisiert. Sie können diese in vielen Formaten senden —\nLeerzeichen, Bindestriche, Punkte, Schrägstriche, Klammern, Unterstriche und geschützte Leerzeichen\nwerden vor der Validierung entfernt. Jedes andere Zeichen (Buchstaben, Apostrophe,\n`=`, `;` usw.) macht die Nummer ungültig.\n\n| Gültig                                          | Ungültig                                            |\n|------------------------------------------------|----------------------------------------------------|\n| `+41794849980` — E.164 international           | `0612345678` — nationales Format (führende `0`)    |\n| `0041 79 484 99 80` — 00-Präfix + Leerzeichen  | `41'794'849'80` — Apostrophe (nicht entfernt)      |\n| `+33 6-12-34-56-78` — + mit Bindestrichen      | `tel=0041794849980` — zusätzliche Zeichen          |\n| `41794849980` — reine Ziffern                  | `1234567` — zu kurz (< 8 Ziffern)                  |\n\n**Regeln:**\n- Akzeptierte Präfixe: `+`, `00` oder kein Präfix\n- Länge nach Normalisierung: **8 bis 15 Ziffern** (E.164-Maximum)\n- Erste Ziffer nach Entfernung des Präfixes muss **1–9** sein (nicht `0`)\n- Entfernte Trennzeichen: Leerzeichen, Tab, Bindestrich `-`, Punkt `.`, Schrägstrich `/`, Klammern `( )`, Unterstrich `_`, NBSP\n- Alles andere (Buchstaben, Apostrophe, `=`, `;`, `+` innerhalb der Nummer usw.) → abgelehnt\n- Gespeicherte Form in unserer Datenbank: reine Ziffern, kein Präfix (z. B. `41794849980`)\n\n**v3 Contact-Besonderheiten:** das Feld `phone_number` auf einem Contact ist derzeit\nnach Normalisierung auf **12 Ziffern** begrenzt (gegenüber 15 für die eigenständigen SMS-\nEndpunkte). Nummern aus Ländern wie Deutschland (13), Brasilien (13) oder Italien mobil\n(12–13) können auf `/v3/Contact` mit\n`Length exceeded for Phone Number (12)` abgelehnt werden. Diese Legacy-Beschränkung kann\nin einer zukünftigen Version gelockert werden.\n\n## Limits\n\n| Ressource | Limit |\n|----------|-------|\n| Tags pro Konto | 1.000 |\n| Listen pro Konto | 1.000 |\n| Benutzerdefinierte Felder pro Konto | 50 |\n| Monatliche API-Anfragen pro Konto | 50.000 (5× E-Mail-Credits des Abonnements) |\n\n## Zustellverfolgung (transaktionale E-Mails)\n\nJede **einzeln** versendete E-Mail (`POST /Send/Mail`, die Email API v2, das SMTP-Relay oder eine Automatisierung) erhält eine Kennung. Sie kann verfolgt werden, bis der Server des Empfängers sie annimmt oder ablehnt. Kampagnen sind hier nicht abgedeckt: Nutzen Sie die Statistiken.\n\n1. **Senden**: die Antwort von `POST /Send/Mail` enthält `id_single_send`.\n2. **Ergebnis empfangen** (empfohlen): Die Webhook-Ereignisse `email.delivered` und `email.bounced` senden den endgültigen Status an Ihren Server, sobald er feststeht – ganz ohne Abfragen.\n3. **Oder abfragen**: `GET /Send/{id}/Status` liefert den aktuellen Status (Tabelle unten).\n\n| `status` | Bedeutung | Endgültig? |\n|---|---|---|\n| `queued` | Angenommen, wartet auf den Versand. | nein |\n| `scheduled` | Für später geplant (`date_planned`). | nein |\n| `sent` | Von unseren Servern übergeben, noch keine Antwort des Empfängerservers. | nein |\n| `delivered` | Vom Empfängerserver angenommen (`diag_code` = seine SMTP-Antwort). | **ja** |\n| `bounced` | Abgelehnt. `bounce_type`: `hard` = ungültige Adresse oder endgültige Ablehnung; `soft` = Ablehnung nach erneuten Versuchen (Postfach voll, Server nicht erreichbar …). | **ja** |\n| `not_found` | Unbekannte Kennung oder Kennung, die nicht zu Ihrem Konto gehört. | **ja** |\n\n**Abfragen ohne Endlosschleife**\n\n- Beenden Sie die Abfragen, sobald der Status **endgültig** ist: Er ändert sich nicht mehr.\n- Erste Abfrage frühestens **5 Minuten** nach dem Versand: `delivered` erscheint etwa 5 Minuten nach der Übergabe.\n- Danach **höchstens eine Abfrage alle 15 Minuten**.\n- Fragen Sie eine nicht endgültige Sendung vor Ablauf von 15 Minuten ab, erhalten Sie dieselbe Antwort mit dem Header `Retry-After` (die Wartezeit in Sekunden), und der Aufruf zählt nicht für Ihr Kontingent.\n- **Spätestens 48 Stunden** nach dem Versand hat jede E-Mail einen endgültigen Status: Fragen Sie danach nicht mehr ab.\n- `scheduled`: Vor `date_planned` ist keine Abfrage nötig.\n- **Jede Abfrage zählt für Ihr Kontingent an API-Anfragen.** Nach diesen Regeln kostet eine Sendung höchstens 192 Anfragen (4 pro Stunde während 48 Stunden), in der Praxis deutlich weniger, da Sie beim endgültigen Status aufhören. Dieselbe Verfolgung per Webhook kostet ein einziges Ereignis.\n\nDie Status werden **365 Tage** aufbewahrt.\n\n## Webhooks\n\nMailpro™ kann Ihren Server in Echtzeit benachrichtigen, wenn bestimmte Ereignisse in Ihrem\nKonto auftreten (ein Kontakt wird erstellt, eine E-Mail wird zugestellt, eine Kampagne endet usw.).\nStripe-Stil — Ihre URL erhält einen mit HMAC-SHA256 signierten POST, sobald das\nEreignis ausgelöst wird.\n\nJedes an Ihren Webhook gesendete Ereignis zählt als 1 Anfrage in Ihrem Kontingent an API-Anfragen.\n\n### So funktioniert es\n\n1. **Abonnieren** Sie eine oder mehrere Ereignistypen über `POST /Webhook`. Die Antwort\n   enthält ein `secret`, das **einmalig** angezeigt wird (Stripe-/GitHub-Stil) — speichern Sie es.\n2. **Mailpro sendet einen POST** mit signiertem JSON-Payload an Ihre URL, sobald ein Ereignis übereinstimmt.\n3. **Verifizieren Sie die Signatur** serverseitig mit Ihrem `secret` (Snippets unten).\n4. **Antworten Sie 200–299** innerhalb von 10 Sekunden. Andernfalls wiederholen wir den Versuch mit exponentiellem\n   Backoff (10 Sek. → 1 Min. → 5 Min. → 30 Min. → 2 Std. → 6 Std. → 24 Std., dann geben wir auf).\n\n> **⏱ Aktivierungsverzögerung** — nachdem Sie einen Webhook erstellt, aktualisiert oder gelöscht haben, dauert es\n> bis zu **10 Minuten**, bis sich die Änderung über die Mailpro-API-Server verbreitet.\n> Während dieses Zeitfensters stimmen Ereignisse möglicherweise noch nicht mit Ihrem neuen Abonnement überein\n> (oder stimmen ggf. weiterhin mit einem gerade entfernten überein). Dies ist die Zeit, die erforderlich ist, um\n> den In-Memory-Abonnement-Cache auf jeder API-Instanz zu aktualisieren.\n\n### Payload-Envelope\n\nAlle Ereignisse teilen sich einen gemeinsamen Envelope:\n\n```json\n{\n  \"id\":         \"evt_8f3a9b2c4d1e5f6789abcdef01234567\",\n  \"type\":       \"contact.created\",\n  \"created\":    1748194800,\n  \"apiVersion\": \"v3\",\n  \"account\":    { \"id\": 12345, \"name\": \"ACME Corp\" },\n  \"data\":       { \"id\": \"...\", \"email\": \"alice@example.com\", \"...\": \"...\" }\n}\n```\n\n| Feld | Format | Beschreibung |\n|-------|--------|-------------|\n| `id` | `evt_` + 32 Hex-Zeichen | Eindeutige Ereignis-ID — verwenden Sie sie auf Ihrer Seite als Idempotenzschlüssel. |\n| `type` | `<domain>.<verb>` | Kanonischer Ereignistyp (z. B. `email.delivered`, `contact.created`). |\n| `created` | Unix-Sekunden UTC | In der HMAC-Signatur enthalten. |\n| `apiVersion` | `\"v3\"` | Welche Mailpro-API das Ereignis veröffentlicht hat. |\n| `account.id` | int | Ihre Mailpro-Client-ID. |\n| `account.name` | string | Ihr Kontoname (nützlich für clientseitiges Debugging). |\n| `data` | object | Ereignis-Payload — die Form hängt vom `type` ab (siehe Katalog unten). |\n\n### Ereigniskatalog\n\n| Ereignis | Auslöser | `data`-Form |\n|-------|---------|--------------|\n| `ping` | Test über `POST /Webhook/{id}/test` | `{ message }` |\n| `contact.created` | `POST /Contact` | `{ id, email, firstName, lastName, createdAt }` |\n| `contact.updated` | `PUT /Contact/{id}` | `{ id, email, firstName, lastName, updatedAt, changes }` |\n| `contact.deleted` | `DELETE /Contact/{id}` | `{ id, email, deletedAt }` |\n| `list.contact_added` | Kontakt zu Liste hinzugefügt | `{ listId, listName, contactId, contactEmail, addedAt }` |\n| `list.contact_removed` | Kontakt von Liste entfernt | `{ listId, listName, contactId, contactEmail, removedAt }` |\n| `tag.applied` | Tag auf Kontakt angewendet | `{ tag, contactId, contactEmail, appliedAt }` |\n| `tag.removed` | Tag entfernt | `{ tag, contactId, contactEmail, removedAt }` |\n| `segment.matched` | Kontakt tritt in ein Segment ein | `{ segmentId, segmentName, contactId, contactEmail, matchedAt }` |\n| `email.processed` | Versand von der Pipeline akzeptiert | `{ messageId, email, campaignId, processedAt }` |\n| `email.delivered` | Eine **einzelne** E-Mail wurde vom Empfängerserver angenommen — API v2/v3, SMTP oder Automation (**nicht** Kampagnen). Aus dem PowerMTA-Zustellstrom ausgelöst. | `{ messageId, email, idSending, sendingType, diagCode, deliveredAt }` |\n| `email.opened` | Tracking-Pixel aufgerufen | `{ messageId, email, campaignId, openedAt, ip, userAgent }` |\n| `email.clicked` | Klick auf getrackten Link | `{ messageId, email, campaignId, clickedAt, url, ip, userAgent }` |\n| `email.bounced` | Hard- oder Soft-Bounce | `{ messageId, email, campaignId, bouncedAt, bounceType, reason }` |\n| `email.spam_report` | FBL-Beschwerde | `{ messageId, email, campaignId, reportedAt }` |\n| `email.unsubscribed` | Opt-out-Link geklickt | `{ messageId, email, campaignId, unsubscribedAt }` |\n| `email.dropped` | Vor dem Versand abgelehnt | `{ messageId, email, campaignId, droppedAt, reason }` |\n| `campaign.started` | Versand beginnt | `{ campaignId, name, totalRecipients, startedAt }` |\n| `campaign.finished` | Alle Empfänger verarbeitet | `{ campaignId, name, totalSent, totalFailed, finishedAt }` |\n| `import.started` | Import-Job gestartet | `{ importId, fileName, totalRows, startedAt }` |\n| `import.progress` | Bei 25/50/75 % | `{ importId, fileName, processedRows, totalRows, progressPct }` |\n| `import.completed` | Import OK | `{ importId, fileName, totalRows, addedCount, updatedCount, errorCount, completedAt }` |\n| `import.failed` | Schwerwiegender Fehler während des Imports | `{ importId, fileName, errorMessage, failedAt }` |\n\nAbonnieren Sie alle Ereignisse dieser API, indem Sie `[\"*\"]` im Array `events` übergeben.\n\n### HMAC-Signatur\n\nJeder POST enthält einen `X-Mailpro-Signature`-Header:\n\n```\nX-Mailpro-Signature: t=1748194800,v1=7f9ac2b6e4d1c8a3...\nX-Mailpro-Event-Id:  evt_8f3a9b2c4d1e5f6789abcdef01234567\nX-Mailpro-Event-Type: contact.created\nX-Mailpro-Attempt:   1\n```\n\nSo verifizieren Sie:\n1. Extrahieren Sie `t` und `v1` aus dem Header.\n2. **Lehnen Sie ab**, falls `|now - t| > 300` (5-minütiges Replay-Schutzfenster).\n3. Berechnen Sie `expected = hex(HMAC_SHA256(secret, t + \".\" + raw_body))`.\n4. **Vergleichen Sie zeitkonstant** `v1` mit `expected` (`crypto.timingSafeEqual`,\n   `hash_equals`, `CryptographicOperations.FixedTimeEquals`) — niemals `==`.\n\n#### Node.js\n\n```js\nconst crypto = require('crypto');\n\nfunction verifyMailproSignature(rawBody, header, secret) {\n  const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));\n  if (Math.abs(Date.now() / 1000 - parseInt(parts.t)) > 300) return false;\n  const expected = crypto\n    .createHmac('sha256', secret)\n    .update(parts.t + '.' + rawBody)\n    .digest('hex');\n  return crypto.timingSafeEqual(\n    Buffer.from(parts.v1, 'hex'),\n    Buffer.from(expected, 'hex'));\n}\n```\n\n#### PHP\n\n```php\nfunction verifyMailproSignature(string $rawBody, string $header, string $secret): bool {\n    parse_str(str_replace(',', '&', $header), $p);\n    if (abs(time() - (int)$p['t']) > 300) return false;\n    $expected = hash_hmac('sha256', $p['t'] . '.' . $rawBody, $secret);\n    return hash_equals($expected, $p['v1']);\n}\n```\n\n#### Python\n\n```python\nimport hmac, hashlib, time\n\ndef verify_mailpro_signature(raw_body: bytes, header: str, secret: str) -> bool:\n    parts = dict(p.split('=') for p in header.split(','))\n    t = int(parts['t'])\n    if abs(time.time() - t) > 300:\n        return False\n    expected = hmac.new(\n        secret.encode(),\n        f\"{t}.\".encode() + raw_body,\n        hashlib.sha256\n    ).hexdigest()\n    return hmac.compare_digest(expected, parts['v1'])\n```\n\n#### C#\n\n```csharp\nusing System.Security.Cryptography;\nusing System.Text;\n\nstatic bool VerifyMailproSignature(string rawBody, string header, string secret) {\n    var parts = header.Split(',')\n        .Select(p => p.Split('='))\n        .ToDictionary(a => a[0], a => a[1]);\n    var t = long.Parse(parts[\"t\"]);\n    if (Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - t) > 300) return false;\n    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));\n    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes($\"{t}.{rawBody}\"));\n    var expected = Convert.ToHexString(hash).ToLowerInvariant();\n    return CryptographicOperations.FixedTimeEquals(\n        Encoding.UTF8.GetBytes(expected),\n        Encoding.UTF8.GetBytes(parts[\"v1\"]));\n}\n```\n\n### Wiederholungsversuche und automatische Deaktivierung\n\n| Versuch | Verzögerung vor dem nächsten Versuch |\n|---------|----------------------|\n| 1 → 2 | 10 Sekunden |\n| 2 → 3 | 1 Minute |\n| 3 → 4 | 5 Minuten |\n| 4 → 5 | 30 Minuten |\n| 5 → 6 | 2 Stunden |\n| 6 → 7 | 6 Stunden |\n| 7 | abgebrochen (Zustellung als `failed` markiert) |\n\nNach **10 aufeinanderfolgenden Fehlschlägen** an demselben Webhook wird er **automatisch\ndeaktiviert** (`isActive: false`) und Sie erhalten eine Benachrichtigungs-E-Mail. Aktivieren Sie ihn\nmit `PUT /Webhook/{id}` erneut, sobald Ihr Endpunkt repariert ist.\n\n### Erfolg = HTTP 2xx\n\nWir betrachten Ihren Webhook nur dann als erfolgreich, wenn Sie einen Status im Bereich `200–299` zurückgeben.\nJeder 3xx/4xx/5xx oder ein Timeout (> 10 Sek.) zählt als Fehlschlag und löst Wiederholungsversuche aus.\nFalls Ihr Endpunkt dauerhaft tot ist, geben Sie explizit `410 Gone` zurück — Wiederholungsversuche\nfinden weiterhin statt, aber der Grund des Fehlschlags ist in Ihrem Zustellprotokoll klarer.\n\n### Limits\n\n| Limit | Wert |\n|-------|-------|\n| Webhooks pro Konto | 20 |\n| Abonnierte Ereignisse pro Webhook | 50 |\n| Maximale Payload-Größe | 256 KB |\n| HTTP-Timeout pro Versuch | 10 Sekunden |\n| Aufbewahrung der Zustellhistorie | 30 Tage |"
  },
  "servers": [
    {
      "url": "https://api.mailpro.com/v3",
      "description": "Produktion"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    },
    {
      "IdClientHeader": [],
      "ApiKeyHeader": []
    },
    {
      "IdClientQuery": [],
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Bearer-JWT-Token, das über `POST /token` bezogen wird.\nÜbergeben Sie ihn als: `Authorization: Bearer <token>`\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "Mailpro OAuth 2.0 — der moderne Weg für Drittanbieter-Anwendungen und\nIntegrationsplattformen (Zapier, Make, n8n), um im Namen eines Mailpro-Benutzers\nmit scoped, widerrufbaren Access-Tokens zu agieren.\n\n- **authorizationCode + PKCE** (S256, für öffentliche Clients zwingend erforderlich) — der\n  „Connect Mailpro“-Einwilligungsablauf. Stellt ein Access-Token und ein rotierendes\n  Refresh-Token aus.\n- **clientCredentials** — Maschine-zu-Maschine, ohne Benutzerbeteiligung.\n\nEin einziger Autorisierungsserver für alle APIs, an der versionsneutralen Schnittstelle\n`https://api.mailpro.com/oauth/` (Issuer / `iss`-Claim\n`https://api.mailpro.com/oauth/`). Access-Tokens sind RS256-JWTs\n(Verifizierung gegen das JWKS unter `https://api.mailpro.com/oauth/.well-known/jwks`);\nTTL **20 Minuten**. Refresh-Tokens sind **30 Tage** gültig (gleitend) und\n**einmalig verwendbar** (bei jedem Refresh rotiert). Autorisierungscodes leben\n**60 Sekunden**.\n\nDasselbe OAuth-Access-Token wird von allen drei Mailpro-APIs akzeptiert\n(CRM v3, Email v2, SMS) — einmal authentifizieren, jede beliebige API aufrufen; der Zugriff wird\ndurch die Scopes des Tokens geregelt, nicht durch die API-Basis-URL. Die Legacy-Authentifizierung\n(Bearer JWT / IdClient+ApiKey) funktioniert weiterhin unverändert und unterliegt KEINER\nScope-Beschränkung.\n",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://api.mailpro.com/oauth/authorize",
            "tokenUrl": "https://api.mailpro.com/oauth/token",
            "refreshUrl": "https://api.mailpro.com/oauth/token",
            "scopes": {
              "contacts:read": "View your contacts, lists, tags, segments and custom fields.",
              "contacts:write": "Create, edit and delete your contacts, lists, tags and custom fields.",
              "email:send": "Send transactional and campaign emails on your behalf.",
              "email:read": "View delivery stats, opens, clicks and bounce history.",
              "email:templates:read": "View your email templates (subject, HTML, plain-text body).",
              "email:templates:write": "Create, edit and delete your email templates.",
              "sms:send": "Send transactional and campaign SMS messages on your behalf.",
              "sms:read": "View SMS credit balance and message history.",
              "sms:contacts:read": "View your SMS phone book.",
              "sms:contacts:write": "Create, edit and delete entries in your SMS phone book.",
              "webhooks:manage": "Subscribe to, edit and remove webhook endpoints for your account.",
              "account:read": "View your account credits, limits and subscription status."
            }
          },
          "clientCredentials": {
            "tokenUrl": "https://api.mailpro.com/oauth/token",
            "scopes": {
              "contacts:read": "View your contacts, lists, tags, segments and custom fields.",
              "contacts:write": "Create, edit and delete your contacts, lists, tags and custom fields.",
              "email:send": "Send transactional and campaign emails on your behalf.",
              "email:read": "View delivery stats, opens, clicks and bounce history.",
              "email:templates:read": "View your email templates (subject, HTML, plain-text body).",
              "email:templates:write": "Create, edit and delete your email templates.",
              "sms:send": "Send transactional and campaign SMS messages on your behalf.",
              "sms:read": "View SMS credit balance and message history.",
              "sms:contacts:read": "View your SMS phone book.",
              "sms:contacts:write": "Create, edit and delete entries in your SMS phone book.",
              "webhooks:manage": "Subscribe to, edit and remove webhook endpoints for your account.",
              "account:read": "View your account credits, limits and subscription status."
            }
          }
        }
      },
      "IdClientHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "IdClient",
        "description": "Ihre numerische Mailpro-Client-ID — bevorzugter Übertragungsweg (HTTP-Header).\nURLs werden von Webservern, Cloudflare und Proxys protokolliert, sodass Anmeldedaten\nin der Abfragezeichenfolge in Zugriffsprotokollen offengelegt werden können. Header werden nicht protokolliert.\n"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "ApiKey",
        "description": "Ihr API-Schlüssel (GUID) — bevorzugter Übertragungsweg (HTTP-Header)."
      },
      "IdClientQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "IdClient",
        "description": "Ihre numerische Mailpro-Client-ID — veraltet, aus Gründen der Abwärtskompatibilität beibehalten.\nWechseln Sie nach Möglichkeit zum `IdClient`-Header.\n"
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "ApiKey",
        "description": "Ihr API-Schlüssel (GUID) — veraltet, aus Gründen der Abwärtskompatibilität beibehalten."
      }
    },
    "schemas": {
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "JWT-Access-Token — verwenden Sie es bei allen nachfolgenden Anfragen als `Authorization: Bearer <token>`"
          },
          "token_type": {
            "type": "string",
            "example": "bearer"
          },
          "expires_in": {
            "type": "integer",
            "description": "Token-Gültigkeitsdauer in Sekunden",
            "example": 31535999
          },
          "userName": {
            "type": "string",
            "description": "Client-ID des authentifizierten Benutzers",
            "example": "12345"
          },
          "refresh_token": {
            "type": "string",
            "description": "Token, um ein neues Access-Token ohne erneute Authentifizierung zu erhalten"
          },
          "application": {
            "type": "string",
            "description": "Name der Integration (nur für Drittanbieter-Grants)",
            "nullable": true
          }
        }
      },
      "Contact": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Eindeutige Kennung des Kontakts (UUID)",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          "email": {
            "type": "string",
            "description": "E-Mail-Adresse des Kontakts",
            "example": "alice@example.com"
          },
          "phone_number": {
            "type": "string",
            "description": "Telefonnummer — akzeptiert `+41…`, `0041…` oder `41…` mit oder ohne Trennzeichen. Siehe **Telefonnummernformat** in der API-Beschreibung.",
            "example": "+41791234567"
          },
          "tags": {
            "type": "array",
            "description": "Tags, die diesem Kontakt zugewiesen sind (enthalten, wenn `includeTags=true`)",
            "items": {
              "$ref": "#/components/schemas/TagRef"
            }
          },
          "lists": {
            "type": "array",
            "description": "Listen, denen dieser Kontakt angehört (enthalten, wenn `includeLists=true`)",
            "items": {
              "$ref": "#/components/schemas/ListRef"
            }
          },
          "custom_fields": {
            "type": "array",
            "description": "Werte benutzerdefinierter Felder für diesen Kontakt",
            "items": {
              "$ref": "#/components/schemas/FieldValue"
            }
          }
        }
      },
      "ContactEntry": {
        "type": "object",
        "required": [
          "email",
          "lists"
        ],
        "properties": {
          "email": {
            "type": "string",
            "description": "E-Mail-Adresse des Kontakts (erforderlich, muss eindeutig sein)",
            "example": "alice@example.com"
          },
          "phone_number": {
            "type": "string",
            "description": "Telefonnummer — akzeptiert `+41…`, `0041…` oder `41…` mit oder ohne Trennzeichen.\nMuss mit einem gültigen Ländercode beginnen. Maximal 12 Ziffern für Kontakte (siehe\n**Telefonnummernformat** in der API-Beschreibung für die vollständigen Regeln).\n",
            "example": "+41791234567"
          },
          "lists": {
            "type": "array",
            "description": "Listen, denen dieser Kontakt zugewiesen werden soll. **Mindestens eine Liste ist erforderlich.**",
            "items": {
              "$ref": "#/components/schemas/ListRef"
            },
            "example": [
              {
                "id": 101
              }
            ]
          },
          "tags": {
            "type": "array",
            "description": "Tags, die diesem Kontakt zugewiesen werden sollen (optional)",
            "items": {
              "$ref": "#/components/schemas/TagRef"
            },
            "example": [
              {
                "id": 5
              }
            ]
          },
          "custom_fields": {
            "type": "array",
            "description": "Werte benutzerdefinierter Felder für diesen Kontakt (optional)",
            "items": {
              "$ref": "#/components/schemas/FieldValue"
            },
            "example": [
              {
                "id": 1,
                "value": "Alice"
              },
              {
                "id": 2,
                "value": "Dupont"
              }
            ]
          }
        }
      },
      "TagRef": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Tag-ID (aus `GET /Tag`)",
            "example": 5
          }
        }
      },
      "ListRef": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Listen-ID (aus `GET /List`)",
            "example": 101
          }
        }
      },
      "FieldValue": {
        "type": "object",
        "required": [
          "id"
        ],
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "ID des benutzerdefinierten Felds (aus `GET /Field`)",
            "example": 1
          },
          "value": {
            "type": "string",
            "description": "Wert, der für dieses Feld gespeichert werden soll. Der Typ muss dem Feldtyp entsprechen.",
            "example": "Alice"
          }
        }
      },
      "List": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Eindeutige Kennung der Liste",
            "example": 101
          },
          "name": {
            "type": "string",
            "description": "Anzeigename der Liste",
            "example": "Newsletter subscribers"
          },
          "total_contacts": {
            "type": "integer",
            "description": "Gesamtzahl der Kontakte in der Liste (enthalten, wenn `includeTotalContacts=true`)",
            "example": 4521
          },
          "date_creation": {
            "type": "string",
            "format": "date-time",
            "example": "2025-01-15T10:30:00"
          }
        }
      },
      "ListEntry": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Anzeigename für die Liste",
            "example": "Newsletter subscribers — France"
          }
        }
      },
      "Tag": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Eindeutige Kennung des Tags",
            "example": 5
          },
          "name": {
            "type": "string",
            "description": "Anzeigename des Tags",
            "example": "VIP customers"
          }
        }
      },
      "TagEntry": {
        "type": "object",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Anzeigename für das Tag",
            "example": "VIP customers"
          }
        }
      },
      "Field": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Eindeutige Kennung des benutzerdefinierten Felds",
            "example": 1
          },
          "name": {
            "type": "string",
            "description": "Interner Name des Felds",
            "example": "first_name"
          },
          "personalisation_key": {
            "type": "string",
            "description": "Der Variablenname, der für die Personalisierung in E-Mail-Vorlagen verwendet wird (z. B. `{{first_name}}`)",
            "example": "first_name"
          },
          "field_type": {
            "type": "string",
            "description": "Datentyp des Felds",
            "enum": [
              "text",
              "number",
              "date"
            ],
            "example": "text"
          }
        }
      },
      "FieldEntry": {
        "type": "object",
        "required": [
          "name",
          "id_field_type",
          "personalize_key"
        ],
        "properties": {
          "name": {
            "type": "string",
            "description": "Anzeigename des Feldes",
            "example": "First name"
          },
          "id_field_type": {
            "type": "integer",
            "description": "ID des Feldtyps (verfügbare Typen über `GET /Field/Types`):\n- `1` = Text\n- `2` = Ganzzahl\n- `3` = Datum und Uhrzeit\n- `4` = Ja / Nein\n- `12` = Dezimalzahl\n",
            "example": 1
          },
          "personalize_key": {
            "type": "string",
            "description": "Variablenschlüssel der Vorlage, um das Feld in eine Nachricht einzufügen",
            "example": "first_name"
          },
          "sort": {
            "type": "integer",
            "minimum": 0,
            "maximum": 255,
            "description": "Anzeigereihenfolge (0 bis 255). Pflicht beim Ändern eines Feldes (`PUT /Field/{id}`).",
            "example": 255
          }
        }
      },
      "CampaignEntry": {
        "type": "object",
        "properties": {
          "campaign_title": {
            "type": "string",
            "description": "Anzeigename für die Kampagne",
            "example": "Spring Newsletter April 2026"
          },
          "date_planned": {
            "type": "string",
            "format": "date-time",
            "description": "Geplante Sendezeit (ISO 8601). Weglassen, um sofort zu senden.",
            "example": "2026-04-20T09:00:00"
          }
        }
      },
      "SendEmailRequest": {
        "type": "object",
        "description": "Anfrage für eine transaktionale E-Mail. Geben Sie **entweder** `email` (inline angegebene Adresse) **oder**\n`id_contact` (CRM-Kontakt) an — nicht beides.\nGeben Sie **entweder** `body_html` (inline angegebenes HTML) **oder** `id_message` (gespeicherte Vorlage) an — nicht beides.\n",
        "properties": {
          "id_sender_email": {
            "type": "integer",
            "description": "ID der Absender-E-Mail-Adresse (aus `GET /SenderEmail`). Erforderlich.",
            "example": 201
          },
          "email": {
            "type": "string",
            "description": "E-Mail-Adresse des Empfängers (inline). Geben Sie dies **ODER** `id_contact` an.\nWenn beide angegeben sind, hat `id_contact` Vorrang.\n\n**Der lokale Teil** (vor dem `@`) akzeptiert Buchstaben, Ziffern und `. _ - +` —\neinschließlich RFC-5322-Sub-Addressing (`user+tag@domain`, z. B. Gmail, Fastmail,\nProton). Andere von RFC 5322 erlaubte Sonderzeichen\n(z. B. `! # $ % & ' * / = ? ^ { | } ~`) sowie lokale Teile in Anführungszeichen\nwerden **nicht** akzeptiert.\n",
            "example": "alice@example.com"
          },
          "id_contact": {
            "type": "string",
            "format": "uuid",
            "description": "ID des CRM-Empfängerkontakts. Geben Sie diese **ODER** `email` an.\nDie Verwendung von `id_contact` ermöglicht die Personalisierung mit den Werten der benutzerdefinierten Felder des Kontakts.\n",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          "subject": {
            "type": "string",
            "description": "Betreffzeile der E-Mail (maximal 255 Zeichen). Erforderlich.",
            "example": "Your order #12345 has been shipped"
          },
          "body_html": {
            "type": "string",
            "description": "Inline-HTML-Inhalt. Geben Sie diesen **ODER** `id_message` an.\nWenn beide angegeben sind, hat `id_message` Vorrang.\n",
            "example": "<p>Hello {{first_name}}, your order has shipped!</p>"
          },
          "id_message": {
            "type": "integer",
            "description": "ID einer gespeicherten Nachrichtenvorlage (aus `GET /Message`).\nGeben Sie diese **ODER** `body_html` an.\n",
            "example": 501
          },
          "reply_to": {
            "type": "string",
            "description": "Antwortadresse (standardmäßig die Absenderadresse)",
            "example": "support@yourcompany.com"
          },
          "fields": {
            "type": "array",
            "description": "Benutzerdefinierte Personalisierungsfelder (nur in Verbindung mit inline angegebener `email` verwendet, nicht mit `id_contact`)",
            "items": {
              "$ref": "#/components/schemas/FieldValue"
            }
          },
          "date_planned": {
            "type": "string",
            "format": "date-time",
            "description": "Planen Sie den Versand für einen späteren Zeitpunkt. Weglassen, um sofort zu senden.",
            "example": "2026-04-15T14:00:00"
          },
          "attachments": {
            "type": "array",
            "maxItems": 5,
            "description": "Optionale Dateianhänge (max. **5**). Jedes Element ist ein Objekt mit `filename` und Base64-kodiertem `content`. Grenzen: **10 MB pro Datei** und **15 MB insgesamt**, gemessen nach der Base64-Dekodierung. Zulässige Typen: PDF, Word, Excel, PowerPoint, Bilder (JPG, PNG, GIF, WebP), ZIP, CSV, TXT — ausführbare Dateien und Skripte werden abgelehnt. **Abrechnung:** der Versand behält sein übliches 1 Guthaben, plus **1 Guthaben pro 512 KB Anhänge über die ersten 512 KB hinaus** (Anhänge ≤ 512 KB kosten nichts extra).",
            "items": {
              "$ref": "#/components/schemas/EmailAttachment"
            }
          },
          "keep_in_my_files": {
            "type": "boolean",
            "default": false,
            "description": "`false` (Standard): Die Anhänge werden nur für diesen Versand verwendet — sie werden außerhalb\nIhres Kontos gespeichert, zählen nicht zu Ihrem Speicherkontingent und werden nach 35 Tagen\nautomatisch gelöscht. `true`: Die Anhänge werden zusätzlich in den Dateien Ihres Kontos gespeichert (Ordner\n`Secure/Files/Sending/api`) und zählen zu Ihrem Speicherkontingent.\n",
            "example": false
          }
        }
      },
      "EmailAttachment": {
        "type": "object",
        "required": [
          "filename",
          "content"
        ],
        "description": "Ein einzelner E-Mail-Dateianhang mit Base64-kodiertem Inhalt.",
        "properties": {
          "filename": {
            "type": "string",
            "description": "Ursprünglicher Dateiname, der dem Empfänger angezeigt wird, z. B. invoice.pdf.",
            "example": "invoice.pdf"
          },
          "content": {
            "type": "string",
            "format": "byte",
            "description": "Dateiinhalt, Base64-kodiert.",
            "example": "JVBERi0xLjQKJVBERi0xLjQK..."
          }
        }
      },
      "SendCampaignRequest": {
        "type": "object",
        "required": [
          "id_message",
          "id_sender_email",
          "lists",
          "campaign_title"
        ],
        "properties": {
          "id_message": {
            "type": "integer",
            "description": "ID der zu verwendenden Nachrichtenvorlage (aus `GET /Message`)",
            "example": 501
          },
          "id_sender_email": {
            "type": "integer",
            "description": "ID der Absenderadresse (aus `GET /SenderEmail`)",
            "example": 201
          },
          "id_email_reply_to": {
            "type": "integer",
            "description": "ID der Antwort-Absenderadresse (aus `GET /SenderEmail`). Muss eine der Absenderadressen Ihres Kontos sein, andernfalls wird die Anfrage abgelehnt. Standard: `id_sender_email`.",
            "example": 201
          },
          "lists": {
            "type": "array",
            "description": "Ziel-Kontaktlisten (mindestens eine erforderlich)",
            "items": {
              "$ref": "#/components/schemas/ListRef"
            },
            "example": [
              {
                "id": 101
              }
            ]
          },
          "id_segment": {
            "type": "integer",
            "description": "Empfänger nach einem gespeicherten Segment filtern (optional)",
            "example": 7
          },
          "campaign_title": {
            "type": "string",
            "description": "Anzeigename für diese Kampagne (maximal 150 Zeichen)",
            "example": "Spring Newsletter April 2026"
          },
          "date_planned": {
            "type": "string",
            "format": "date-time",
            "description": "Geplante Sendezeit (ISO 8601). Weglassen, um sofort zu senden.",
            "example": "2026-04-20T09:00:00"
          },
          "id_automation": {
            "type": "integer",
            "description": "Verknüpft diesen Versand mit einem Automatisierungs-Workflow (optional)",
            "example": 3
          }
        }
      },
      "SmsSingleRequest": {
        "type": "object",
        "required": [
          "phone_number",
          "message"
        ],
        "properties": {
          "phone_number": {
            "type": "string",
            "description": "Telefonnummer des Empfängers — akzeptiert `+41…`, `0041…` oder `41…` mit oder ohne Trennzeichen. Siehe **Telefonnummernformat** in der API-Beschreibung.",
            "example": "+41791234567"
          },
          "message": {
            "type": "string",
            "description": "SMS-Nachrichtentext (maximal 160 Zeichen für Standardkodierung)",
            "example": "Your verification code is 9473. Valid for 10 minutes."
          },
          "date_planned": {
            "type": "string",
            "format": "date-time",
            "description": "Planen Sie den Versand. Weglassen, um sofort zu senden.",
            "example": "2026-04-15T14:00:00"
          }
        }
      },
      "SmsCampaignRequest": {
        "type": "object",
        "required": [
          "lists",
          "message"
        ],
        "properties": {
          "lists": {
            "type": "array",
            "description": "Ziel-Kontaktlisten (verwendet das Feld phone_number jedes Kontakts)",
            "items": {
              "$ref": "#/components/schemas/ListRef"
            },
            "example": [
              {
                "id": 101
              }
            ]
          },
          "message": {
            "type": "string",
            "description": "SMS-Nachrichtentext",
            "example": "Flash sale today — 20% off all products. Shop at mailpro.com"
          },
          "date_planned": {
            "type": "string",
            "format": "date-time",
            "description": "Planen Sie den Versand. Weglassen, um sofort zu senden.",
            "example": "2026-04-20T10:00:00"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "Message": {
            "type": "string",
            "description": "Für Menschen lesbare Fehlermeldung",
            "example": "Contact cannot be created. Email cannot be empty."
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "Webhook-ID (Mailpro)",
            "example": 42
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS-Endpunkt, der Ereignisse empfängt",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Abonnierte Ereignistypen",
            "example": [
              "email.delivered",
              "email.bounced",
              "contact.created"
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "Frei wählbare Beschreibung (für Ihre eigene Referenz)",
            "example": "Slack integration"
          },
          "isActive": {
            "type": "boolean",
            "description": "Wenn `false`, wird kein Ereignis zugestellt. Wird nach 10 aufeinanderfolgenden Fehlversuchen automatisch deaktiviert.",
            "example": true
          },
          "consecutiveFailures": {
            "type": "integer",
            "description": "Anzahl der aufeinanderfolgenden fehlgeschlagenen Zustellversuche (wird bei Erfolg zurückgesetzt)",
            "example": 0
          },
          "autoDisabledAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wird gesetzt, wenn `isActive` automatisch auf `false` umgeschaltet wurde"
          },
          "autoDisabledReason": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS-Endpunkt (HTTP wird in der Produktion abgelehnt)",
            "example": "https://example.com/hooks/mailpro"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50,
            "description": "Liste der Ereignistypen, die abonniert werden sollen (siehe Katalog oben). Verwenden Sie `[\"*\"]`, um alle Ereignisse dieser API zu abonnieren.",
            "example": [
              "email.delivered",
              "email.bounced",
              "contact.created"
            ]
          },
          "description": {
            "type": "string",
            "maxLength": 500,
            "description": "Frei wählbare Beschreibung für Ihre Referenz",
            "example": "Slack integration"
          }
        }
      },
      "WebhookCreateResponse": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Webhook"
          },
          {
            "type": "object",
            "properties": {
              "secret": {
                "type": "string",
                "description": "HMAC-Secret. **Wird hier einmal angezeigt, nie wieder.** Speichern Sie es serverseitig — es wird zum Signieren jedes an Ihre URL gesendeten Payloads verwendet.",
                "example": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
              }
            }
          }
        ]
      },
      "WebhookUpdate": {
        "type": "object",
        "description": "Teilaktualisierung — jedes Feld ist optional.",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 1,
            "maxItems": 50
          },
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "isActive": {
            "type": "boolean",
            "description": "Setzen Sie auf `true`, um einen automatisch deaktivierten Webhook wieder zu aktivieren, sobald Ihr Endpunkt repariert ist."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "format": "int64",
            "description": "ID des Zustellversuchs"
          },
          "eventId": {
            "type": "string",
            "description": "Ereignis-UUID (= das Feld `id` im Payload, das Ihr Endpunkt empfangen hat)",
            "example": "evt_8f3a9b2c4d1e5f6789abcdef01234567"
          },
          "eventType": {
            "type": "string",
            "example": "email.delivered"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "retrying",
              "failed"
            ],
            "description": "Aktueller Status dieser Zustellung"
          },
          "statusCode": {
            "type": "integer",
            "nullable": true,
            "description": "HTTP-Statuscode, der von Ihrem Endpunkt empfangen wurde (`null`, wenn noch kein Versuch erfolgt ist oder bei Timeout)",
            "example": 200
          },
          "responseTimeMs": {
            "type": "integer",
            "nullable": true,
            "example": 142
          },
          "attemptCount": {
            "type": "integer",
            "description": "Anzahl der bisherigen Versuche (1–7, danach dauerhaft fehlgeschlagen)"
          },
          "lastError": {
            "type": "string",
            "nullable": true,
            "description": "Erste 2 KB des Antwort-Bodys oder der Ausnahmemeldung bei einem fehlgeschlagenen Versuch"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "lastAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "nextAttemptAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Wann der nächste Wiederholungsversuch stattfindet — `null`, wenn die Zustellung erfolgreich war oder dauerhaft aufgegeben wurde."
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Authentication",
      "description": "Beziehen Sie ein Bearer-JWT-Token, um sich für alle anderen API-Aufrufe zu authentifizieren.\nDer Token-Endpunkt akzeptiert mehrere Grant-Typen: `password`, `refresh_token`,\n`client_credentials` und Drittanbieter-Integrationen (`zapier`, `automateio`, `microsoft-flow`).\n"
    },
    {
      "name": "Account",
      "description": "Rufen Sie das Kontoprofil, den Guthabenstand und Abonnementdetails ab."
    },
    {
      "name": "Contact",
      "description": "Vollständiges CRUD für CRM-Kontakte. Kontakte speichern eine E-Mail-Adresse, optional eine Telefonnummer,\nWerte benutzerdefinierter Felder und gehören einer oder mehreren **Listen** an. Sie können auch mit **Tags** versehen werden.\nKontakt-IDs sind UUIDs.\n"
    },
    {
      "name": "List",
      "description": "Verwalten Sie Kontaktlisten. Listen gruppieren Kontakte für Kampagnen und Segmentierung.\nMaximal 1.000 Listen pro Konto (gleiche Grenze für die drei Mailpro-APIs und in der App). Maximal 1.000.000 Kontakte pro Liste.\n"
    },
    {
      "name": "Tag",
      "description": "Verwalten Sie Tags zur Kennzeichnung und Segmentierung von Kontakten.\nTags sind flache Labels (z. B. „VIP“, „Churned“, „B2B“).\nMaximal 1.000 Tags pro Konto.\n"
    },
    {
      "name": "Field",
      "description": "Verwalten Sie benutzerdefinierte Kontaktfelder. Mit Feldern können Sie zusätzliche Daten zu jedem Kontakt speichern\n(z. B. Vorname, Stadt, Treuestufe). Maximal 50 Felder pro Konto.\nFeldtypen: `text`, `number`, `date`.\n"
    },
    {
      "name": "Message",
      "description": "Verwalten Sie HTML-E-Mail-Vorlagen. Vorlagen speichern den Betreff, den HTML-Body\nund die Einstellungen für den Abmeldelink. Vorlagen können kampagnenübergreifend wiederverwendet werden.\n"
    },
    {
      "name": "Campaign",
      "description": "Zeigen Sie Kampagnenstatistiken an und verwalten Sie geplante Kampagnen.\nKampagnen können bis 5 Minuten vor dem geplanten Sendezeitpunkt bearbeitet oder gelöscht werden.\n"
    },
    {
      "name": "Send",
      "description": "Versenden Sie E-Mail-Massenkampagnen (an Kontaktlisten) und einzelne transaktionale E-Mails.\nKampagnen können geplant oder sofort versendet werden.\n"
    },
    {
      "name": "Sender Addresses",
      "description": "Verwalten Sie validierte Absender-E-Mail-Adressen. Nur verifizierte Adressen können als `From` verwendet werden.\n"
    },
    {
      "name": "History",
      "description": "Durchsuchen Sie das Protokoll vergangener E-Mail- und SMS-Versendungen."
    },
    {
      "name": "Segment",
      "description": "Verwalten Sie dynamische Segmente — gespeicherte Filterregeln, die Kontakte automatisch\nauf Basis von Feldwerten, Verhalten oder Listenzugehörigkeit auswählen.\n"
    },
    {
      "name": "SMS",
      "description": "Senden Sie SMS-Nachrichten an einzelne Kontakte oder an ganze Kontaktlisten.\nVerwendet das Feld `phone_number` jedes Kontakts.\n"
    },
    {
      "name": "Folders",
      "description": "Organisieren Sie Nachrichtenvorlagen in Ordnern."
    },
    {
      "name": "Import",
      "description": "Laden Sie eine CSV- oder XLSX-Datei hoch, um Kontakte massenhaft in eine Liste zu importieren.\nDie Datei wird zur asynchronen Verarbeitung in die Warteschlange eingereiht — verfolgen Sie den Abschluss über\ndie zurückgegebene `import_job_id` oder über den optionalen `webhook_url`-Callback.\n"
    },
    {
      "name": "Webhooks",
      "description": "Abonnieren Sie mit Ihrem Server Echtzeit-Ereignisbenachrichtigungen. Mailpro sendet einen\nHMAC-signierten JSON-Payload per POST an Ihre URL, sobald das abonnierte Ereignis eintritt.\nIm Abschnitt „Webhooks“ der Einführung finden Sie den vollständigen Ereigniskatalog,\ndie Payload-Hülle, Codebeispiele zur Signaturprüfung und die Wiederholungsrichtlinie.\n"
    },
    {
      "name": "Suppression",
      "description": "Bounces und Abmeldungen des Kontos: auflisten, hinzufügen, entfernen."
    }
  ],
  "paths": {
    "/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "operationId": "getAccessToken",
        "summary": "Access-Token abrufen",
        "security": [],
        "description": "Bezieht ein Bearer-JWT-Token mithilfe von Client-Anmeldedaten.\nÜbergeben Sie das zurückgegebene `access_token` als `Authorization: Bearer <token>` in allen nachfolgenden Anfragen.\n\n### Unterstützte Grant-Typen\n\n| Grant-Typ | Anwendungsfall |\n|------------|----------|\n| `password` | Standardintegration — Benutzername + API-Schlüssel |\n| `refresh_token` | Erneuern eines ablaufenden Access-Tokens ohne erneute Authentifizierung |\n| `client_credentials` | Server-zu-Server nur mit Client-ID |\n| `zapier` / `automateio` / `microsoft-flow` | Integrationen mit Drittanbieter-Plattformen |\n\n### Token-Gültigkeitsdauer\n- Access-Token: **30 Tage**\n- Refresh-Token: **90 Tage**\n\nVerwenden Sie `grant_type=refresh_token`, um ein frisches Access-Token ohne\nerneute Authentifizierung zu erhalten — Ihr SDK sollte dies automatisch tun, wenn das\nAccess-Token kurz vor dem Ablauf steht (typische Strategie: Erneuerung, wenn weniger\nals 24 h verbleiben).\n\n### Tokens sicher speichern\nAuch bei einer Gültigkeitsdauer von 30 Tagen kann jede Person, die in den Besitz eines `access_token` kommt,\nIhr Konto bis zu dessen Ablauf imitieren. Speichern Sie Tokens in einem serverseitigen\nSecret-Store (Vault, AWS Secrets Manager, Azure Key Vault, Umgebungs-\nvariablen auf einem gehärteten Host). **Niemals** ein Token einbetten in:\n- clientseitiges JavaScript oder ein beliebiges Browser-Bundle\n- mobile Apps, die an Endbenutzer ausgeliefert werden (die Binärdatei kann inspiziert werden)\n- öffentliche Git-Repositorys oder CI-Build-Logs\nWenn ein Token offengelegt wurde, widerrufen Sie es über die Einstellungen Ihres Mailpro-Kontos und\nfordern Sie ein neues an.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "description": "Authentifizierungs-Grant-Typ",
                    "enum": [
                      "password",
                      "refresh_token",
                      "client_credentials",
                      "zapier",
                      "automateio",
                      "microsoft-flow"
                    ],
                    "example": "password"
                  },
                  "username": {
                    "type": "string",
                    "description": "Ihr Mailpro-Benutzername (E-Mail). Erforderlich für den `password`-Grant.",
                    "example": "user@yourcompany.com"
                  },
                  "password": {
                    "type": "string",
                    "description": "Ihr Mailpro-API-Schlüssel (GUID-Format). Erforderlich für den `password`-Grant.",
                    "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "Vorheriges Refresh-Token. Erforderlich für den `refresh_token`-Grant."
                  },
                  "client_id": {
                    "type": "string",
                    "description": "Ihre Mailpro-Client-ID (Ganzzahl). Erforderlich für den `client_credentials`-Grant.",
                    "example": "12345"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token erfolgreich ausgestellt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "token_type": "bearer",
                  "expires_in": 31535999,
                  "userName": "12345",
                  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "application": null
                }
              }
            }
          },
          "400": {
            "description": "Ungültige Anmeldedaten oder nicht unterstützter Grant-Typ",
            "content": {
              "application/json": {
                "examples": {
                  "invalid_grant": {
                    "summary": "Falsche Anmeldedaten",
                    "value": {
                      "error": "invalid_grant",
                      "error_description": "The username or password is incorrect."
                    }
                  },
                  "no_api_access": {
                    "summary": "Kein API-Zugriff",
                    "value": {
                      "error": "no_api_access",
                      "error_description": "The account doesn't have API access."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/Account/Me": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getCrmAccountMe",
        "summary": "Kontodetails abrufen",
        "description": "Gibt die Profildetails und Einstellungen des authentifizierten Mailpro-Kontos zurück.",
        "responses": {
          "200": {
            "description": "Kontodetails erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Account/Credits": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getCrmAccountCredits",
        "summary": "Guthabenstand abrufen",
        "description": "Gibt das verbleibende E-Mail- und SMS-Guthaben des Kontos zurück.",
        "responses": {
          "200": {
            "description": "Guthabenstand erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": {
                  "email_credits": 48500,
                  "sms_credits": 1200
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Account/SubscriptionEndDate": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getCrmSubscriptionEndDate",
        "summary": "Abonnement-Enddatum abrufen",
        "description": "Gibt das Ablaufdatum des aktuellen Mailpro-Abonnements zurück.",
        "responses": {
          "200": {
            "description": "Abonnement-Enddatum erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Account/Limits": {
      "get": {
        "tags": [
          "Account"
        ],
        "operationId": "getCrmAccountLimits",
        "summary": "Monatliches API-Kontingent abrufen",
        "description": "Gibt das monatliche API-Anfragekontingent für den authentifizierten Client zurück.\n\n**Kontingentberechnung:** Das Limit wird aus den E-Mail-\nAbonnementguthaben kalibriert (typischerweise `subscription_credits × 5`). Für\neinen Tarif mit 10.000 E-Mails/Monat ergibt dies ein monatliches Budget von 50.000 Anfragen. Die exakte Zuordnung wird vom Abrechnungsjob bei der\nAbonnementregistrierung festgelegt und am **Jahrestag des Abonnements** zurückgesetzt (nicht am\n1. des Kalendermonats).\n\n**Was Guthaben verbraucht:**\n- Jede authentifizierte API-Anfrage an die Endpunkte `v2`, `v3` oder `sms`\n  (jeder Aufruf = 1 Guthaben, unabhängig vom Ergebnis — sowohl 2xx als auch die meisten\n  fachlichen 4xx-Fehler zählen).\n- Jedes Webhook-Ereignis, das an einen abonnierten Endpunkt zugestellt wird\n  (z. B. `contact.created`, das an Ihren abonnierten Webhook ausgelöst wird = 1 Guthaben\n  zusätzlich zum auslösenden API-Aufruf).\n\n**Was KOSTENLOS ist (verbraucht kein Guthaben):**\n- `/health`-Endpunkte (Monitoring).\n- Anfragen, die mit `401` (Authentifizierungsfehler), `403` (verboten) oder\n  `429` (Rate-Limit überschritten) fehlschlagen.\n- Webhook-Ereignisse für Clients ohne passendes Abonnement\n  (zwischengespeicherter Kurzschluss — keine Auswirkung auf das Kontingent).\n",
        "security": [
          {
            "BearerAuth": []
          },
          {
            "LegacyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Kontingent-Snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "monthly_limit": {
                      "type": "integer",
                      "description": "Gesamtguthaben, das für den aktuellen Abrechnungsmonat zugewiesen wurde.",
                      "example": 50000
                    },
                    "remaining": {
                      "type": "integer",
                      "description": "Vor dem nächsten Reset noch verfügbares Guthaben.",
                      "example": 32847
                    },
                    "used": {
                      "type": "integer",
                      "description": "Seit dem letzten Reset verbrauchtes Guthaben (max(0, monthly_limit - remaining)).",
                      "example": 17153
                    },
                    "is_free": {
                      "type": "boolean",
                      "description": "True für Konten der kostenlosen Stufe.",
                      "example": false
                    },
                    "remained_sends_for_free": {
                      "type": "integer",
                      "nullable": true,
                      "description": "Spezifischer Zähler für die kostenlose Stufe. `null` für kostenpflichtige Konten.",
                      "example": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Für dieses Konto wurde kein Kontingent-Datensatz gefunden (neu erstelltes Konto, das noch nie einen API-Aufruf getätigt hat; der Eintrag wird bei der ersten authentifizierten Anfrage angelegt)."
          }
        }
      }
    },
    "/Contact": {
      "post": {
        "tags": [
          "Contact"
        ],
        "operationId": "createContact",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt erstellen",
        "description": "Erstellt einen neuen CRM-Kontakt mit optionalen benutzerdefinierten Feldern, Listenzuweisungen und Tags.\n\n**Erforderlich:**\n- `email` — muss kontoübergreifend eindeutig sein\n- `lists` — mindestens eine Listenzuweisung ist verpflichtend\n\n**Telefonnummern** akzeptieren `+41…`, `0041…` oder `41…` mit oder ohne Trennzeichen\n(maximal 12 Ziffern für Kontakte — siehe **Telefonnummernformat** in der API-Beschreibung).\n\n**Benutzerdefinierte Felder** werden über ihre `id` identifiziert (aus `GET /Field`).\nDie Werte werden gegen den Typ des Felds validiert.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactEntry"
              },
              "example": {
                "email": "alice@example.com",
                "phone_number": "+41791234567",
                "lists": [
                  {
                    "id": 101
                  }
                ],
                "tags": [
                  {
                    "id": 5
                  }
                ],
                "custom_fields": [
                  {
                    "id": 1,
                    "value": "Alice"
                  },
                  {
                    "id": 2,
                    "value": "Dupont"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich erstellt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                }
              }
            }
          },
          "400": {
            "description": "Ungültiges E-Mail-Format"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "406": {
            "description": "Verstoß gegen Geschäftsregel (siehe Beschreibung für die vollständige Liste)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "email_exists": {
                    "summary": "Doppelte E-Mail-Adresse",
                    "value": {
                      "Message": "Contact cannot be created. A contact already exist with the same Email"
                    }
                  },
                  "no_list": {
                    "summary": "Keine Liste angegeben",
                    "value": {
                      "Message": "Contact cannot be created. At least one List is necessary"
                    }
                  },
                  "unsubscribed_forever": {
                    "summary": "Dauerhaft abgemeldet",
                    "value": {
                      "Message": "Contact cannot be created. The email address was unsubscribed permanently"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/Contact/Multiple": {
      "post": {
        "tags": [
          "Contact"
        ],
        "operationId": "createContactsBulk",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakte importieren (Massenvorgang)",
        "description": "Erstellt bis zu **1.000 Kontakte** in einer einzigen Anfrage für einen effizienten Massenimport.\nDie Antwort enthält eine Liste der erfolgreich erstellten Kontakte sowie eine Fehlerliste\nfür Kontakte, die nicht erstellt werden konnten (z. B. doppelte E-Mail-Adresse, ungültige Daten).\n\n**Hinweis:** In Massenimporten verwendete Listen und Tags dürfen **nicht** mit aktiven\nAutomatisierungs-Workflows verknüpft sein. Andernfalls wird der gesamte Import mit HTTP 406 abgelehnt.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ContactEntry"
                },
                "maxItems": 1000
              },
              "example": [
                {
                  "email": "alice@example.com",
                  "lists": [
                    {
                      "id": 101
                    }
                  ],
                  "custom_fields": [
                    {
                      "id": 1,
                      "value": "Alice"
                    }
                  ]
                },
                {
                  "email": "bob@example.com",
                  "lists": [
                    {
                      "id": 101
                    }
                  ],
                  "custom_fields": [
                    {
                      "id": 1,
                      "value": "Bob"
                    }
                  ]
                }
              ]
            }
          }
        },
        "responses": {
          "200": {
            "description": "Massenimport abgeschlossen (prüfen Sie das `errors`-Array auf Teilfehler)",
            "content": {
              "application/json": {
                "example": {
                  "Added": [
                    {
                      "Email": "alice@example.com",
                      "Id": "550e8400-e29b-41d4-a716-446655440000"
                    },
                    {
                      "Email": "bob@example.com",
                      "Id": "660e8400-e29b-41d4-a716-446655440001"
                    }
                  ],
                  "Errors": []
                }
              }
            }
          },
          "400": {
            "description": "Ungültige Eingabe"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "406": {
            "description": "Verstoß gegen Geschäftsregel (z. B. Automatisierungskonflikt, Listenlimit erreicht)"
          }
        }
      }
    },
    "/Contact/{id}": {
      "get": {
        "tags": [
          "Contact"
        ],
        "operationId": "getContact",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt abrufen",
        "description": "Gibt die Details eines bestimmten Kontakts zurück.\nVerwenden Sie `includeTags=true`, um auch die dem Kontakt zugewiesenen Tags zurückzugeben.\nVerwenden Sie `includeLists=true`, um auch die Listen zurückzugeben, denen der Kontakt angehört.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID (aus `POST /Contact` oder `GET /List/{id}/Contact`)",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          {
            "name": "includeTags",
            "in": "query",
            "description": "Auf `true` setzen, um die Tag-Zuweisungen des Kontakts in die Antwort einzubeziehen",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeLists",
            "in": "query",
            "description": "Auf `true` setzen, um die Listenzugehörigkeiten des Kontakts in die Antwort einzubeziehen",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Contact"
                },
                "example": {
                  "id": "550e8400-e29b-41d4-a716-446655440000",
                  "email": "alice@example.com",
                  "phone_number": "41791234567",
                  "custom_fields": [
                    {
                      "id": 1,
                      "value": "Alice"
                    },
                    {
                      "id": 2,
                      "value": "Dupont"
                    }
                  ],
                  "tags": [
                    {
                      "id": 5
                    }
                  ],
                  "lists": [
                    {
                      "id": 101
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt nicht gefunden"
          }
        }
      },
      "put": {
        "tags": [
          "Contact"
        ],
        "operationId": "updateContact",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt aktualisieren",
        "description": "Aktualisiert die E-Mail-Adresse, Telefonnummer, benutzerdefinierten Felder, Listenzuweisungen und Tags eines Kontakts.\nDer Anfrage-Body ersetzt die aktuellen Daten des Kontakts — geben Sie alle Listen und Tags an,\ndenen der Kontakt weiterhin zugewiesen bleiben soll.\n\n**Im Body erforderlich:** `email` und mindestens ein `lists`-Eintrag.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactEntry"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich aktualisiert",
            "content": {
              "application/json": {
                "example": {
                  "Result": "Successful operation"
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt nicht gefunden"
          },
          "422": {
            "description": "Validierungsfehler (E-Mail-Format, Telefonnummer, Typdiskrepanz beim Feldwert)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Contact"
        ],
        "operationId": "deleteContact",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt löschen",
        "description": "Löscht einen Kontakt dauerhaft aus dem CRM.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich gelöscht"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt nicht gefunden"
          }
        }
      }
    },
    "/Contact/{id}/Activity": {
      "get": {
        "tags": [
          "Contact"
        ],
        "operationId": "getCrmContactActivity",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Aktivität eines Kontakts über 90 Tage",
        "description": "Empfangene, geöffnete und angeklickte E-Mails, bevorzugtes E-Mail-Programm und letzte Kampagnen des Kontakts.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "GUID des Kontakts",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Aktivität zurückgegeben",
            "content": {
              "application/json": {
                "example": {
                  "period_days": 90,
                  "email_received": 12,
                  "email_opened": 7,
                  "email_clicked": 2,
                  "favorite_email_client": "Gmail",
                  "last_campaigns": [
                    {
                      "id": 5001,
                      "name": "Spring Sale 2026",
                      "date": "2026-10-01T09:00:00"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Der angeforderte Kontakt existiert nicht"
          }
        }
      }
    },
    "/Contact/{id}/Tag/{tagid}": {
      "put": {
        "tags": [
          "Contact"
        ],
        "operationId": "addTagToContact",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag zu Kontakt hinzufügen",
        "description": "Weist einem Kontakt ein Tag zu. Ist das Tag bereits zugewiesen, ist der Vorgang ein No-Op.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          {
            "name": "tagid",
            "in": "path",
            "required": true,
            "description": "Tag-ID (aus `GET /Tag`)",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Tag erfolgreich zugewiesen"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt oder Tag nicht gefunden"
          }
        }
      },
      "delete": {
        "tags": [
          "Contact"
        ],
        "operationId": "removeTagFromContact",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag von Kontakt entfernen",
        "description": "Entfernt eine Tag-Zuweisung von einem Kontakt.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          {
            "name": "tagid",
            "in": "path",
            "required": true,
            "description": "Tag-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Tag erfolgreich entfernt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt oder Tag nicht gefunden"
          }
        }
      }
    },
    "/Contact/{id}/List/{listid}": {
      "put": {
        "tags": [
          "Contact"
        ],
        "operationId": "addContactToList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt zu Liste hinzufügen",
        "description": "Fügt einen Kontakt einer bestimmten Liste hinzu.\nGibt HTTP 404 zurück, wenn der Kontakt zuvor von dieser Liste abgemeldet wurde.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          {
            "name": "listid",
            "in": "path",
            "required": true,
            "description": "Listen-ID (aus `GET /List`)",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich zur Liste hinzugefügt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt, Liste nicht gefunden oder Kontakt wurde von dieser Liste abgemeldet"
          }
        }
      },
      "delete": {
        "tags": [
          "Contact"
        ],
        "operationId": "removeContactFromList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt aus Liste entfernen",
        "description": "Entfernt einen Kontakt aus einer bestimmten Liste. Der Kontakt selbst wird nicht gelöscht.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Kontakt-UUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          {
            "name": "listid",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt erfolgreich aus Liste entfernt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kontakt oder Liste nicht gefunden"
          }
        }
      }
    },
    "/List": {
      "get": {
        "tags": [
          "List"
        ],
        "operationId": "getLists",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontaktlisten auflisten",
        "description": "Gibt alle Kontaktlisten des Kontos zurück.\nFilterung nach Name oder Erstellungsdatum. Alphabetische Sortierung mit `sortByName=true`.\nMit `includeTotalContacts=true` wird die Gesamtzahl der Kontakte pro Liste mit einbezogen.\n",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Filterung nach Listennamen (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            },
            "example": "newsletter"
          },
          {
            "name": "dateCreationFrom",
            "in": "query",
            "description": "Filterung nach Erstellungsdatum (ab, ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateCreationTo",
            "in": "query",
            "description": "Filterung nach Erstellungsdatum (bis, ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "description": "Einträge pro Seite — standardmäßig und maximal 5.000",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "description": "1-basierte Seitennummer",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "sortByName",
            "in": "query",
            "description": "Auf `true` setzen, um alphabetisch nach Namen zu sortieren",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeTotalContacts",
            "in": "query",
            "description": "Auf `true` setzen, um die Anzahl `total_contacts` in jedem Ergebnis einzubeziehen",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Listen erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 101,
                    "name": "Newsletter subscribers",
                    "total_contacts": 4521,
                    "date_creation": "2025-01-15T10:30:00"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "tags": [
          "List"
        ],
        "operationId": "createList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontaktliste erstellen",
        "description": "Erstellt eine neue Kontaktliste. Maximal 1.000 Listen pro Konto.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListEntry"
              },
              "example": {
                "name": "Spring Campaign 2026"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Liste erfolgreich erstellt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/List"
                },
                "example": {
                  "id": 102,
                  "name": "Spring Campaign 2026",
                  "date_creation": "2026-04-14T12:00:00"
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "406": {
            "description": "Listenlimit (1.000) erreicht"
          }
        }
      }
    },
    "/List/{id}": {
      "get": {
        "tags": [
          "List"
        ],
        "operationId": "getList",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontaktliste abrufen",
        "description": "Gibt die Details einer bestimmten Kontaktliste zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "responses": {
          "200": {
            "description": "Liste erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Liste nicht gefunden"
          }
        }
      },
      "put": {
        "tags": [
          "List"
        ],
        "operationId": "updateList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontaktliste aktualisieren",
        "description": "Benennt eine bestehende Kontaktliste um.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ListEntry"
              },
              "example": {
                "name": "Newsletter subscribers — Europe"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Liste erfolgreich aktualisiert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Liste nicht gefunden"
          }
        }
      },
      "delete": {
        "tags": [
          "List"
        ],
        "operationId": "deleteList",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontaktliste löschen",
        "description": "Löscht eine Kontaktliste dauerhaft.\nDie Kontakte selbst werden nicht gelöscht — nur ihre Zugehörigkeit zu dieser Liste wird entfernt.\nListen, die von aktiven Automatisierungs-Workflows verwendet werden, können nicht gelöscht werden.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "responses": {
          "200": {
            "description": "Liste erfolgreich gelöscht"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Liste nicht gefunden"
          },
          "406": {
            "description": "Liste wird von einem aktiven Automatisierungs-Workflow verwendet"
          }
        }
      }
    },
    "/List/{id}/Contact": {
      "get": {
        "tags": [
          "List"
        ],
        "operationId": "getListContacts",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakte in einer Liste auflisten",
        "description": "Gibt die Kontakte zurück, die einer bestimmten Liste angehören.\nFilterung nach E-Mail oder Hinzufügedatum. Tags und Listenzugehörigkeiten mit den entsprechenden Flags einbeziehen.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          },
          {
            "name": "email",
            "in": "query",
            "description": "Filterung nach E-Mail (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            },
            "example": "@example.com"
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "description": "Einträge pro Seite — standardmäßig und maximal 5.000",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "sortByEmail",
            "in": "query",
            "description": "Alphabetische Sortierung nach E-Mail",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeTags",
            "in": "query",
            "description": "Tag-Zuweisungen in die Ergebnisse einbeziehen",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "includeLists",
            "in": "query",
            "description": "Listenzugehörigkeiten in die Ergebnisse einbeziehen",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakte erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Liste nicht gefunden oder keine Kontakte entsprechen den Kriterien"
          }
        }
      }
    },
    "/List/{listId}/Unsubscribers": {
      "get": {
        "tags": [
          "List"
        ],
        "operationId": "getListUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Abgemeldete auflisten",
        "description": "Gibt die Kontakte zurück, die sich von einer bestimmten Liste abgemeldet haben.",
        "parameters": [
          {
            "name": "listId",
            "in": "path",
            "required": true,
            "description": "Listen-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 101
          }
        ],
        "responses": {
          "200": {
            "description": "Abgemeldete erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Liste nicht gefunden"
          }
        }
      }
    },
    "/Tag": {
      "get": {
        "tags": [
          "Tag"
        ],
        "operationId": "getTags",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tags auflisten",
        "description": "Gibt alle Tags des Kontos zurück.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Filterung nach Name (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "sortByName",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Tags erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 5,
                    "name": "VIP customers"
                  },
                  {
                    "id": 6,
                    "name": "Newsletter openers"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "tags": [
          "Tag"
        ],
        "operationId": "createTag",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag erstellen",
        "description": "Erstellt ein neues Tag. Maximal 1.000 Tags pro Konto.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagEntry"
              },
              "example": {
                "name": "VIP customers"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag erfolgreich erstellt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "406": {
            "description": "Tag-Limit (1.000) erreicht"
          }
        }
      }
    },
    "/Tag/{id}": {
      "get": {
        "tags": [
          "Tag"
        ],
        "operationId": "getTag",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag abrufen",
        "description": "Gibt ein bestimmtes Tag anhand seiner ID zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Tag-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Tag erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Tag nicht gefunden"
          }
        }
      },
      "put": {
        "tags": [
          "Tag"
        ],
        "operationId": "updateTag",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag aktualisieren",
        "description": "Benennt ein bestehendes Tag um.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagEntry"
              },
              "example": {
                "name": "VIP customers — updated"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tag erfolgreich aktualisiert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Tag nicht gefunden"
          }
        }
      },
      "delete": {
        "tags": [
          "Tag"
        ],
        "operationId": "deleteTag",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Tag löschen",
        "description": "Löscht ein Tag dauerhaft. Das Tag wird von allen Kontakten entfernt.\nTags, die von aktiven Automatisierungs-Workflows verwendet werden, können nicht gelöscht werden.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          }
        ],
        "responses": {
          "200": {
            "description": "Tag erfolgreich gelöscht"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Tag nicht gefunden"
          },
          "406": {
            "description": "Tag wird von einem aktiven Automatisierungs-Workflow verwendet"
          }
        }
      }
    },
    "/Tag/{id}/Contact": {
      "get": {
        "tags": [
          "Tag"
        ],
        "operationId": "getTagContacts",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakte mit einem Tag auflisten",
        "description": "Gibt die Kontakte zurück, denen ein bestimmtes Tag zugewiesen wurde.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Tag-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakte erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Tag nicht gefunden"
          }
        }
      }
    },
    "/Field": {
      "get": {
        "tags": [
          "Field"
        ],
        "operationId": "listFields",
        "summary": "Benutzerdefinierte Felder auflisten",
        "description": "Gibt alle für das Konto definierten benutzerdefinierten Kontaktfelder zurück.\nVerwenden Sie die zurückgegebenen `id`-Werte beim Erstellen oder Aktualisieren von Kontakten.\n",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Filterung nach Feldnamen",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idFieldType",
            "in": "query",
            "description": "Filterung nach Feldtyp-ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "sortByName",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Benutzerdefinierte Felder erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 1,
                    "name": "first_name",
                    "personalisation_key": "first_name",
                    "field_type": "text"
                  },
                  {
                    "id": 2,
                    "name": "last_name",
                    "personalisation_key": "last_name",
                    "field_type": "text"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "tags": [
          "Field"
        ],
        "operationId": "createField",
        "summary": "Benutzerdefiniertes Feld erstellen",
        "description": "Erstellt ein neues benutzerdefiniertes Kontaktfeld.\nMaximal 50 Felder pro Konto.\nVerwenden Sie die zurückgegebene `id`, um Kontakten Werte zuzuweisen.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FieldEntry"
              },
              "example": {
                "name": "First name",
                "id_field_type": 1,
                "personalize_key": "first_name"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feld erfolgreich erstellt",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Field"
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "406": {
            "description": "Feldlimit (50) erreicht"
          }
        }
      }
    },
    "/Field/Types": {
      "get": {
        "tags": [
          "Field"
        ],
        "operationId": "listFieldTypes",
        "summary": "Feldtypen auflisten",
        "description": "Gibt die verfügbaren Feldtyp-Kennungen zurück, die beim Erstellen eines benutzerdefinierten Felds zu verwenden sind.\nGängige Typen: `1` = Text, `2` = Zahl, `3` = Datum.\n",
        "responses": {
          "200": {
            "description": "Feldtypen erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Field/{id}": {
      "get": {
        "tags": [
          "Field"
        ],
        "operationId": "getField",
        "summary": "Benutzerdefiniertes Feld abrufen",
        "description": "Gibt die Definition und Metadaten eines bestimmten benutzerdefinierten Felds zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Feld-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Feld erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Feld nicht gefunden"
          }
        }
      },
      "put": {
        "tags": [
          "Field"
        ],
        "operationId": "updateField",
        "summary": "Benutzerdefiniertes Feld aktualisieren",
        "description": "Aktualisiert den Namen oder den Personalisierungsschlüssel eines benutzerdefinierten Felds.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FieldEntry"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feld erfolgreich aktualisiert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Feld nicht gefunden"
          }
        }
      },
      "delete": {
        "tags": [
          "Field"
        ],
        "operationId": "deleteField",
        "summary": "Benutzerdefiniertes Feld löschen",
        "description": "Löscht ein benutzerdefiniertes Feld dauerhaft und entfernt dessen Wert aus allen Kontakten.\nDiese Aktion kann nicht rückgängig gemacht werden.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Feld erfolgreich gelöscht"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Feld nicht gefunden"
          }
        }
      }
    },
    "/Campaign": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "listCrmCampaigns",
        "summary": "Kampagnen auflisten",
        "description": "Gibt eine paginierte Liste der E-Mail-Kampagnen des Kontos zurück.",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 20
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Kampagnen erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 8001,
                    "title": "Spring Newsletter April 2026",
                    "date_planned": "2026-04-20T09:00:01",
                    "count_open": 1823,
                    "count_sent": 4521,
                    "count_click": 342,
                    "count_badmail": 12,
                    "count_unsubscription": 8,
                    "count_clicking_users": 289,
                    "count_complaints": 1,
                    "spam_trap": 0,
                    "deliverability_score": 98
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaign",
        "summary": "Kampagne abrufen",
        "description": "Gibt die Konfiguration und die Statistikzusammenfassung einer bestimmten Kampagne zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Kampagne erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kampagne nicht gefunden"
          }
        }
      },
      "put": {
        "tags": [
          "Campaign"
        ],
        "operationId": "updateCrmCampaign",
        "summary": "Kampagne aktualisieren",
        "description": "Aktualisiert den Titel oder das Sendedatum einer geplanten Kampagne.\nKampagnen können nur bis **5 Minuten vor** dem geplanten Sendezeitpunkt geändert werden.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CampaignEntry"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kampagne erfolgreich aktualisiert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kampagne nicht gefunden"
          }
        }
      },
      "delete": {
        "tags": [
          "Campaign"
        ],
        "operationId": "deleteCrmCampaign",
        "summary": "Kampagne löschen",
        "description": "Storniert und löscht eine Kampagne anhand ihrer Kennung dauerhaft.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Kampagne erfolgreich gelöscht"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kampagne nicht gefunden"
          }
        }
      }
    },
    "/Campaign/Scheduled": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "listScheduledCrmCampaigns",
        "summary": "Meine geplanten Kampagnen auflisten",
        "description": "Gibt Kampagnen mit zukünftigem `date_planned` zurück, die noch nicht\nversendet wurden. Sortiert nach `date_planned` in aufsteigender Reihenfolge.\n",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 5000,
              "maximum": 5000
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Liste der geplanten Kampagnen",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 5001,
                    "id_client": 12345,
                    "subject": "Spring Sale 2026",
                    "date_planned": "2026-05-01T09:00:00",
                    "title": "Spring Sale",
                    "id_campaign": 7001,
                    "id_list": 101,
                    "id_segment": null,
                    "number_email": 1250
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/Cancel": {
      "post": {
        "tags": [
          "Campaign"
        ],
        "operationId": "cancelScheduledCrmCampaign",
        "summary": "Geplante Kampagne stornieren",
        "description": "Storniert eine zukünftig geplante Kampagne. Gibt **409 Conflict** zurück, wenn die\nKampagne bereits versendet wurde oder nicht existiert.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kampagne storniert",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "cancelled": 5001
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "Bereits versendet oder nicht gefunden"
          }
        }
      }
    },
    "/Campaign/{id}/Reschedule": {
      "patch": {
        "tags": [
          "Campaign"
        ],
        "operationId": "rescheduleCrmCampaign",
        "summary": "Geplante Kampagne neu planen",
        "description": "Aktualisiert das geplante Sendedatum einer geplanten Kampagne. Das neue Datum muss\nin der Zukunft und innerhalb von 90 Tagen liegen.\n\n**Name des Body-Felds:** Die API akzeptiert `date_planned` (snake_case, primär)\nsowie die Legacy-Aliasse `PlanDate` und `scheduled_time`. Geben Sie einen beliebigen\ndavon an — der erste nicht-null-Wert wird verwendet.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Geben Sie eines von `date_planned`, `PlanDate` oder `scheduled_time` an.",
                "properties": {
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Primärer Feldname.",
                    "example": "2026-12-31T14:30:00"
                  },
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Aus Gründen der Abwärtskompatibilität akzeptierter Legacy-Alias."
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Aus Gründen der Abwärtskompatibilität akzeptierter Legacy-Alias."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kampagne neu geplant",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "id": 5001,
                  "date_planned": "2026-12-31T14:30:00"
                }
              }
            }
          },
          "400": {
            "description": "Fehlendes Datum — geben Sie eines von date_planned / PlanDate / scheduled_time an"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "Bereits versendet",
            "not found": null,
            "or out of range": null
          }
        }
      }
    },
    "/Campaign/{id}/ByHour": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignStatsByHour",
        "summary": "Statistik nach Stunde",
        "description": "Gibt die stündliche Aufschlüsselung der Öffnungen und Klicks für die Kampagne zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Stündliche Statistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/ByDay": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignStatsByDay",
        "summary": "Statistik nach Tag",
        "description": "Gibt die tägliche Aufschlüsselung der Öffnungen und Klicks für die Kampagne zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Tägliche Statistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/Openings": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignOpenings",
        "summary": "E-Mail-Öffnungen auflisten",
        "description": "Gibt eine paginierte Liste der Kontakte zurück, die die Kampagnen-E-Mail geöffnet haben.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          },
          {
            "name": "email",
            "in": "query",
            "description": "Filterung nach Empfänger-E-Mail",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Öffnungsliste erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/Clicks": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignClicks",
        "summary": "Link-Klicks auflisten",
        "description": "Gibt eine paginierte Liste der Kontakte zurück, die in der Kampagne auf einen Link geklickt haben.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          },
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Klickliste erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/HardBounces": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignHardBounces",
        "summary": "Hard Bounces auflisten",
        "description": "Gibt die E-Mail-Adressen zurück, bei denen während dieser Kampagne ein Hard Bounce aufgetreten ist.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          },
          {
            "name": "email",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Hard-Bounce-Liste erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/Links": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignLinks",
        "summary": "Verfolgte Links auflisten",
        "description": "Gibt die Klick-Leistungsdaten für jeden in der Kampagne verfolgten Link zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          },
          {
            "name": "link",
            "in": "query",
            "description": "Filterung nach Link-URL (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Link-Statistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/OS": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignStatsByOS",
        "summary": "Statistik nach Betriebssystem / Gerät",
        "description": "Gibt die Aufschlüsselung der Öffnungen und Klicks nach Betriebssystem und Gerätetyp zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "BS-Statistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/EmailClients": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignStatsByEmailClient",
        "summary": "Statistik nach E-Mail-Client",
        "description": "Gibt die Aufschlüsselung der Öffnungen nach E-Mail-Client zurück (Gmail, Outlook, Apple Mail…).",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "E-Mail-Client-Statistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Campaign/{id}/Countries": {
      "get": {
        "tags": [
          "Campaign"
        ],
        "operationId": "getCrmCampaignStatsByCountry",
        "summary": "Statistik nach Land",
        "description": "Gibt die geografische Verteilung der Öffnungen und Klicks zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Länderstatistik erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Send/Mail": {
      "post": {
        "tags": [
          "Send"
        ],
        "operationId": "sendTransactionalEmailCrm",
        "summary": "Transaktionale E-Mail senden",
        "description": "Sendet eine einmalige transaktionale E-Mail an einen einzelnen Empfänger.\n\n**Empfänger:** Geben Sie `email` (inline angegebene Adresse) **ODER** `id_contact` (CRM-Kontakt) an — nicht beides.\nDie Verwendung von `id_contact` ermöglicht die automatische Personalisierung mit den Werten der benutzerdefinierten Felder des Kontakts.\n\n**Inhalt:** Geben Sie `body_html` (inline angegebenes HTML) **ODER** `id_message` (gespeicherte Vorlage) an — nicht beides.\nWenn beide angegeben werden, hat `id_message` Vorrang.\n\n**Erforderlich:** `id_sender_email`, `subject` und eines von (`email` oder `id_contact`)\nsowie eines von (`body_html` oder `id_message`).\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendEmailRequest"
              },
              "example": {
                "id_sender_email": 201,
                "email": "alice@example.com",
                "subject": "Your order #12345 has shipped",
                "body_html": "<p>Hello {{first_name}}, your order is on its way!</p>",
                "reply_to": "support@yourcompany.com",
                "fields": [
                  {
                    "id": 1,
                    "value": "Alice"
                  }
                ],
                "attachments": [
                  {
                    "filename": "invoice.pdf",
                    "content": "JVBERi0xLjQKJVBERi0xLjQK..."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-Mail erfolgreich gesendet oder geplant",
            "content": {
              "application/json": {
                "example": {
                  "message": "Successful operation",
                  "id_single_send": 8001
                }
              }
            }
          },
          "400": {
            "description": "Ungültiges E-Mail-Format oder fehlendes Pflichtfeld"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Absender, Nachricht oder Kontakt nicht gefunden; oder Empfänger abgemeldet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "no_credits": {
                    "summary": "Unzureichendes Guthaben",
                    "value": {
                      "Message": "Not enough credit available"
                    }
                  },
                  "unsubscribed": {
                    "summary": "Empfänger abgemeldet",
                    "value": {
                      "Message": "Email address unsubscribed."
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validierungsfehler (Betreff zu lang, Body und Nachricht beide leer usw.)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/Send/{id}/Status": {
      "get": {
        "tags": [
          "Send"
        ],
        "operationId": "getTransactionalStatusCrm",
        "summary": "Zustellstatus einer transaktionalen E-Mail abrufen",
        "description": "Gibt den aktuellen Zustellstatus einer transaktionalen E-Mail zurück, die über `POST /Send/Mail` gesendet wurde. Übergeben Sie die `id_single_send`, die dieser Aufruf zurückgegeben hat.\n\nMögliche Werte: `delivered` (vom Empfängerserver angenommen, siehe `diag_code`), `bounced` (abgelehnt — `bounce_type: hard` ungültige Adresse oder endgültige Ablehnung, `soft` Ablehnung nach erneuten Versuchen), `sent` (an den Mailserver übergeben, noch keine Antwort), `scheduled` (noch nicht gesendet, `date_planned` in der Zukunft) und `queued` (wartet auf den Versand). `delivered` und `bounced` sind endgültig: Beenden Sie die Abfragen. Jede E-Mail hat spätestens 48 Stunden nach dem Versand einen endgültigen Status; fragen Sie höchstens alle 15 Minuten ab (jeder Aufruf zählt für Ihr API-Kontingent) oder nutzen Sie die Webhooks `email.delivered` / `email.bounced`. Nur der Kunde, der die E-Mail gesendet hat, kann ihren Status lesen — jede andere ID liefert 404.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Die von `POST /Send/Mail` zurückgegebene `id_single_send`.",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 8001
          }
        ],
        "responses": {
          "200": {
            "description": "Aktueller Zustellstatus",
            "content": {
              "application/json": {
                "example": {
                  "id_single_send": 8001,
                  "email": "alice@example.com",
                  "status": "delivered",
                  "date_planned": "2026-04-15T14:30:00",
                  "status_date": "2026-04-15T14:30:07",
                  "diag_code": "2.0.0 (success)",
                  "bounce_type": null
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Kein transaktionaler Versand mit dieser ID für diesen Kunden gefunden"
          }
        }
      }
    },
    "/Send/Campaign": {
      "post": {
        "tags": [
          "Send"
        ],
        "operationId": "sendCampaignCrm",
        "summary": "E-Mail-Kampagne senden",
        "description": "Sendet eine E-Mail-Massenkampagne an eine oder mehrere Kontaktlisten.\n\n**Erforderlich:**\n- `id_message` — die zu sendende Vorlage (aus `GET /Message`)\n- `id_sender_email` — die Absenderadresse (aus `GET /SenderEmail`)\n- `lists` — mindestens eine Ziel-Kontaktliste\n- `campaign_title` — Bezeichnung zur Statistik-Nachverfolgung\n\n**Segment:** Optional können Empfänger nach einem gespeicherten Segment gefiltert werden (`id_segment`).\nDas Segment filtert die Kontakte innerhalb der angegebenen Listen.\n\n**Planung:** Setzen Sie `date_planned` auf ein zukünftiges ISO-8601-Datum/-Uhrzeit.\nKampagnen können bis 5 Minuten vor dem geplanten Zeitpunkt bearbeitet oder storniert werden.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendCampaignRequest"
              },
              "example": {
                "id_message": 501,
                "id_sender_email": 201,
                "lists": [
                  {
                    "id": 101
                  }
                ],
                "campaign_title": "Spring Newsletter April 2026",
                "date_planned": "2026-04-20T09:00:00"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Kampagne erfolgreich geplant oder gesendet",
            "content": {
              "application/json": {
                "example": {
                  "Message": "Successful operation. Campaigns can be edited or deleted until 5 minutes prior to send.",
                  "IdCampaign": 8001
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "402": {
            "description": "Unzureichendes Guthaben",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "404": {
            "description": "Nachricht, Absender, Liste oder Segment nicht gefunden; oder unzureichendes Guthaben",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "422": {
            "description": "Kampagnentitel leer oder zu lang (maximal 150 Zeichen)"
          }
        }
      }
    },
    "/Send": {
      "get": {
        "tags": [
          "Send"
        ],
        "operationId": "getSendWaiting",
        "summary": "Geplante Sendungen auflisten",
        "description": "Gibt die Liste der E-Mail-Kampagnen zurück, die auf ihren Versand warten (geplant, noch nicht verarbeitet).",
        "parameters": [
          {
            "name": "subjectMessage",
            "in": "query",
            "description": "Filterung nach Betreff (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Wartende Sendungen erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Send/{id}": {
      "delete": {
        "tags": [
          "Send"
        ],
        "operationId": "deleteSendWaiting",
        "summary": "Geplante Sendung stornieren",
        "description": "Storniert und löscht eine geplante E-Mail-Sendung, die noch nicht verarbeitet wurde.\nSendungen, die gerade verarbeitet werden, können nicht storniert werden.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Sendungs-ID (aus `GET /Send`)",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 3001
          }
        ],
        "responses": {
          "200": {
            "description": "Geplante Sendung erfolgreich storniert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Geplante Sendung nicht gefunden"
          }
        }
      }
    },
    "/Send/Mail/Scheduled": {
      "get": {
        "tags": [
          "Send"
        ],
        "operationId": "listScheduledCrmMails",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Geplante Einzel-E-Mails auflisten",
        "description": "Gibt die mit `POST /Send/Mail` und einem zukünftigen Datum gesendeten Einzel-E-Mails zurück, die noch nicht versendet wurden. Kampagnen werden von `GET /Campaign/Scheduled` aufgelistet.",
        "responses": {
          "200": {
            "description": "Geplante E-Mails zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id_single_send": 880123,
                    "email": "jane@example.com",
                    "subject": "Your invoice",
                    "date_planned": "2026-12-01T09:00:00"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Send/Mail/{id}/Cancel": {
      "post": {
        "tags": [
          "Send"
        ],
        "operationId": "cancelCrmMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Geplante Einzel-E-Mail stornieren",
        "description": "Storniert die E-Mail, solange sie noch nicht versendet wurde.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Von `POST /Send/Mail` zurückgegebene `id_single_send`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "E-Mail storniert",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "cancelled": 880123
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "Versand nicht gefunden oder bereits erfolgt"
          }
        }
      }
    },
    "/Send/Mail/{id}/Reschedule": {
      "patch": {
        "tags": [
          "Send"
        ],
        "operationId": "rescheduleCrmMail",
        "security": [
          {
            "OAuth2": [
              "email:send"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Geplante Einzel-E-Mail neu planen",
        "description": "Ändert das Versanddatum. Das neue Datum muss in der Zukunft und innerhalb von 90 Tagen liegen. `POST` wird ebenfalls akzeptiert.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Von `POST /Send/Mail` zurückgegebene `id_single_send`",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "date_planned"
                ],
                "properties": {
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Neues Versanddatum (ISO 8601)",
                    "example": "2026-12-15T09:00:00"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "E-Mail neu geplant",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "id": 880123,
                  "date_planned": "2026-12-15T09:00:00"
                }
              }
            }
          },
          "400": {
            "description": "Datum fehlt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "Versand nicht gefunden, bereits erfolgt oder Datum außerhalb des zulässigen Bereichs"
          }
        }
      }
    },
    "/SenderEmail": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "listCrmSenderEmails",
        "summary": "Absenderadressen auflisten",
        "description": "Gibt die für das Konto konfigurierten validierten Absender-E-Mail-Adressen zurück.",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Absenderadressen erfolgreich zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 201,
                    "email": "newsletter@yourcompany.com",
                    "sender_name": "Your Company Newsletter",
                    "is_validated": true
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "addCrmSenderEmail",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Absenderadresse hinzufügen",
        "description": "Fügt die Adresse mit denselben Prüfungen wie in der Anwendung hinzu und sendet ihr eine Bestätigungs-E-Mail. Sie kann verwendet werden, sobald der Link in dieser E-Mail angeklickt wurde. Ein Konto kann bis zu 25 Absender haben, bestätigt oder ausstehend.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email",
                  "sender_name"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "Absenderadresse",
                    "example": "news@example.com"
                  },
                  "sender_name": {
                    "type": "string",
                    "description": "Den Empfängern angezeigter Name",
                    "example": "Example News"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Adresse hinzugefügt. `domain_has_mx` ist false, wenn die Domain keinen MX-Eintrag hat.",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "confirmation_sent": true,
                  "domain_has_mx": true
                }
              }
            }
          },
          "400": {
            "description": "`email` oder `sender_name` fehlt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "422": {
            "description": "Adresse abgelehnt: ungültig, bereits unter den Absendern des Kontos, öffentliche E-Mail-Domain, unzulässiger Name oder Limit von 25 erreicht. Die Meldung nennt den Grund."
          },
          "503": {
            "description": "Vorübergehend nicht verfügbar, bitte versuchen Sie es erneut"
          }
        }
      }
    },
    "/SenderEmail/{id}/ResendValidation": {
      "post": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "resendCrmSenderValidation",
        "security": [
          {
            "OAuth2": [
              "email:templates:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Bestätigungs-E-Mail erneut senden",
        "description": "Für eine Adresse, die noch auf die Bestätigung wartet.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "`id_sender_email` aus `GET /SenderEmail`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "E-Mail erneut gesendet",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "confirmation_sent": true
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Absender nicht gefunden"
          },
          "409": {
            "description": "Dieser Absender ist bereits bestätigt"
          },
          "503": {
            "description": "Vorübergehend nicht verfügbar, bitte versuchen Sie es erneut"
          }
        }
      }
    },
    "/SenderEmail/{id}/Authentication": {
      "get": {
        "tags": [
          "Sender Addresses"
        ],
        "operationId": "getCrmSenderAuthentication",
        "security": [
          {
            "OAuth2": [
              "email:templates:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Domain eines Absenders prüfen (SPF, DKIM, DMARC, MX)",
        "description": "Prüft die Domain live im DNS und gibt die zu veröffentlichenden Einträge zurück. Nur Lesezugriff. DKIM wird in der Anwendung aktiviert: `dkim_settings_url` öffnet die richtige Seite.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "`id_sender_email` aus `GET /SenderEmail`",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Status der Domain. `spf.recommended_record` basiert auf Ihrem aktuellen Eintrag: Veröffentlichen Sie ihn nur, wenn `spf.change_needed` true ist.",
            "content": {
              "application/json": {
                "example": {
                  "domain": "example.com",
                  "spf": {
                    "valid": true,
                    "record": "v=spf1 include:spf.mailpro.com -all",
                    "recommended_record": "v=spf1 include:spf.mailpro.com -all",
                    "change_needed": false
                  },
                  "dkim": {
                    "valid": true,
                    "records": [
                      {
                        "host": "key._domainkey.example.com",
                        "value": "v=DKIM1;k=rsa;p=MIIBIjANBgkq...",
                        "validated": true
                      }
                    ]
                  },
                  "dmarc": {
                    "valid": true,
                    "record": "v=DMARC1; p=quarantine"
                  },
                  "mx": {
                    "valid": true,
                    "record": "mail.example.com"
                  },
                  "dkim_settings_url": "https://app.mailpro.com/dkim/list?d=example.com"
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Absender nicht gefunden"
          },
          "503": {
            "description": "Vorübergehend nicht verfügbar, bitte versuchen Sie es erneut"
          }
        }
      }
    },
    "/History/Email": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "getCrmHistoryEmail",
        "summary": "Verlauf der E-Mail-Versendungen auflisten",
        "description": "Gibt das Protokoll vergangener E-Mail-Versendungen des Kontos zurück.",
        "parameters": [
          {
            "name": "subjectMessage",
            "in": "query",
            "description": "Filterung nach Betreff (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idCampaign",
            "in": "query",
            "description": "Filterung nach Kampagnen-ID",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "includeBodyHTML",
            "in": "query",
            "description": "Vollständigen HTML-Body in die Antwort einbeziehen (langsamer)",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "E-Mail-Verlauf erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/History/SMS": {
      "get": {
        "tags": [
          "History"
        ],
        "operationId": "getCrmHistorySms",
        "summary": "Verlauf der SMS-Versendungen auflisten",
        "description": "Gibt das Protokoll vergangener SMS-Versendungen des Kontos zurück.",
        "parameters": [
          {
            "name": "dateSend",
            "in": "query",
            "description": "Filterung ab diesem Datum (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateSendEnd",
            "in": "query",
            "description": "Filterung bis zu diesem Datum (ISO 8601)",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "phoneNumber",
            "in": "query",
            "description": "Filterung nach Telefonnummer des Empfängers (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter für SMS-Typ",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "statusCode",
            "in": "query",
            "description": "Filter für DLR-Statuscode",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "sortByStatus",
            "in": "query",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "SMS-Verlauf erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Suppression/Bounces": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listCrmBounces",
        "security": [
          {
            "OAuth2": [
              "email:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Bounces des Kontos auflisten",
        "description": "Die neuesten zuerst. Die Gesamtzahl steht im Header `X-Total-Count`.",
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "`hard` oder `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          },
          {
            "name": "source",
            "in": "query",
            "description": "Herkunft des Bounces: `list`, `contact`, `api` oder `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Genaue Adresse",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "Ab diesem Datum",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Bis zu diesem Datum",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bounces zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 5521,
                    "source": "contact",
                    "type": "hard",
                    "email": "old@example.com",
                    "date": "2026-10-12T08:30:00",
                    "diag_code": "550 5.1.1 User unknown",
                    "id_list": 101
                  }
                ]
              }
            }
          },
          "400": {
            "description": "`type` muss `hard` oder `soft` sein"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Suppression/Bounces/{id}": {
      "delete": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteCrmBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Bounce entfernen",
        "description": "`source` und `type` sind erforderlich, wie von `GET /Suppression/Bounces` zurückgegeben: Eine `id` allein ist nicht eindeutig.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "`id` des Bounces",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": true,
            "description": "`list`, `contact`, `api` oder `smtp`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": true,
            "description": "`hard` oder `soft`",
            "schema": {
              "type": "string",
              "enum": [
                "hard",
                "soft"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bounce entfernt",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "id": 5521,
                  "restored": false
                }
              }
            }
          },
          "400": {
            "description": "`source` oder `type` fehlt"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Bounce nicht gefunden"
          }
        }
      }
    },
    "/Suppression/Bounces/{id}/Restore": {
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "restoreCrmBounce",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakt mit Hard Bounce wieder in seine Listen aufnehmen",
        "description": "Nur für einen Hard Bounce mit der Herkunft `contact`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "`id` des Bounces",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakt wieder aufgenommen",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "id": 5521,
                  "restored": true
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Hard Bounce eines Kontakts nicht gefunden oder Adresse nicht mehr aktiv"
          }
        }
      }
    },
    "/Suppression/Unsubscribers": {
      "get": {
        "tags": [
          "Suppression"
        ],
        "operationId": "listCrmUnsubscribers",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Abmeldungen des Kontos auflisten",
        "description": "Die neuesten zuerst. Die Gesamtzahl steht im Header `X-Total-Count`.",
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "description": "Herkunft der Abmeldung: `contact`, `list`, `smtp`, `api` oder `api3`",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "description": "Genaue Adresse",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dateFrom",
            "in": "query",
            "description": "Ab diesem Datum",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dateTo",
            "in": "query",
            "description": "Bis zu diesem Datum",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Abmeldungen zurückgegeben",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 9012,
                    "source": "api3",
                    "email": "stop@example.com",
                    "date": "2026-10-20T16:05:00",
                    "list_name": null,
                    "comment": "Asked by phone"
                  }
                ]
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "tags": [
          "Suppression"
        ],
        "operationId": "addCrmUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Abmeldung hinzufügen",
        "description": "Ohne `id_list` wird die Adresse für das gesamte Konto abgemeldet. Mit `id_list` nur von dieser Abmeldeliste.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "description": "Abzumeldende Adresse",
                    "example": "stop@example.com"
                  },
                  "comment": {
                    "type": "string",
                    "description": "Freier Kommentar",
                    "example": "Asked by phone"
                  },
                  "id_list": {
                    "type": "integer",
                    "format": "int64",
                    "description": "Abmeldeliste des Kontos (optional)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erledigt. `already_unsubscribed` ist true, wenn die Adresse bereits abgemeldet war.",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "already_unsubscribed": false
                }
              }
            }
          },
          "400": {
            "description": "Eine gültige Adresse ist erforderlich"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "`id_list` ist keine Abmeldeliste dieses Kontos"
          }
        }
      }
    },
    "/Suppression/Unsubscribers/{id}": {
      "delete": {
        "tags": [
          "Suppression"
        ],
        "operationId": "deleteCrmUnsubscriber",
        "security": [
          {
            "OAuth2": [
              "contacts:write"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Abmeldung entfernen",
        "description": "`source` ist erforderlich, wie von `GET /Suppression/Unsubscribers` zurückgegeben: Eine `id` allein ist nicht eindeutig.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "`id` der Abmeldung",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": true,
            "description": "`contact`, `list`, `smtp`, `api` oder `api3`",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Abmeldung entfernt",
            "content": {
              "application/json": {
                "example": {
                  "result": "ok",
                  "removed": 9012
                }
              }
            }
          },
          "400": {
            "description": "`source` ist erforderlich"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Abmeldung nicht gefunden"
          }
        }
      }
    },
    "/Segment": {
      "get": {
        "tags": [
          "Segment"
        ],
        "operationId": "getSegments",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Segmente auflisten",
        "description": "Gibt alle für das Konto gespeicherten dynamischen Segmente zurück.",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Segmente erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Segment/{id}/Contact": {
      "get": {
        "tags": [
          "Segment"
        ],
        "operationId": "getCrmSegmentContacts",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakte eines Segments auflisten",
        "description": "Mit `id_list` werden nur die Kontakte dieser Liste im Segment zurückgegeben: diejenigen, die eine Kampagne Liste + Segment erreichen würde. Die Gesamtzahl steht im Header `X-Total-Count`.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID des Segments",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "id_list",
            "in": "query",
            "description": "Auf diese Liste beschränken (optional)",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Kontakte zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Segment oder Liste nicht gefunden"
          }
        }
      }
    },
    "/Segment/{id}/Count": {
      "get": {
        "tags": [
          "Segment"
        ],
        "operationId": "countCrmSegmentContacts",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Kontakte eines Segments zählen",
        "description": "Nur die Anzahl, um die Größe eines Versands im Voraus zu kennen. Mit `id_list` werden nur die Kontakte dieser Liste im Segment gezählt.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID des Segments",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "id_list",
            "in": "query",
            "description": "Auf diese Liste beschränken (optional)",
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Anzahl der Kontakte",
            "content": {
              "application/json": {
                "example": {
                  "total": 1250
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Segment oder Liste nicht gefunden"
          }
        }
      }
    },
    "/Segment/{id}/contact/{contactId}/check": {
      "get": {
        "tags": [
          "Segment"
        ],
        "operationId": "checkContactInSegment",
        "security": [
          {
            "OAuth2": [
              "contacts:read"
            ]
          },
          {
            "bearerAuth": []
          },
          {
            "IdClientHeader": [],
            "ApiKeyHeader": []
          },
          {
            "IdClientQuery": [],
            "ApiKeyQuery": []
          }
        ],
        "summary": "Prüfen, ob ein Kontakt einem Segment entspricht",
        "description": "Prüft, ob ein bestimmter Kontakt (per GUID) aktuell den Regeln\neines bestimmten Segments entspricht. Nützlich, um Automatisierungslogik bei Bedarf auszulösen.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Segment-ID",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 4001
          },
          {
            "name": "contactId",
            "in": "path",
            "required": true,
            "description": "Kontakt-GUID",
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "11111111-2222-3333-4444-555555555555"
          }
        ],
        "responses": {
          "200": {
            "description": "Gibt das Übereinstimmungsergebnis zurück"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Segment oder Kontakt nicht gefunden"
          }
        }
      }
    },
    "/FolderList": {
      "get": {
        "tags": [
          "Folders"
        ],
        "operationId": "getFolderLists",
        "summary": "Listenordner auflisten",
        "description": "Gibt die zur Organisation von Kontaktlisten verwendeten Ordner zurück.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Filterung nach Ordnernamen (Teilübereinstimmung)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Listenordner erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/FolderList/{id}": {
      "get": {
        "tags": [
          "Folders"
        ],
        "operationId": "getFolderListById",
        "summary": "Einzelnen Listenordner abrufen",
        "description": "Gibt die Details eines Listenordners anhand seiner ID zurück.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Ordner-ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "responses": {
          "200": {
            "description": "Ordner erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "Ordner nicht gefunden"
          }
        }
      }
    },
    "/Sms/SingleSMS": {
      "post": {
        "tags": [
          "SMS"
        ],
        "operationId": "sendSingleSmsCrm",
        "summary": "Einzel-SMS senden",
        "description": "Sendet eine einzelne SMS direkt an eine Telefonnummer.\nVerwenden Sie dies für transaktionale Nachrichten (OTPs, Bestellbestätigungen, Benachrichtigungen).\nDie Telefonnummer akzeptiert `+41…`, `0041…` oder `41…` mit oder ohne Trennzeichen —\nsiehe **Telefonnummernformat** in der API-Beschreibung für akzeptierte / abgelehnte Eingaben.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmsSingleRequest"
              },
              "example": {
                "phone_number": "+41791234567",
                "message": "Your verification code is 9473. Valid for 10 minutes."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS erfolgreich gesendet oder geplant"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "422": {
            "description": "Ungültiges Telefonnummernformat"
          }
        }
      }
    },
    "/Sms/Campaign": {
      "post": {
        "tags": [
          "SMS"
        ],
        "operationId": "sendSmsCampaignCrm",
        "summary": "SMS-Kampagne senden",
        "description": "Sendet eine SMS-Nachricht an das Feld `phone_number` aller Kontakte in einer oder mehreren Listen.\nKontakte ohne Telefonnummer werden übersprungen.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SmsCampaignRequest"
              },
              "example": {
                "lists": [
                  {
                    "id": 101
                  }
                ],
                "message": "Flash sale today — 20% off. Shop at mailpro.com",
                "date_planned": "2026-04-20T10:00:00"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "SMS-Kampagne erfolgreich gesendet oder geplant"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Sms": {
      "get": {
        "tags": [
          "SMS"
        ],
        "operationId": "getSmsSends",
        "summary": "SMS-Verlauf auflisten",
        "description": "Gibt das Protokoll der SMS-Versendungen (sowohl Einzel- als auch Kampagnen-SMS) des Kontos zurück.",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "SMS-Verlauf erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Sms/{id}": {
      "delete": {
        "tags": [
          "SMS"
        ],
        "operationId": "deleteSmsSendCrm",
        "summary": "Geplante SMS stornieren",
        "description": "Storniert eine ausstehende geplante SMS-Sendung.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID der SMS-Sendung",
            "schema": {
              "type": "integer",
              "format": "int64"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Geplante SMS erfolgreich storniert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "404": {
            "description": "SMS-Sendung nicht gefunden"
          }
        }
      }
    },
    "/Sms/Scheduled": {
      "get": {
        "tags": [
          "SMS"
        ],
        "operationId": "listScheduledSmsCrm",
        "summary": "Geplante SMS-Sendungen auflisten",
        "description": "Gibt SMS-Sendungen mit zukünftigem `date_planned` (noch nicht versendet) zurück, aufsteigend nach Datum sortiert.",
        "parameters": [
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 100
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Geplante SMS-Sendungen erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Sms/{id}/Cancel": {
      "post": {
        "tags": [
          "SMS"
        ],
        "operationId": "cancelScheduledSmsCrm",
        "summary": "Geplante SMS stornieren",
        "description": "Storniert eine geplante SMS-Sendung nur, wenn diese noch nicht versendet wurde.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID der SMS-Sendung",
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "responses": {
          "200": {
            "description": "Geplante SMS erfolgreich storniert"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "SMS-Sendung nicht gefunden, gehört nicht zum Client oder bereits versendet"
          }
        }
      }
    },
    "/Sms/{id}/Reschedule": {
      "patch": {
        "tags": [
          "SMS"
        ],
        "operationId": "rescheduleScheduledSmsCrm",
        "summary": "Geplante SMS neu planen",
        "description": "Aktualisiert das geplante Sendedatum einer geplanten SMS. Das neue Datum muss\nin der Zukunft und innerhalb von 90 Tagen liegen. Schlägt fehl, wenn die SMS bereits versendet wurde.\n\n**Name des Body-Felds:** Die API akzeptiert `date_planned` (snake_case, primär)\nsowie die Legacy-Aliasse `PlanDate` und `scheduled_time`. Geben Sie einen beliebigen\ndavon an.\n",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID der SMS-Sendung",
            "schema": {
              "type": "integer"
            },
            "example": 5001
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Geben Sie eines von `date_planned`, `PlanDate` oder `scheduled_time` an.",
                "properties": {
                  "date_planned": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Primärer Feldname.",
                    "example": "2026-05-10T14:00:00Z"
                  },
                  "PlanDate": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Aus Gründen der Abwärtskompatibilität akzeptierter Legacy-Alias."
                  },
                  "scheduled_time": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Aus Gründen der Abwärtskompatibilität akzeptierter Legacy-Alias."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Geplante SMS erfolgreich neu geplant"
          },
          "400": {
            "description": "Fehlendes Datum — geben Sie eines von date_planned / PlanDate / scheduled_time an"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "409": {
            "description": "Neuplanung fehlgeschlagen (nicht gefunden, bereits versendet oder Datum außerhalb des Bereichs)"
          }
        }
      }
    },
    "/FolderMessage": {
      "get": {
        "tags": [
          "Folders"
        ],
        "operationId": "getFolderMessages",
        "summary": "Nachrichtenordner auflisten",
        "description": "Gibt die zur Organisation von E-Mail-Nachrichtenvorlagen verwendeten Ordner zurück.",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "description": "Filterung nach Ordnernamen",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "numberOfRecords",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 50
          },
          {
            "name": "pageNumber",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Nachrichtenordner erfolgreich zurückgegeben"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Import/Upload": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "uploadImportFile",
        "summary": "Kontaktdatei (CSV / XLSX) für Massenimport hochladen",
        "description": "Laden Sie eine CSV- oder XLSX-Datei hoch, um Kontakte in eine Liste zu importieren.\nDie Datei wird gespeichert und zur asynchronen Verarbeitung in die Warteschlange eingereiht — der Endpunkt\ngibt sofort eine `import_job_id` zurück.\n\n**Anfragetyp:** `multipart/form-data`\n\n**Erforderliche Formularfelder:**\n- `id_list` (Ganzzahl) — ID der Zielliste\n- `file` (Binär) — die hochzuladende CSV- oder XLSX-Datei\n- `json_match_fields` (Zeichenfolge, JSON) — welche Spalte der Datei in\n  welches Kontaktfeld geht. `email_position` = Spalte der E-Mail-Adresse,\n  ab 0 gezählt (erforderlich), `phone_position` = Spalte der Mobilnummer\n  oder `-1`, `fields` = IDs der übrigen Felder (siehe `GET /Field`),\n  `fields_position` = Spalte jedes dieser Felder, `update_fields` =\n  bestehende Kontakte aktualisieren. Fehlende oder ungültige Zuordnung:\n  Antwort `400`, es wird kein Import angelegt.\n\n**Optional:**\n- `webhook_url` (Zeichenfolge) — HTTPS-URL, die beim Abschluss der Verarbeitung aufgerufen wird.\n  Empfängt einen JSON-Payload mit dem endgültigen Status (success / failed) und\n  der Anzahl der importierten / übersprungenen / ungültigen Zeilen.\n\n**Dateiformat:**\n- UTF-8-kodiert\n- Die erste Zeile darf Kopfzeilen enthalten (automatische Erkennung: eine\n  erste Zeile ohne E-Mail-Adresse wird übersprungen)\n- Die Spalten werden über `json_match_fields` den Feldern zugeordnet\n- Maximale Dateigröße: 50 MB\n",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "id_list",
                  "file",
                  "json_match_fields"
                ],
                "properties": {
                  "id_list": {
                    "type": "integer",
                    "format": "int64",
                    "description": "ID der Zielliste",
                    "example": 11088
                  },
                  "file": {
                    "type": "string",
                    "format": "binary",
                    "description": "CSV- oder XLSX-Datei (UTF-8, max. 50 MB)"
                  },
                  "json_match_fields": {
                    "type": "string",
                    "description": "JSON-Zuordnung der Dateispalten zu den Kontaktfeldern",
                    "example": "{\"email_position\":0,\"phone_position\":-1,\"fields\":[1315597,1315598],\"fields_position\":[1,2],\"update_fields\":true}"
                  },
                  "webhook_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Callback-URL, die beim Abschluss der Verarbeitung aufgerufen wird",
                    "example": "https://example.com/hooks/mailpro-import"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Datei akzeptiert und in Warteschlange eingereiht",
            "content": {
              "application/json": {
                "example": {
                  "result": "OK",
                  "import_job_id": 14,
                  "internal_name": "230575-20260420142615-contacts.csv"
                }
              }
            }
          },
          "400": {
            "description": "Keine Datei hochgeladen, id_list fehlt oder json_match_fields fehlt / ist ungültig"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          },
          "500": {
            "description": "Server- oder Speicherfehler"
          }
        }
      }
    },
    "/Webhook": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst (getrennt vom Haupt-API-Host)"
        }
      ],
      "get": {
        "summary": "Webhooks auflisten",
        "description": "Gibt alle für das authentifizierte Konto konfigurierten Webhooks zurück.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array von Webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Webhook"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      },
      "post": {
        "summary": "Webhook erstellen",
        "description": "Erstellt ein neues Webhook-Abonnement. Die Antwort enthält ein `secret`, das\n**nur einmal angezeigt** wird — speichern Sie es sofort serverseitig. Verwenden Sie es zur\nÜberprüfung der HMAC-Signatur jedes eingehenden Payloads.\n\n**Limits**: maximal 20 Webhooks pro Konto, maximal 50 Ereignisse pro Webhook.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              },
              "example": {
                "url": "https://example.com/hooks/mailpro",
                "events": [
                  "email.delivered",
                  "email.bounced",
                  "contact.created"
                ],
                "description": "Slack-Integration"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook erstellt — `secret` wird ausschließlich hier zurückgegeben",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookCreateResponse"
                },
                "example": {
                  "id": 42,
                  "url": "https://example.com/hooks/mailpro",
                  "events": [
                    "email.delivered",
                    "email.bounced",
                    "contact.created"
                  ],
                  "description": "Slack-Integration",
                  "isActive": true,
                  "consecutiveFailures": 0,
                  "autoDisabledAt": null,
                  "autoDisabledReason": null,
                  "createdAt": "2026-05-25T10:00:00Z",
                  "updatedAt": "2026-05-25T10:00:00Z",
                  "secret": "whsec_AbcD1234EfgH5678IjkL9012MnoP3456QrsT"
                }
              }
            }
          },
          "400": {
            "description": "Ungültige URL, Ereignisliste oder Limit überschritten"
          },
          "401": {
            "description": "Ungültiges oder abgelaufenes Token"
          }
        }
      }
    },
    "/Webhook/{id}": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "get": {
        "summary": "Webhook abrufen",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Der Webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      },
      "put": {
        "summary": "Webhook aktualisieren",
        "description": "Teilaktualisierung — nur die gesendeten Felder werden geändert.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Aktualisierter Webhook",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Webhook"
                }
              }
            }
          },
          "400": {
            "description": "Ungültiger Payload"
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      },
      "delete": {
        "summary": "Webhook löschen",
        "description": "Löscht den Webhook und seine vollständige Zustellungshistorie dauerhaft.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "204": {
            "description": "Gelöscht"
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      }
    },
    "/Webhook/{id}/test": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Testereignis senden",
        "description": "Reiht sofort ein `ping`-Ereignis (oder einen beliebigen anderen Ereignistyp über das\nBody-Feld `eventType`) für Ihren Endpunkt in die Warteschlange ein. Nützlich, um die Erreichbarkeit\nund die Signaturprüfung zu verifizieren, bevor Sie sich auf reale Ereignisse verlassen.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "eventType": {
                    "type": "string",
                    "default": "ping",
                    "description": "Überschreibt den Ereignistyp (muss von diesem Webhook abonniert sein). `ping` funktioniert immer."
                  }
                }
              },
              "example": {
                "eventType": "ping"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Ereignis zum Versand in die Warteschlange eingereiht",
            "content": {
              "application/json": {
                "example": {
                  "deliveryId": 1234,
                  "eventId": "evt_8f3a9b2c4d1e5f6789abcdef01234567",
                  "eventType": "ping"
                }
              }
            }
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      }
    },
    "/Webhook/{id}/rotate-secret": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "HMAC-Secret rotieren",
        "description": "Erstellt ein neues HMAC-Secret und macht das alte sofort ungültig.\nDas neue Secret wird **einmalig** in der Antwort zurückgegeben — speichern Sie es. Jede\nZustellung ab diesem Zeitpunkt wird mit dem neuen Secret signiert.\n\nVerwenden Sie diese Funktion, wenn Sie den Verdacht haben, dass Ihr Secret kompromittiert wurde.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Neues Secret (einmalig sichtbar)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secret": {
                      "type": "string"
                    }
                  }
                },
                "example": {
                  "secret": "whsec_XyzA9876BcdE5432FghI1098JklM7654NopQ"
                }
              }
            }
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      }
    },
    "/Webhook/{id}/deliveries": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "query",
          "name": "limit",
          "schema": {
            "type": "integer",
            "default": 50,
            "maximum": 200
          }
        },
        {
          "in": "query",
          "name": "cursor",
          "schema": {
            "type": "integer",
            "format": "int64"
          },
          "description": "Paginierungs-Cursor (= zuletzt gesehene Zustellungs-ID). Gibt Zustellungen mit `id < cursor` zurück."
        }
      ],
      "get": {
        "summary": "Zustellversuche auflisten",
        "description": "Gibt die Historie der Zustellversuche für diesen Webhook zurück (30 Tage Aufbewahrung).\nNützlich zur Fehlersuche — welche Ereignisse wurden gesendet, welche Statuscodes wurden empfangen,\nwie viele Wiederholungsversuche und welche Fehlermeldungen.\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Array von Zustellversuchen (neueste zuerst)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDelivery"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook nicht gefunden"
          }
        }
      }
    },
    "/Webhook/{id}/deliveries/{deliveryId}/replay": {
      "servers": [
        {
          "url": "https://webhook.mailpro.com/api/v3",
          "description": "Webhook-Verwaltungsdienst"
        }
      ],
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        },
        {
          "in": "path",
          "name": "deliveryId",
          "required": true,
          "schema": {
            "type": "integer",
            "format": "int64"
          }
        }
      ],
      "post": {
        "summary": "Zustellung wiederholen",
        "description": "Reiht einen frischen Zustellversuch mit demselben Payload wie das Original in die Warteschlange ein.\nNützlich, um eine fehlgeschlagene Zustellung nach Behebung Ihres Endpunkts erneut auszulösen.\nEine NEUE `Webhook_Delivery`-Zeile wird angelegt (das Original bleibt zu\nPrüfzwecken erhalten). Die Wiederholung durchläuft die standardmäßige Wiederholungsrichtlinie\n(10s → 1min → 5min → 30min → 2h → 6h → 24h, dann aufgegeben).\n",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "202": {
            "description": "Wiederholung in Warteschlange eingereiht",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "new_delivery_id": {
                      "type": "integer",
                      "format": "int64",
                      "example": 12999
                    },
                    "queued_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Webhook oder Zustellung nicht gefunden"
          }
        }
      }
    }
  }
}