QMailing
ProduktCennikAPI i MCP
Zaloguj się

Dokumentacja

Publiczne API i serwer MCP

Buduj agentów, narzędzia CLI i integracje back-office na bazie qmailing. PLUS i wyżej odblokowuje uwierzytelnianie tokenem Bearer na każdym publicznym endpointcie oraz gotowy serwer MCP, który możesz podpiąć do Claude Desktop, Cursora lub dowolnego innego kompatybilnego klienta.

Zaczynaj Zarządzaj tokenami

Na tej stronie

  • 1. Pierwsze kroki
  • 2. Uwierzytelnianie
  • 3. Scope'y
  • 4. Skrzynki
  • 5. Domeny i DNS
  • 6. E-mail
  • 7. Webhooki
  • 8. Błędy
  • 9. Limity zapytań
  • 10. Serwer MCP

Pierwsze kroki

  1. 1. Przejdź na PLUS — publiczne API jest dostępne dla planów PLUS, PRO, PRO_PLUS i PRO_MAX. Wywołania z FREE otrzymują 402 Payment Required niezależnie od tokena.
  2. 2. Wygeneruj token — wejdź w Ustawienia → Programiści, kliknij Nowy token, wybierz potrzebne scope'y i skopiuj wartość qm_live_…, gdy się pojawi. Tokeny pokazują się tylko raz.
  3. 3. Wykonaj pierwsze wywołanie:
    curl https://qmailing.com/api/v1/pub/mailboxes \
      -H "Authorization: Bearer qm_live_your_token_here"

Uwierzytelnianie

Każde wywołanie publicznego API zawiera nagłówek Authorization: Bearer qm_live_<…>. Format tokena ma prefiks (qm_live_ z 32 losowymi znakami), dzięki czemu wycieki w logach i repozytoriach są od razu widoczne.

Tokeny są przechowywane w postaci hasha (SHA-256). Tekst jawny jest pokazywany dokładnie raz w momencie wystawienia i nigdy więcej — jeśli go zgubisz, wygeneruj nowy. Każde żądanie wyzwala porównanie hasha w stałym czasie; last_used_at aktualizuje się przy sukcesie, dzięki czemu UI dla programistów może wskazywać przestarzałe poświadczenia.

Obniżenie planu natychmiast dezaktywuje istniejące tokeny. API ponownie sprawdza apiAccess przy każdym podpisanym żądaniu — przy zmianie planu nie trzeba odwoływać tokenów pojedynczo.

Scope'y

Każdy token zawiera jeden lub więcej ciągów scope. Endpointy deklarują, jakich scope'ów wymagają; brak wymaganego scope'a daje 403 InsufficientScope. Wieloznacznik (*) przyznaje wszystko — włączaj go tylko wtedy, gdy naprawdę go potrzebujesz.

ScopePozwala
mailboxes:readListować i przeglądać skrzynki
mailboxes:writeTworzyć, modyfikować i usuwać skrzynki
domains:readListować domeny i rekordy DNS
domains:writeDodawać, weryfikować i usuwać własne domeny (w v1 tylko z FE)
email:readListować i przeglądać wiadomości ze skrzynek
email:sendWysyłać pocztę wychodzącą przez API
webhooks:readListować endpointy webhooków
webhooks:writeRejestrować, listować i odwoływać endpointy webhooków
*Wieloznacznik — przyznaje wszystko. Stosuj oszczędnie.

Skrzynki

Lista

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

Pobierz jedną

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

Utwórz

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

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

Pole domain jest opcjonalne — pomiń je, a skrzynka zostanie utworzona w qmailing.com. Na własnej domenie domena musi być jednocześnie claimed ORAZ fullyVerified; nie gotowa domena zwraca 400, zamiast po cichu utworzyć nieroutowalną skrzynkę.

