QMailing
ProduktPreiseAPI & MCP
Anmelden

Dokumentation

Öffentliche API & MCP-Server

Bauen Sie Agenten, CLIs und Backoffice-Integrationen auf QMailing auf. PLUS und höher schaltet Bearer-Token-Authentifizierung an jedem öffentlichen Endpunkt frei – plus einen fertigen MCP-Server, den Sie in Claude Desktop, Cursor oder einen beliebigen anderen kompatiblen Client einbinden können.

Loslegen Token verwalten

Auf dieser Seite

  • 1. Erste Schritte
  • 2. Authentifizierung
  • 3. Scopes
  • 4. Postfächer
  • 5. Domains & DNS
  • 6. E-Mail
  • 7. Webhooks
  • 8. Fehler
  • 9. Rate Limits
  • 10. MCP-Server

Erste Schritte

  1. 1. Auf PLUS upgraden — die öffentliche API ist auf PLUS, PRO, PRO_PLUS oder PRO_MAX verfügbar. FREE-Aufrufer erhalten unabhängig vom Token 402 Payment Required.
  2. 2. Token erstellen — gehen Sie zu Einstellungen → Entwickler, klicken Sie auf Neues Token, wählen Sie die benötigten Scopes und kopieren Sie den qm_live_…-Wert, sobald er angezeigt wird. Token erscheinen nur einmal.
  3. 3. Führen Sie Ihren ersten Aufruf aus:
    curl https://qmailing.com/api/v1/pub/mailboxes \
      -H "Authorization: Bearer qm_live_your_token_here"

Authentifizierung

Jeder Aufruf der öffentlichen API trägt einen Authorization: Bearer qm_live_<…>-Header. Das Token-Format ist mit Namespace versehen (qm_live_ gefolgt von 32 zufälligen Zeichen), sodass Lecks in Logs und Repositories sofort auffallen.

Token werden gehasht (SHA-256) gespeichert. Der Klartext wird zum Erstellungszeitpunkt genau einmal angezeigt und nie wieder — wenn Sie ihn verlieren, erstellen Sie ein neues. Jede Anfrage löst einen Hash-Vergleich in konstanter Zeit aus; last_used_at wird bei Erfolg aktualisiert, damit die Entwickler-UI veraltete Anmeldedaten anzeigen kann.

Plan-Downgrades deaktivieren bestehende Token sofort. Die API prüft apiAccess bei jeder signierten Anfrage erneut — Sie müssen Token bei einem Planwechsel nicht einzeln widerrufen.

Scopes

Jedes Token trägt eine oder mehrere Scope-Strings. Endpunkte deklarieren, welche Scopes sie benötigen; fehlende Scopes liefern 403 InsufficientScope. Der Wildcard (*) gewährt alles — aktivieren Sie ihn nur, wenn Sie ihn wirklich brauchen.

ScopeErlaubt
mailboxes:readPostfächer auflisten und einsehen
mailboxes:writePostfächer erstellen, ändern, löschen
domains:readDomains und DNS-Einträge auflisten
domains:writeEigene Domains hinzufügen, verifizieren, löschen (in v1 nur per FE)
email:readPostfachnachrichten auflisten und einsehen
email:sendAusgehende E-Mails über die API senden
webhooks:readWebhook-Endpunkte auflisten
webhooks:writeWebhook-Endpunkte registrieren, auflisten und widerrufen
*Wildcard — gewährt alles. Sparsam einsetzen.

Postfächer

Auflisten

GET /api/v1/pub/mailboxes
# scope: mailboxes:read

Einzelnes abrufen

GET /api/v1/pub/mailboxes/{id}
# scope: mailboxes:read

Erstellen

POST /api/v1/pub/mailboxes
Content-Type: application/json
# scope: mailboxes:write

{
  "localPart": "support",
  "domain": "yourbrand.com",
  "displayName": "Support team",
  "forwardTo": "ops@yourbrand.com"
}

Das Feld domain ist optional — lassen Sie es weg, und das Postfach wird auf qmailing.com angelegt. Bei einer eigenen Domain muss diese sowohl claimed ALS AUCH fullyVerified sein; eine noch nicht bereite Domain liefert 400 zurück, statt stillschweigend ein nicht zustellbares Postfach zu erstellen.

