QMailing
ПродуктТарифиAPI та MCP
Увійти

Документація

Публічне API та MCP-сервер

Створюй агентів, CLI та бек-офіс інтеграції на основі qmailing. PLUS та вище відкриває аутентифікацію через Bearer-токен на кожному публічному ендпоінті, а також готовий MCP-сервер, який можна підключити до Claude Desktop, Cursor чи будь-якого іншого сумісного клієнта.

Почати Керувати токенами

На цій сторінці

  • 1. Початок роботи
  • 2. Аутентифікація
  • 3. Скоупи
  • 4. Поштові скриньки
  • 5. Домени та DNS
  • 6. Електронна пошта
  • 7. Вебхуки
  • 8. Помилки
  • 9. Обмеження частоти
  • 10. MCP-сервер

Початок роботи

  1. 1. Перейди на PLUS — публічне API доступне на PLUS, PRO, PRO_PLUS чи PRO_MAX. Виклики з FREE отримують 402 Payment Required незалежно від токена.
  2. 2. Створи токен — перейди в Налаштування → Розробники, натисни Новий токен, обери потрібні скоупи та скопіюй значення qm_live_…, коли воно зʼявиться. Токени показуються лише один раз.
  3. 3. Зроби свій перший виклик:
    curl https://qmailing.com/api/v1/pub/mailboxes \
      -H "Authorization: Bearer qm_live_your_token_here"

Аутентифікація

Кожен виклик публічного API містить заголовок Authorization: Bearer qm_live_<…>. Формат токена має префікс (qm_live_ з 32 випадковими символами), щоб витоки в логах і репозиторіях одразу впадали в око.

Токени зберігаються у вигляді хешу (SHA-256). Відкритий текст показується рівно один раз під час створення і більше ніколи — якщо ти його втратиш, створюй новий. Кожен запит виконує порівняння хешу з постійним часом; last_used_at оновлюється у разі успіху, тож UI розробників може показувати застарілі облікові дані.

Пониження плану одразу деактивує існуючі токени. API повторно перевіряє apiAccess на кожному підписаному запиті — немає потреби відкликати токени окремо при зміні плану.

Скоупи

Кожен токен містить один або більше рядків скоупу. Ендпоінти оголошують потрібні їм скоупи; відсутні скоупи призводять до 403 InsufficientScope. Підстановка (*) надає все — вмикай лише тоді, коли це справді потрібно.

СкоупДозволяє
mailboxes:readПереглядати та інспектувати поштові скриньки
mailboxes:writeСтворювати, змінювати, видаляти поштові скриньки
domains:readПереглядати домени та DNS-записи
domains:writeДодавати, верифікувати, видаляти власні домени (лише через FE у v1)
email:readЧитати та переглядати листи у скриньках
email:sendНадсилати вихідні листи через API
webhooks:readПереглядати ендпоінти вебхуків
webhooks:writeРеєструвати, переглядати та відкликати ендпоінти вебхуків
*Підстановка — надає все. Використовуй обачно.

Поштові скриньки

Список

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

Отримати одну

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

Створити

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

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

Поле domain необовʼязкове — пропусти його, і скриньку буде створено на qmailing.com. На власному домені він має бути одночасно claimed ТА fullyVerified; ще не готовий домен повертає 400 замість того, щоб мовчки створити нероботящу скриньку.

Видалення поштової скриньки навмисно не доступне в v1. Воно фіксує згоду з умовами користування й використовує слот пожиттєвої квоти акаунта — те й інше має робити людина, що натискає кнопку після прочитання модалки, а не автоматичний агент. Користуйся фронтендом.

Домени та DNS

Список власних доменів

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

Перелік DNS-записів

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

Повертає повний перелік з 8 записів (challenge TXT, MX, SPF, три DKIM CNAME, DMARC, опційний _amazonses) із status для кожного рядка: PENDING / FOUND / MISMATCH / NOT_REQUIRED. Агент може використати це, щоб підказати користувачу, що саме опублікувати у свого DNS-провайдера.

Електронна пошта

Читай вміст скриньок та надсилай вихідні листи. Пагінація за папками збігається з внутрішнім API фронтенду — агенти, що мігрують з cookie-JWT на Bearer, не побачать жодних змін у формі відповіді.

Список за папкою

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 за замовчуванням INBOX; допустимі значення: INBOX, SENT, DRAFTS, TRASH, STARRED, SPAM. mailboxId необовʼязковий — без нього список повертається з усіх скриньок викликача. Пагінація через offset + limit; limit обмежено діапазоном 1–100 (за замовчуванням 25).