Usuwanie skrzynek celowo nie jest udostępniane w v1. Operacja ta zapisuje zgodę na Warunki świadczenia usług i zużywa slot dożywotniego limitu konta — oba elementy należą do osoby naciskającej przycisk po przeczytaniu modala, a nie do nienadzorowanego agenta. Skorzystaj z frontendu.

Domeny i DNS

Lista własnych domen

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

Lista rekordów DNS

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

Zwraca pełną listę 8 rekordów (TXT challenge, MX, SPF, trzy CNAME DKIM, DMARC, opcjonalnie _amazonses) z polem status dla każdego wiersza: PENDING / FOUND / MISMATCH / NOT_REQUIRED. Agent może z niej skorzystać, by precyzyjnie powiedzieć użytkownikowi, co opublikować u jego dostawcy DNS.

E-mail

Czytaj zawartość skrzynek i wysyłaj pocztę wychodzącą. Paginacja po folderach jest taka sama jak w wewnętrznym API frontendu — agenty migrujące z auth cookie-JWT na Bearer nie zobaczą zmian w kształcie odpowiedzi.

Listuj wg folderu

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

folder domyślnie to INBOX; dozwolone wartości: INBOX, SENT, DRAFTS, TRASH, STARRED, SPAM. mailboxId jest opcjonalny — bez niego listowane są wszystkie skrzynki wywołującego. Paginacja przez offset + limit; limit jest ograniczony do zakresu 1–100 (domyślnie 25).

Pobierz jedną

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

Zwraca pełny EmailDetailDto: treść HTML / tekst, listę etykiet, metadane załączników. Załączniki NIE są inline — pobierz każdy poniższym GET /{emailId}/attachments/{index}, który strumieniuje surowe bajty z oryginalną nazwą pliku i typem MIME.

Pobieranie załącznika

GET /api/v1/pub/email/{emailId}/attachments/{index}
# scope: email:read
# response: streamed bytes, Content-Type from the attachment

Strumieniuje surowe bajty załącznika (indeks od zera w liście załączników wiadomości). Identyczny kształt jak endpoint sesyjny: pass-through Content-Type, Content-Disposition wg RFC 6266 z oryginalną nazwą pliku (UTF-8 percent-encoded dla znaków Unicode). Agenci MCP wywołujący przez @qmailing/mcp-server używają narzędzia qmailing_get_attachment, które zwraca bajty zakodowane base64 (limit 5 MiB).

Wyślij

Endpoint wysyłki. Body multipart/form-data z jedną częścią JSON command (odbiorcy / temat / treść) oraz zerem lub więcej częściami-plikami attachments:

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

Kształt JSON command:

{
  "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"
}

Każde wywołanie liczy się do dziennego limitu wysyłki w planie, do limitu wysyłki SES dla skrzynki oraz do limitu pojemności użytkownika dla powstałej kopii w SENT. Odbiorcy są walidowani jako adresy RFC 5322; nieprawidłowe zwracają 400 z błędnym adresem. Skrzynka wskazana w mailboxId musi być zweryfikowana w SES — w przeciwnym razie 409 MailboxNotVerified z odsyłaczem do strony domen.

Agenty preferujące JSON zamiast multipart mogą skorzystać z dołączonego narzędzia MCP — koduje załączniki inline w base64, a w drodze na zewnątrz przepakowuje je w multipart/form-data, dzięki czemu format na łączu pozostaje identyczny.
filename w części command jest opcjonalny — Node fetch automatycznie ustawia filename="blob" na każdym Blobie, klienci przeglądarkowi i Node mogą przekazywać command.json, a zgodne klienty curl --form mogą go pominąć. Wszystkie trzy formy są parsowane tak samo; liczy się tylko Content-Type: application/json na bajtach części.

Scope'y: email:read dla listy i pobierania jednej, email:send dla wysyłki.

Webhooki