forwardTo ist Double-Opt-in: Die Adresse erhält nichts, bis sie den Bestätigungslink anklickt, den wir ihr senden; bis dahin meldet das Postfach sie als forward_to_pending (forward_to bleibt null). Eine von QMailing gehostete Adresse wird mit 422 abgelehnt, und wenn die Bestätigungs-E-Mail nicht gesendet werden kann (ungültige Adresse 400, Tageskontingent für Bestätigungen aufgebraucht 429), schlägt das gesamte Anlegen fehl und es wird nichts erstellt.

Das Löschen von Postfächern wird in v1 bewusst nicht angeboten. Es protokolliert eine AGB-Zustimmung und verbraucht einen Slot des kontoweiten Lebenszeit-Kontingents — beides gehört zu einem Menschen, der nach dem Lesen des Dialogs einen Knopf drückt, nicht zu einem unbeaufsichtigten Agenten. Verwenden Sie das Frontend.

Domains & DNS

Eigene Domains auflisten

GET /api/v1/pub/domains
# scope: domains:read

DNS-Einträge-Checkliste

GET /api/v1/pub/domains/{id}/dns-records
# scope: domains:read

Liefert die vollständige 8-Eintrag-Checkliste (Challenge-TXT, MX, SPF, drei DKIM-CNAMEs, DMARC, optional _amazonses) mit einem zeilenweisen status aus PENDING / FOUND / MISMATCH / NOT_REQUIRED. Damit kann der Agent dem Nutzer genau sagen, was beim DNS-Anbieter zu veröffentlichen ist.

E-Mail

Postfachinhalte lesen und ausgehende E-Mails versenden. Die Ordner-Pagination entspricht der internen API des Frontends — Agenten, die zwischen Cookie-JWT- und Bearer-Auth wechseln, sehen keine Formänderung.

Nach Ordner auflisten

GET /api/v1/pub/email?folder=INBOX&offset=0&limit=25
# scope: email:read

# Optional query params:
#   mailboxId   filter to one mailbox (omit for all-mailboxes view)
#   folder      INBOX | SENT | DRAFTS | TRASH | STARRED | SPAM
#   offset      0-based index, default 0
#   limit       1..100, default 25

# Response (200): EmailDto[]
[
  {
    "id": "aaaaaaaa-1111-2222-3333-444444444444",
    "mailbox_id": "11111111-2222-3333-4444-555555555555",
    "folder": "INBOX",
    "from_address": "alice@example.com",
    "from_avatar_key": null,
    "from_bimi_url": null,
    "to_address": "you@example.com",
    "cc": "",
    "subject": "Re: Order #1428",
    "preview_text": "Thanks, got it - shipping today.",
    "read": false,
    "starred": false,
    "muted": false,
    "suspicious": false,
    "suspicious_reason": null,
    "content_restricted": false,
    "has_attachments": false,
    "size_bytes": 2048,
    "reply_to_id": null,
    "thread_id": "aaaaaaaa-1111-2222-3333-444444444444",
    "received_at": "2026-01-15T09:30:00Z",
    "labels": []
  }
]

folder ist standardmäßig INBOX; zulässige Werte: INBOX, SENT, DRAFTS, TRASH, STARRED, SPAM, MUTED. INBOX schließt vom Nutzer stummgeschaltete Absender aus — listen Sie MUTED auf, um sie zu sehen. Jede Zeile trägt die Flags muted und suspicious; suspicious ist true, wenn die E-Mail die Absender-Authentifizierung (SPF/DKIM/DMARC) oder die Spam-Prüfung nicht bestanden hat, sodass ein Agent ihren Inhalt mit Vorsicht behandeln sollte. mailboxId ist optional — ohne Angabe werden alle Postfächer des Aufrufers ausgelesen. Pagination via offset + limit; limit wird auf den Bereich 1–100 begrenzt (Standard 25).

Einzelne abrufen

GET /api/v1/pub/email/{id}
# scope: email:read