Отримати один

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

Повертає повний EmailDetailDto: HTML / текст листа, список ярликів, метадані вкладень. Самі вкладення не вкладаються в тіло — кожне завантажуй наведеним нижче GET /{emailId}/attachments/{index}, який стрімить сирі байти з оригінальною назвою файла та content-type.

Завантаження вкладення

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

Стрімить сирі байти вкладення (індекс від нуля у списку вкладень листа). Той самий формат, що й сесійний ендпоінт: pass-through Content-Type, Content-Disposition за RFC 6266 з оригінальною назвою файла (UTF-8 percent-encoded для Unicode). MCP-агенти, які звертаються через @qmailing/mcp-server, використовують інструмент qmailing_get_attachment, що повертає байти в base64 (ліміт 5 MiB).

Надіслати

Ендпоінт надсилання. Тіло multipart/form-data з однією JSON-частиною command, що містить отримувачів / тему / тіло, та з нулем або більше частинами-файлами 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--

Структура 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"
}

Кожен виклик враховується у щоденному ліміті відправки за планом, у квоті відправки SES для скриньки та у квоті сховища для копії в SENT. Адреси отримувачів перевіряються за RFC 5322; невалідні повертають 400 з конкретною адресою. Скринька, на яку посилається mailboxId, має бути верифікованою в SES — інакше отримаєш 409 MailboxNotVerified з підказкою, яка веде на сторінку доменів.

Агенти, яким зручніше працювати з JSON, можуть використати MCP-інструмент із комплекту — він кодує вкладення в base64 у JSON, а на виході перепаковує їх у multipart/form-data, тож формат на дроті залишається ідентичним.
filename на command-частині не обовʼязковий — Node fetch автоматично штампує filename="blob" на кожен Blob, браузерні та Node-клієнти можуть передавати command.json, а коректні curl --form клієнти можуть взагалі його опустити. Усі три варіанти парсяться однаково; значення має лише Content-Type: application/json на байтах частини.

Скоупи: email:read для списку та get-one, email:send для надсилання.

Вебхуки

Зареєструй HTTPS-ендпоінт, і QMailing POSTитиме підписаний JSON-конверт на нього щоразу, коли спрацьовує одна з підписаних подій. Доставка жива — воркер опитує per-event чергу кожні 10 с, підписує кожен запит HMAC-SHA256 і повторює невдачі за експоненційним backoff-ом (1 хв / 5 хв / 15 хв / 1 год / 6 год), після чого паркує рядок у DLQ для ручного огляду.

Зареєструвати ендпоінт

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 має бути HTTPS-ендпоінтом (HTTP дозволено лише для localhost у dev). Хост перевіряється за allow-list проти SSRF — приватні / loopback / cloud-metadata адреси відхиляються вже на реєстрації. У відповіді plaintext приходить рівно один раз; збережи його на сервері та використовуй для перевірки HMAC-підпису вхідних подій.

Каталог подій

ПодіяСпрацьовує коли
email.receivedВхідний лист прийшов в одну з твоїх скриньок.
email.sentВихідний лист прийнято SES.
email.bouncedВихідний лист повернувся з помилкою (hard або soft bounce).
domain.verifiedВласний домен повністю пройшов DNS-верифікацію.

Список ендпоінтів

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

Повертає активні та відкликані ендпоінти, нові спочатку. Доступ на читання працює і з webhooks:read, і з webhooks:write — інспекторський токен може уникати ширшого write-скоупу.

Формат доставки

Кожна доставка — це один POST на твій ендпоінт із Content-Type: application/json. Тіло — конверт події з полями event (імʼя події), occurred_at (ISO-таймштамп) і блоком data, форма якого залежить від типу події (див. таблицю вище). Три хедери несуть routing і verification-метадані:

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

Схема підпису

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

Відхиляй запит, якщо timestamp старший за 5 хвилин (вікно проти replay) або якщо обчислений HMAC не збігається з v1 hex — наш BE-підписувач точно повторює конвенції Stripe / GitHub, тож будь-яка стандартна бібліотека для верифікації працюватиме з коробки.

Політика повторів

Не-2xx відповіді (або transport-помилки — DNS, TLS, connection refused, 10с timeout) інкрементують attempt_count і зсувають next_attempt_at на наступний слот у 1 хв / 5 хв / 15 хв / 1 год / 6 год. Після пʼятої невдачі доставка переходить у FAILED (DLQ) — видно на сторінці /settings/developers, де розробник може повторити її вручну. Ідемпотентність: кожен retry несе той самий UUID у X-Qmailing-Delivery — приймачі дедуплікують за цим хедером.