Zarejestruj endpoint HTTPS, a QMailing wykona POST podpisanego envelope JSON za każdym razem, gdy zostanie wyzwolone jedno z subskrybowanych zdarzeń. Dostarczanie działa — worker odpytuje kolejkę per-event co 10s, podpisuje każde żądanie HMAC-SHA256 i ponawia niepowodzenia z wykładniczym backoffem (1m / 5m / 15m / 1h / 6h), po czym parkuje wiersz w DLQ do ręcznego przeglądu.

Zarejestruj endpoint

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"],
    "secretPrefix": "whk_AbCd",
    "createdAt":  "2026-05-04T20:30:00Z",
    "active":     true
  },
  "plaintext":  "whk_AbCd…<32 random chars>"   // shown ONCE
}

url musi być endpointem HTTPS (HTTP dozwolony tylko dla localhost w dev). Host jest sprawdzany względem allow-listy SSRF — adresy prywatne / loopback / cloud-metadata są odrzucane już przy rejestracji. Odpowiedź zawiera plaintext dokładnie raz; przechowuj go po stronie serwera i używaj do weryfikacji podpisów HMAC w przychodzących dostarczeniach.

Katalog zdarzeń

ZdarzenieWyzwala się gdy
email.receivedPrzychodzący e-mail trafił do jednej z twoich skrzynek.
email.sentWychodzący e-mail został zaakceptowany przez SES.
email.bouncedWychodzący e-mail zwrócił się (hard lub soft bounce).
domain.verifiedWłasna domena zakończyła pełną weryfikację DNS.

Listuj endpointy

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

Zwraca aktywne i odwołane endpointy, najnowsze pierwsze. Dostęp odczytu działa zarówno z webhooks:read, jak i webhooks:write — token inspektorski może w ten sposób uniknąć szerszego scope'a do zapisu.

Format dostarczenia

Każde dostarczenie to pojedynczy POST do Twojego endpointu z Content-Type: application/json. Body to envelope zdarzenia z polami event (nazwa zdarzenia), occurred_at (timestamp ISO) i blok data, którego kształt zależy od zdarzenia (patrz tabela wyżej). Trzy nagłówki niosą metadane routingu + weryfikacji:

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…"
  }
}

Schemat podpisu

# 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]));
}

Odrzuć żądanie, jeśli timestamp jest starszy niż 5 minut (okno anty-replay) lub jeśli przeliczony HMAC nie zgadza się z v1 hex — nasz podpisywacz BE wiernie odwzorowuje konwencje Stripe / GitHub, więc dowolna ze standardowych bibliotek weryfikacji zadziała od ręki.

Polityka ponawiania

Odpowiedzi inne niż 2xx (lub błędy transportu — DNS, TLS, odmowa połączenia, 10s timeout) inkrementują attempt_count i przesuwają next_attempt_at do kolejnego slotu w 1m / 5m / 15m / 1h / 6h. Po piątym niepowodzeniu dostarczenie przechodzi w FAILED (DLQ) — widoczne na /settings/developers, gdzie deweloper może je ręcznie ponowić. Idempotentność: każdy retry niesie ten sam UUID w X-Qmailing-Delivery — odbiorcy deduplikują po tym nagłówku.

Listuj ostatnie dostarczenia

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

Zwraca limit najnowszych dostarczeń pojedynczego endpointu (default 100, max 100), najnowsze pierwsze. Każdy wiersz zawiera status, licznik prób, ostatni kod HTTP, ostatni błąd i oryginalny payload JSON — zasila widok historii w panelu dewelopera.

Wyślij dostawę testową

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

Strzela syntetycznym zdarzeniem webhook.test w endpoint — ta sama ścieżka dispatchu co realne zdarzenia, przydatne do weryfikacji podpisu + TLS przed subskrypcją na żywy ruch.

Ponów dostarczenie

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

Ręcznie wstawia wiersz dostarczenia z powrotem do kolejki. Nie można ponowić wiersza już DELIVERED (409). Retry daje dokładnie jedną dodatkową próbę (licznik na MAX-1), więc trwale zepsuty endpoint nie zapętli się od powtarzanych kliknięć.