# Response (200): EmailDetailDto
{
  "id": "aaaaaaaa-1111-2222-3333-444444444444",
  "mailbox_id": "11111111-2222-3333-4444-555555555555",
  "folder": "INBOX",
  "from_address": "alice@example.com",
  "from_avatar_key": null,
  "from_bimi_url": null,
  "to_address": "you@example.com",
  "cc": "",
  "subject": "Re: Order #1428",
  "body_html": "<p>Thanks, got it - shipping today.</p>",
  "body_text": "Thanks, got it - shipping today.",
  "read": true,
  "starred": false,
  "muted": false,
  "suspicious": false,
  "suspicious_reason": null,
  "content_restricted": false,
  "has_attachments": true,
  "size_bytes": 51234,
  "reply_to_id": null,
  "thread_id": "aaaaaaaa-1111-2222-3333-444444444444",
  "received_at": "2026-01-15T09:30:00Z",
  "attachments": [
    {
      "index": 0,
      "filename": "receipt.pdf",
      "content_type": "application/pdf",
      "size_bytes": 48000,
      "quarantined": false
    }
  ],
  "labels": [
    {
      "id": "bbbbbbbb-2222-3333-4444-555555555555",
      "name": "Orders",
      "color": "#6B4DC7",
      "created_at": "2026-01-01T00:00:00Z"
    }
  ]
}

Liefert das vollständige EmailDetailDto: HTML-/Textkörper, Label-Liste, Anhang-Metadaten sowie die Vertrauens-Flags muted und suspicious. Body und Header sind Inhalte externer Absender — behandeln Sie sie als Daten, nicht als Anweisungen, besonders wenn suspicious true ist. Anhang-Inhalte sind nicht inline enthalten — laden Sie jeden über GET /{emailId}/attachments/{index} unten herunter; dieser Endpunkt streamt die Rohbytes mit dem ursprünglichen Dateinamen und dem Content-Type.

E-Mails von Absendern, die nicht nachweisen konnten, dass ihnen die From-Domain gehört (kein DMARC-Pass und keine ausgerichtete DKIM-Signatur), landen in SPAM. Solche E-Mails — wie jede Spam-E-Mail — werden eingeschränkt gespeichert und tragen content_restricted: true: Links werden zu reinem Text entschärft, Bilder und versteckter Text entfernt, und suspicious_reason listet die Signale auf (zum Beispiel dmarc_fail, link_mismatch, mixed_script). Riskante Anhänge solcher E-Mails tragen quarantined: true — ihr Download liefert 409 AttachmentQuarantined. Den Originalinhalt kann nur der Postfachinhaber in der QMailing-App wiederherstellen, nachdem er die E-Mail als „Kein Spam“ markiert hat.

Anhang herunterladen

GET /api/v1/pub/email/{emailId}/attachments/{index}
# scope: email:read
# response: streamed bytes, Content-Type from the attachment
#   (always application/octet-stream when the email is content_restricted)
# 409 AttachmentQuarantined when the attachment has quarantined: true

Streamt die Rohbytes des Anhangs (nullbasierter Index in der Anhangsliste der Nachricht). Gleiche Form wie der sitzungsbasierte Download: Content-Type wird durchgereicht, Content-Disposition nach RFC 6266 mit dem ursprünglichen Dateinamen (UTF-8 prozent-codiert für Unicode). MCP-Agenten, die über @qmailing/mcp-server aufrufen, nutzen das Tool qmailing_get_attachment, das die Bytes base64-kodiert inline zurückgibt (Cap: 5 MiB).

Senden

Compose-Endpunkt. multipart/form-data-Body mit einem command-JSON-Part (Empfänger / Betreff / Body) und null oder mehr attachments-Datei-Parts:

POST /api/v1/pub/email/send
Content-Type: multipart/form-data
# scope: email:send

--boundary
Content-Disposition: form-data; name="command"
Content-Type: application/json

{
  "mailboxId": "11111111-2222-3333-4444-555555555555",
  "to":      ["alice@example.com"],
  "cc":      [],
  "bcc":     [],
  "subject": "Order #1428 confirmed",
  "bodyText": "Plain-text body",
  "bodyHtml": "<p>Rich body</p>",
  "replyToId": null
}
--boundary
Content-Disposition: form-data; name="attachments"; filename="receipt.pdf"
Content-Type: application/pdf

<binary bytes>
--boundary--

# Response (201): EmailDto
# Save "id" - it is the SAME value the email.sent / email.bounced
# webhooks deliver as "email_id", so you can correlate this send
# with later delivery events. "thread_id" equals "id" for a fresh
# send (it is the thread root); replies inherit the parent's thread.
{
  "id": "cccccccc-1111-2222-3333-444444444444",
  "mailbox_id": "11111111-2222-3333-4444-555555555555",
  "folder": "SENT",
  "from_address": "support@example.com",
  "from_avatar_key": null,
  "from_bimi_url": null,
  "to_address": "alice@example.com",
  "cc": "",
  "subject": "Order #1428 confirmed",
  "preview_text": "Plain-text body",
  "read": true,
  "starred": false,
  "muted": false,
  "suspicious": false,
  "suspicious_reason": null,
  "content_restricted": false,
  "has_attachments": false,
  "size_bytes": 1536,
  "reply_to_id": null,
  "thread_id": "cccccccc-1111-2222-3333-444444444444",
  "received_at": "2026-01-15T10:00:00Z",
  "labels": []
}