Список останніх доставок

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

Повертає limit найсвіжіших доставок для одного ендпоінту (default 100, max 100), нові спочатку. Кожен рядок містить статус, лічильник спроб, останній HTTP-код, рядок помилки і оригінальний JSON payload — все, що потрібно для history-вʼю на дашборді розробника.

Надіслати тестову доставку

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

Випускає синтетичну подію webhook.test на ендпоінт — той самий шлях dispatch-у, що й справжні події; корисно для перевірки підпису + TLS перш ніж підписатись на живий трафік.

Повторити доставку

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

Вручну повторно додає рядок доставки в чергу. Не можна повторити вже-DELIVERED рядок (409). Повтор дає рівно одну додаткову спробу (лічильник скидається до MAX-1), тож постійно зламаний ендпоінт не зациклитися від багаторазових кліків.

Видалити доставку з історії

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

Hard-delete рядка доставки з таблиці історії. Compliance audit-log зберігає сам факт видалення, тож traceability не втрачається, навіть якщо рядка більше нема.

Відкликати ендпоінт

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

Ідемпотентно — відкликання вже відкликаного завершується тихим успіхом. Рядок зберігається (виставляється revoked-at), щоб журнали аудиту не втрачали посилання.

Ліміт: 10 активних ендпоінтів на акаунт, 32 події на ендпоінт. Обидва перевіряються при реєстрації — 409 WebhookEndpointLimitExceeded / 400 InvalidWebhookEvent.

Помилки

Кожна відповідь з кодом, відмінним від 2xx, є RFC-7807 ProblemDetail зі стабільним полем code, на яке твій агент може реагувати:

HTTPcodeКоли
400InvalidApiTokenScopeНевідомий рядок скоупу під час створення.
400InvalidEmailAddressОдин з отримувачів не пройшов перевірку синтаксису RFC 5322.
400InvalidWebhookEventСписок зареєстрованих подій містить невідому назву.
401—Bearer-заголовок відсутній, некоректний, або токен відкликано / прострочено.
402PlanFeatureRequiredВикликач на плані без доступу до API — підвищ план.
403InsufficientScopeТокен не має жодного з потрібних скоупів.
404ApiTokenNotFoundЦіль для відкликання не існує або належить іншому акаунту.
409MailboxNotVerifiedДомен скриньки ще не повністю верифікований — заверши DNS у /settings/domains.
409ApiTokenLimitExceededАкаунт містить максимум (20) активних токенів; спочатку відклич один.
409WebhookEndpointLimitExceededНа акаунті вже 10 активних ендпоінтів вебхуків; спочатку відклич один.
429RateLimitExceededТокен перевищив 300 запитів за хвилину. Retry-After у секундах.

Обмеження частоти

Кожен токен має власну корзину на 300 запитів за хвилину. Багатоагентні налаштування (CLI + cron + плагін IDE), що використовують різні токени для одного акаунта, працюють незалежно — вони ніколи не борються за одну спільну корзину. 429 RateLimitExceeded містить заголовок Retry-After у секундах.

MCP-сервер

Пакет @qmailing/mcp-server працює локально та надає публічне API як інструменти Model Context Protocol. Підключи його до Claude Desktop, Cursor, Continue або будь-якого MCP-сумісного клієнта.

Формат API стабільний — але в 0.x релізах можуть зʼявлятися нові інструменти. Пін конкретну версію (@qmailing/mcp-server@0.2.0), якщо не хочеш автоматичних оновлень.
{
  "mcpServers": {
    "qmailing": {
      "command": "npx",
      "args": ["-y", "@qmailing/mcp-server"],
      "env": {
        "QMAILING_API_TOKEN": "qm_live_your_token_here"
      }
    }
  }
}

Вбудовані інструменти: 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. Каталог зростає в міру появи нових ендпоінтів.

Знайшов баг чи маєш питання? Токени, скоупи, ліміти плану та лічильники rate-limit можна побачити на сторінці розробників.

QMailing

Створюй скриньки, а не акаунти.

Продукт

  • Все, що потрібно
  • Тарифи
  • Порівняння
  • Сценарії
  • API та MCP

Правова інформація

  • Політика конфіденційності
  • Умови використання
  • Повернення коштів
  • Видалення даних

Підтримка

  • Звʼязатися з підтримкою
© 2026 QMailing. Усі права захищені.