Usuń dostarczenie z historii

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

Hard-delete wiersza dostarczenia z tabeli historii. Log audytu compliance zapisuje samo usunięcie, więc traceability nie ginie, nawet gdy wiersz znika.

Odwołaj endpoint

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

Idempotentne — odwołanie już odwołanego endpointu kończy się cichym sukcesem. Wiersz jest zachowywany (z timestampem revoked-at), żeby logi audytu nie traciły referencji.

Limit: 10 aktywnych endpointów na konto, 32 zdarzenia na endpoint. Oba są egzekwowane przy rejestracji — 409 WebhookEndpointLimitExceeded / 400 InvalidWebhookEvent.

Błędy

Każda odpowiedź spoza 2xx to ProblemDetail RFC-7807 ze stabilnym polem code, na które twój agent może reagować:

HTTPcodeKiedy
400InvalidApiTokenScopeNieznany ciąg scope w momencie tworzenia.
400InvalidEmailAddressJeden z odbiorców nie przeszedł walidacji składni RFC 5322.
400InvalidWebhookEventLista zarejestrowanych zdarzeń zawiera nieznaną nazwę.
401—Brak nagłówka Bearer, jest niepoprawny, lub token został odwołany / wygasł.
402PlanFeatureRequiredWywołujący jest na planie, który nie obejmuje dostępu do API — wykonaj upgrade.
403InsufficientScopeToken nie zawiera żadnego z wymaganych scope'ów.
404ApiTokenNotFoundCel odwołania nie istnieje lub należy do innego konta.
409MailboxNotVerifiedDomena skrzynki nadawczej nie jest jeszcze w pełni zweryfikowana — dokończ DNS w /settings/domains.
409ApiTokenLimitExceededKonto osiągnęło maksymalną liczbę (20) aktywnych tokenów; najpierw odwołaj jeden.
409WebhookEndpointLimitExceededKonto ma już 10 aktywnych endpointów webhooków; najpierw odwołaj jeden.
429RateLimitExceededToken przekroczył 300 zapytań na minutę. Retry-After w sekundach.

Limity zapytań

Każdy token ma swój własny kubełek 300 zapytań na minutę. Konfiguracje wieloagentowe (CLI + cron + wtyczka IDE) używające różnych tokenów dla tego samego konta działają niezależnie — nigdy nie konkurują o jeden wspólny kubełek. 429 RateLimitExceeded zawiera nagłówek Retry-After w sekundach.

Serwer MCP

Pakiet @qmailing/mcp-server działa lokalnie i udostępnia publiczne API jako narzędzia Model Context Protocol. Podepnij go do Claude Desktop, Cursora, Continue lub dowolnego klienta zgodnego z MCP.

Format wymiany jest stabilny — ale w każdym wydaniu 0.x mogą pojawić się nowe narzędzia. Przypnij konkretną wersję (@qmailing/mcp-server@0.2.0), jeśli nie chcesz automatycznych aktualizacji.
{
  "mcpServers": {
    "qmailing": {
      "command": "npx",
      "args": ["-y", "@qmailing/mcp-server"],
      "env": {
        "QMAILING_API_TOKEN": "qm_live_your_token_here"
      }
    }
  }
}

Wbudowane narzędzia: 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. Katalog rośnie wraz z pojawianiem się nowych endpointów.

Znalazłeś błąd lub masz pytanie? Tokeny, scope'y, limity planu i liczniki rate-limit są dostępne na stronie programisty.

QMailing

Twórz skrzynki, nie konta.

Produkt

  • Wszystko, czego potrzebujesz
  • Cennik
  • Porównanie
  • Zastosowania
  • API i MCP

Informacje prawne

  • Polityka prywatności
  • Warunki korzystania
  • Zwroty
  • Usuwanie danych

Pomoc

  • Skontaktuj się z pomocą
© 2026 QMailing. Wszelkie prawa zastrzeżone.