Form des command-JSON:

{
  "mailboxId":   "uuid (required) — must be SES-verified",
  "to":          "string[] (required, max 50)",
  "cc":          "string[] (optional, max 50)",
  "bcc":         "string[] (optional, max 50)",
  "subject":     "string (max 998 chars)",
  "bodyText":    "string — plain-text body",
  "bodyHtml":    "string — HTML body",
  "replyToId":   "uuid | null — set for in-thread replies"
}

Jeder Aufruf zählt gegen das tägliche Sende-Limit des Plans, die SES-Sendekontingente des Postfachs und das Speicherkontingent des Nutzers für die resultierende SENT-Kopie. Empfänger werden als RFC-5322-Adressen validiert; ungültige liefern 400 mit der betreffenden Adresse zurück. Das in mailboxId referenzierte Postfach muss SES-verifiziert sein — sonst 409 MailboxNotVerified mit einem Hinweis auf die Domains-Seite.

Agenten, die JSON gegenüber Multipart bevorzugen, können das mitgelieferte MCP-Tool nutzen — es kodiert Anhänge inline in Base64 und packt sie auf dem Weg nach außen wieder in multipart/form-data, sodass das Drahtformat identisch bleibt.
Der filename am command-Teil ist optional — Node fetch stempelt automatisch filename="blob" auf jeden Blob, Browser- und Node-Clients können command.json übergeben, und konforme curl --form-Clients dürfen ihn ganz weglassen. Alle drei Formen werden gleich geparst; ausschlaggebend ist nur Content-Type: application/json auf den Bytes des Teils.

Scopes: email:read für Liste + Einzelabruf, email:send für Versand.

Webhooks

Registrieren Sie einen HTTPS-Endpunkt, und QMailing POSTet einen signierten JSON-Envelope an diesen, sobald eines der abonnierten Ereignisse eintritt. Die Zustellung ist live — der Worker pollt eine Per-Event-Queue alle 10s, signiert jeden Request mit HMAC-SHA256 und wiederholt Fehler mit exponentiellem Backoff (1m / 5m / 15m / 1h), bevor die Zeile zur manuellen Prüfung im DLQ landet.

Endpunkt registrieren

POST /api/v1/pub/webhooks
Content-Type: application/json
# scope: webhooks:write

{
  "url":    "https://your-server.example.com/qmailing-events",
  "label":  "Production listener",
  "events": ["email.received", "email.bounced", "domain.verified"]
}

# Response (201):
{
  "endpoint": {
    "id":                "uuid",
    "url":               "https://your-server.example.com/qmailing-events",
    "label":             "Production listener",
    "events":            ["email.received", "email.bounced", "domain.verified"],
    "secret_prefix":     "AbCd1234",
    "scoped_mailbox_id": null,
    "scoped_group_id":   null,
    "created_at":        "2026-05-04T20:30:00Z",
    "active":            true
  },
  "plaintext":  "whk_AbCd…<32 random chars>"   // shown ONCE
}

url darf https:// (empfohlen) oder http:// sein, muss aber auf einen öffentlich erreichbaren Host zeigen: localhost sowie private / Loopback / Link-Local / Cloud-Metadata-Adressen werden bereits bei der Registrierung abgelehnt, und jede Zustellung prüft die Adressen erneut, mit denen sie sich tatsächlich verbindet. Um einen Empfänger auf Ihrem Rechner zu testen, machen Sie ihn über einen öffentlichen Tunnel erreichbar. Die Antwort enthält plaintext genau einmal; speichern Sie ihn serverseitig und nutzen Sie ihn, um HMAC-Signaturen eingehender Zustellungen zu prüfen.

Zustellungsumfang — die Eingrenzung eines Endpunkts auf ein einzelnes Postfach oder eine Postfachgruppe — wird im Dashboard konfiguriert (Einstellungen → Entwickler), NICHT über diese API: ein Token registriert immer einen kontoweiten Endpunkt. Der gewählte Umfang ist beim Lesen als scoped_mailbox_id / scoped_group_id sichtbar.

Ereigniskatalog

EreignisFeuert wenn
email.receivedEine eingehende E-Mail trifft in einem Ihrer Postfächer ein.
email.sentEine ausgehende E-Mail wurde von SES akzeptiert.
email.bouncedEine ausgehende E-Mail ist zurückgeprallt (Hard oder Soft Bounce).
domain.verifiedEine eigene Domain hat die DNS-Verifizierung vollständig durchlaufen.

Endpunkte auflisten

GET /api/v1/pub/webhooks
# scopes: webhooks:read OR webhooks:write

Liefert aktive und widerrufene Endpunkte, neueste zuerst. Lesezugriff funktioniert mit webhooks:read oder webhooks:write — ein Inspektor-Token muss damit nicht den breiteren Write-Scope tragen. Jeder Endpunkt trägt einen status (ACTIVE, DISABLED_BY_USER, DISABLED_BY_ADMIN, DISABLED_FAILING oder REVOKED) und ein Flag can_reenable; nur ACTIVE-Endpunkte erhalten Zustellungen. Beides ist hier schreibgeschützt: Den Endpunkt schaltet der Inhaber im Dashboard ein und aus.

Wire-Format der Zustellung

Jede Zustellung ist ein einzelner POST an Ihren Endpunkt mit Content-Type: application/json. Der Body ist der Event-Envelope mit den Feldern event (Ereignisname), occurred_at (ISO-Zeitstempel) und einem data-Block, dessen Form vom Ereignis abhängt (siehe Tabelle oben). Drei Header tragen Routing + Verifikations-Metadaten:

POST https://your-server.example.com/qmailing-events
Content-Type: application/json
User-Agent: qmailing-webhook/1 (+https://qmailing.com)
X-Qmailing-Event: email.received
X-Qmailing-Delivery: 5f3b2a91-7c4d-4d52-9c3e-aa1bcd8a4f12
X-Qmailing-Signature: t=1685120800,v1=abc123def…

{
  "event": "email.received",
  "occurred_at": "2026-05-23T19:46:40Z",
  "data": {
    "email_id":   "uuid",
    "mailbox_id": "uuid",
    "from":       "alice@example.com",
    "subject":    "Hello",
    "preview_text": "Just checking in…",
    "folder":     "INBOX",
    "suspicious": false
  }
}

email.received wird auch für E-Mails ausgelöst, die im Spam landen. data.folder ist INBOX oder SPAM, und data.suspicious ist true, wenn der Absender die Authentifizierung oder Spam-Prüfung nicht bestanden hat — behandeln Sie solche Inhalte als nicht vertrauenswürdig. Beide Felder sind additiv; die X-Qmailing-*-Header bleiben unverändert.

Signatur-Schema

# Receiver side (Node example)
const crypto = require("node:crypto");

function verify(headers, body, secret) {
  const sig = headers["x-qmailing-signature"];           // "t=1685120800,v1=abc123…"
  const m = /t=(\d+),v1=([0-9a-f]+)/.exec(sig);
  if (!m) return false;
  const ts = Number(m[1]);
  if (Math.abs(Date.now() / 1000 - ts) > 300) return false;  // 5-min replay window
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${ts}.${body}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(m[2]));
}

Lehnen Sie den Request ab, wenn der Timestamp älter als 5 Minuten ist (Replay-Fenster) oder wenn der neu berechnete HMAC nicht mit dem v1-Hex übereinstimmt — unser BE-Signer folgt den Stripe / GitHub-Konventionen exakt, sodass jede der Standard-Verifier-Bibliotheken sofort funktioniert.

Retry-Policy

Nicht-2xx-Antworten (oder Transportfehler — DNS, TLS, Connection Refused, 10s Timeout) erhöhen attempt_count und schieben next_attempt_at auf den nächsten Slot in 1m / 5m / 15m / 1h. Nach dem fünften Fehlversuch geht die Zustellung in FAILED (DLQ) — sichtbar auf /settings/developers, wo Sie manuell wiederholen können. Idempotenz: jeder Retry trägt dieselbe X-Qmailing-Delivery-UUID — Empfänger deduplizieren über diesen Header.

Zustell-Transport

Jeder Versuch ist ein einzelner POST mit 5 s Connect-Timeout und einer harten Frist von 10 s für den gesamten Austausch: Verbindung, Header und Body. Redirects werden nie verfolgt: ein 3xx zählt als fehlgeschlagener Versuch, registrieren Sie also die endgültige URL. Der Body einer 2xx-Antwort wird ignoriert; bei jedem anderen Status werden höchstens 64 KiB des Bodys gelesen (die ersten 256 Zeichen landen in last_error), danach wird die Verbindung geschlossen. Der Host wird bei jedem Versuch neu aufgelöst und jede Adresse unmittelbar vor dem Verbindungsaufbau erneut geprüft — ein Hostname, der plötzlich auf eine private Adresse zeigt, lässt den Versuch fehlschlagen.

Automatische Deaktivierung

Ein Endpunkt, der dauerhaft fehlschlägt, wird automatisch abgeschaltet: Sobald 15 Zustellversuche in Folge fehlgeschlagen sind und der erste davon mindestens 3 Tage zurückliegt, deaktiviert QMailing den Endpunkt und benachrichtigt den Kontoinhaber per E-Mail. Beide Bedingungen müssen erfüllt sein — ein kurzer Ausfall bei einem viel genutzten Endpunkt oder ein einzelner Fehler bei einem ruhigen schaltet ihn nie ab —, und jede 2xx-Antwort setzt die Serie zurück. Solange er deaktiviert ist, wird nichts gesendet, und noch eingereihte Zustellungen enden als PERMANENTLY_FAILED. Lesezugriffe zeigen enabled: false und status: DISABLED_FAILING mit dem Grund in last_error. Ist der Empfänger repariert, schalten Sie den Endpunkt auf /settings/developers mit seinem Schalter wieder ein — er startet mit frischer Serie (auch das Rotieren des Signing-Secrets aktiviert einen vom Worker abgeschalteten Endpunkt wieder). Mit demselben Schalter können Sie einen Endpunkt auch selbst abschalten; ein vom QMailing-Support deaktivierter und gesperrter bleibt aus, bis der Support ihn wieder einschaltet.

Letzte Zustellungen auflisten

GET /api/v1/pub/webhooks/{endpointId}/deliveries?limit=100
# scopes: webhooks:read OR webhooks:write

Liefert die letzten limit Zustellungen eines einzelnen Endpunkts (Default 100, max 100), neueste zuerst. Jede Zeile enthält Status, Versuchszähler, letzten HTTP-Code, letzte Fehlermeldung und das Original-Payload-JSON — versorgt die History-Ansicht im Developer-Dashboard.

Testzustellung senden

POST /api/v1/pub/webhooks/{endpointId}/test
# scope: webhooks:write
# Response 202: WebhookDeliveryDto (enqueued, picked up next worker tick)

Feuert ein synthetisches webhook.test-Ereignis am Endpunkt ab — derselbe Dispatch-Pfad wie echte Ereignisse, nützlich zur Verifikation von Signatur + TLS vor dem Abonnieren von Live-Traffic. Liefert 409, solange der Endpunkt deaktiviert ist oder bereits 20 fällige Zustellungen für diesen Endpunkt auf den Empfänger warten — senden Sie den Test erneut, sobald er wieder aktiv ist bzw. sie raus sind.

Zustellung wiederholen

POST /api/v1/pub/webhooks/deliveries/{deliveryId}/retry
# scope: webhooks:write
# Response 200: WebhookDeliveryDto (status=PENDING, attempt=MAX-1)

Stellt eine Zustellungszeile manuell wieder in die Queue. Liefert 409 für bereits zugestellte Zeilen und für eine Zeile, deren Zustellversuch gerade läuft (warten Sie das Ende des Versuchs ab und laden Sie die Zeile neu). Der Retry gibt genau einen weiteren Versuch (Zähler auf MAX-1), sodass ein dauerhaft kaputter Endpunkt nicht durch wiederholte Klicks endlos geloopt wird.

Zustellung aus History löschen

DELETE /api/v1/pub/webhooks/deliveries/{deliveryId}
# scope: webhooks:write
# Response: 204 No Content

Hard-Delete einer Zustellungszeile aus der History-Tabelle. Das Compliance-Audit-Log erfasst das Löschen selbst, sodass Traceability auch ohne die Zeile erhalten bleibt.

Endpunkt widerrufen

DELETE /api/v1/pub/webhooks/{id}
# scope: webhooks:write
# Response: 204 No Content

Idempotent — das Widerrufen eines bereits widerrufenen Endpunkts gelingt geräuschlos. Die Zeile bleibt erhalten (revoked-at-Zeitstempel gesetzt), damit Audit-Logs ihre Referenzen behalten.

Limit: 10 aktive Endpunkte pro Konto, 32 Ereignisse pro Endpunkt. Beides wird bei der Registrierung erzwungen — 409 WebhookEndpointLimitExceeded / 400 InvalidWebhookEvent.

Fehler

Jede Antwort, die nicht 2xx ist, ist ein RFC-7807-ProblemDetail mit einem stabilen code-Feld, auf das Ihr Agent verzweigen kann:

HTTPcodeWann
400InvalidApiTokenScopeUnbekannter Scope-String beim Anlegen.
400InvalidEmailAddressEin Empfänger hat die RFC-5322-Syntaxprüfung nicht bestanden.
400InvalidWebhookEventDie registrierte Ereignisliste enthält einen unbekannten Ereignisnamen.
401—Bearer-Header fehlt, ist fehlerhaft, oder Token wurde widerrufen / ist abgelaufen.
402PlanFeatureRequiredAufrufer hat einen Plan ohne API-Zugang — Upgrade nötig.
403InsufficientScopeToken enthält keinen der erforderlichen Scopes.
404ApiTokenNotFoundWiderrufsziel existiert nicht oder gehört zu einem anderen Konto.
409MailboxNotVerifiedDie Domain des Sende-Postfachs ist noch nicht vollständig verifiziert — DNS in /settings/domains abschließen.
409AttachmentQuarantinedDownload verweigert: Die Datei steht unter Quarantäne, weil sie zu einer eingeschränkten E-Mail gehört (nicht verifizierter Absender oder Spam).
409ApiTokenLimitExceededKonto hat das Maximum (20) aktiver Token erreicht; widerrufen Sie zuerst eines.
409WebhookEndpointLimitExceededKonto hält bereits 10 aktive Webhook-Endpunkte; widerrufen Sie zuerst einen.
429RateLimitExceededToken hat 300 Anfragen pro Minute überschritten. Retry-After in Sekunden.

Rate Limits

Jedes Token erhält einen eigenen Bucket von 300 Anfragen pro Minute. Multi-Agent-Setups (CLI + Cron + IDE-Plugin) mit unterschiedlichen Token für dasselbe Konto laufen unabhängig — sie kämpfen nie um einen gemeinsamen Bucket. 429 RateLimitExceeded enthält einen Retry-After-Header in Sekunden.

MCP-Server

Das Paket @qmailing/mcp-server läuft lokal und stellt die öffentliche API als Werkzeuge des Model Context Protocol bereit. Binden Sie es in Claude Desktop, Cursor, Continue oder einen beliebigen MCP-kompatiblen Client ein.

Das Wire-Format ist stabil — aber in jedem 0.x-Release können neue Werkzeuge hinzukommen. Pinnen Sie eine bestimmte Version (@qmailing/mcp-server@0.2.0), wenn Sie keine automatischen Upgrades wünschen.
{
  "mcpServers": {
    "qmailing": {
      "command": "npx",
      "args": ["-y", "@qmailing/mcp-server"],
      "env": {
        "QMAILING_API_TOKEN": "qm_live_your_token_here"
      }
    }
  }
}

Mitgelieferte Werkzeuge: qmailing_list_mailboxes, qmailing_get_mailbox, qmailing_create_mailbox, qmailing_list_domains, qmailing_get_dns_records, qmailing_list_emails, qmailing_get_email, qmailing_get_attachment, qmailing_send_email, qmailing_register_webhook, qmailing_list_webhooks, qmailing_delete_webhook. Der Katalog wächst, sobald neue Endpunkte hinzukommen.

Einen Bug gefunden oder eine Frage? Token, Scopes, Plan-Limits und Rate-Limit-Zähler sind alle auf Ihrer Entwicklerseite einsehbar.

QMailing

Erstelle Postfächer, keine Konten.

Produkt

  • Alles, was Sie brauchen
  • Preise
  • Vergleich
  • Anwendungsfälle
  • API & MCP

Rechtliches

  • Datenschutzrichtlinie
  • Nutzungsbedingungen
  • Rückerstattung
  • Datenlöschung

Support

  • Support kontaktieren
© 2026 QMailing. Alle Rechte vorbehalten.