Mailkub
Back to home

Mailkub API reference

Fetch mail, send mail, push inbound mail from a backend, and tag KTB / SCB transfer modes. No login required to read this page — share it with any developer.

Public page — no Mailkub login required. Share this URL with a developer.

Full reference for the Mailkub public API — use it to fetch mail, send mail, and pull a message's content into another system.

Overview

The Mailkub API lets an external system connect to one mailbox to fetch mail (list & read messages), send mail, push inbound mail from a backend, and pull a message's full content for display elsewhere. Put the mailbox address and API key in your backend — SMTP mail to you@yourdomain.com lands here automatically, or POST to /messages/inbound. Every API key created in the Keys tab is scoped to exactly one mailbox.

Base URL: https://mailkub.cloud/api/v1JSON over HTTPS

Authentication

Send the API key as a Bearer token on every request. Keys look like mk_live_… and are only ever shown once, right after you create them in the Keys tab.

Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx

Requests without a valid, non-revoked key for an active mailbox get 401 Unauthorized.

Quick start

Verify a key and see the mailbox it's scoped to:

curl "https://mailkub.cloud/api/v1/mailbox" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "data": {
    "id": "cmb...",
    "emailAddress": "you@yourdomain.com",
    "displayName": "Sales",
    "domain": "acme.test",
    "status": "ACTIVE",
    "quotaBytes": 1073741824,
    "usedStorageBytes": 52428800,
    "folders": { "inbox": 12, "unread": 3, "sent": 40, "starred": 2, "drafts": 1, "trash": 0, "spam": 0 },
    "transferModes": [
      { "value": "KTB_AUTO", "label": "KTBอัตโนมัติ", "description": "โอนผ่าน KTB Business API" },
      { "value": "EXPORT_KTB_BULK", "label": "ExportKTBBulk", "description": "ส่งออกไฟล์สำหรับ KTB Business" },
      { "value": "EXPORT_SCB_ANYWHERE", "label": "ExportSCBAnywhere", "description": "ส่งออกไฟล์สำหรับ SCB Anywhere" }
    ]
  }
}

1. ดึงข้อมูล — List messages

GET/messages

List messages in a folder

Paginated with a cursor. Defaults to the INBOX folder, newest first.

ParamTypeNotes
folderstringINBOX (default) | STARRED | SENT | DRAFT | TRASH | SPAM
limitnumber1–100, default 20
cursorstringid of the last message from the previous page
unreadtrue|falsefilter by read state
qstringfree-text search across subject/body/from/to
transferModestringKTB_AUTO | EXPORT_KTB_BULK | EXPORT_SCB_ANYWHERE (also accepts KTBอัตโนมัติ, ExportKTBBulk, ExportSCBAnywhere)
curl "https://mailkub.cloud/api/v1/messages?folder=INBOX&limit=20" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "data": [
    {
      "id": "cme_1",
      "threadId": "cmt_1",
      "from": "customer@example.com",
      "to": "you@yourdomain.com",
      "cc": null,
      "bcc": null,
      "subject": "Question about my order",
      "folder": "INBOX",
      "status": "RECEIVED",
      "isRead": false,
      "isStarred": false,
      "createdAt": "2026-09-08T10:15:00.000Z",
      "updatedAt": "2026-09-08T10:15:00.000Z",
      "snippet": "Hi, I wanted to ask about...",
      "hasAttachments": true,
      "transferMode": "KTB_AUTO"
    }
  ],
  "meta": { "count": 1, "nextCursor": null }
}

To page forward, call again with cursor=<meta.nextCursor> — repeat until nextCursor is null.

2. ส่งข้อมูล — Send a message

POST/messages

Send a message from this mailbox

ParamTypeNotes
to*string | string[]recipient address(es)
cc / bccstring | string[]optional
subjectstringoptional, defaults to empty
textstringplain-text body — text or html is required
htmlstringHTML body — text or html is required
inReplyTostringoptional Message-Id being replied to
transferModestringoptional: KTB_AUTO | EXPORT_KTB_BULK | EXPORT_SCB_ANYWHERE
attachments[]{ filename, contentType?, content }content is base64-encoded file bytes; max 10 files, 15 MB each
curl -X POST "https://mailkub.cloud/api/v1/messages" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "customer@example.com",
    "subject": "Re: Question about my order",
    "text": "Hi! Thanks for reaching out...",
    "transferMode": "KTB_AUTO",
    "attachments": [
      { "filename": "invoice.pdf", "contentType": "application/pdf", "content": "JVBERi0xLjQK..." }
    ]
  }'
// 201 Created
{
  "data": {
    "messageId": "<a1b2c3@acme.test>",
    "deliveredLocal": []
  }
}

deliveredLocal lists recipients that were delivered straight into another Mailkub mailbox on the same server (no outbound SMTP hop). Everyone else goes out over SMTP as usual.

3. ดึงแสดงข้อมูล — Fetch a message to display

GET/messages/:id

Get one message's full content

Returns the plain-text and HTML body plus attachment metadata — enough to render the message elsewhere. Does not mark it as read.

curl "https://mailkub.cloud/api/v1/messages/cme_1" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
{
  "data": {
    "id": "cme_1",
    "threadId": "cmt_1",
    "messageId": "<a1b2c3@example.com>",
    "inReplyTo": null,
    "from": "customer@example.com",
    "to": "you@yourdomain.com",
    "cc": null,
    "bcc": null,
    "replyTo": null,
    "subject": "Question about my order",
    "text": "Hi, I wanted to ask about...",
    "html": "<p>Hi, I wanted to ask about...</p>",
    "folder": "INBOX",
    "status": "RECEIVED",
    "isRead": false,
    "isStarred": false,
    "transferMode": "EXPORT_KTB_BULK",
    "createdAt": "2026-09-08T10:15:00.000Z",
    "updatedAt": "2026-09-08T10:15:00.000Z",
    "attachments": [
      {
        "id": "att_1",
        "filename": "receipt.png",
        "mimeType": "image/png",
        "size": 48213,
        "downloadUrl": "/api/v1/messages/cme_1/attachments/att_1"
      }
    ]
  }
}
GET/messages/:id/attachments/:attachmentId

Download an attachment

Streams the raw file by default. Add ?format=base64 to get JSON with the file base64-encoded instead.

curl "https://mailkub.cloud/api/v1/messages/cme_1/attachments/att_1" -OJ \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

# or, as JSON/base64:
curl "https://mailkub.cloud/api/v1/messages/cme_1/attachments/att_1?format=base64" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx"
PATCH/messages/:id

Update read / starred / folder state

Send only the fields you want to change.

curl -X PATCH "https://mailkub.cloud/api/v1/messages/cme_1" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "isRead": true }'
DELETE/messages/:id

Move to Trash

Calling it again on a message already in Trash permanently deletes it (same as the web app).

4. ใส่ API หลังบ้าน — inbound mail

Save the API key on your backend. SMTP mail sent to you@yourdomain.com arrives automatically. If the other system cannot send SMTP, have it POST here and the message lands in this inbox the same way — webhook included.

POST/messages/inbound

Push incoming mail into this mailbox

Always delivers to the mailbox this API key belongs to. Use transferMode to tag KTB / SCB channels from the transfer-mode picker.

ParamTypeNotes
from*stringsender address
tostring | string[]optional; stored against this mailbox
subjectstringoptional
text / htmlstringat least subject, text, or html
transferModestringKTB_AUTO | EXPORT_KTB_BULK | EXPORT_SCB_ANYWHERE — also accepted as header X-Transfer-Mode
attachments[]{ filename, contentType?, content }content is base64; use this for KTB Bulk / SCB Anywhere export files
curl -X POST "https://mailkub.cloud/api/v1/messages/inbound" \
  -H "Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "X-Transfer-Mode: ExportKTBBulk" \
  -d '{
    "from": "payroll@company.com",
    "subject": "KTB Bulk payment file",
    "text": "Attached is the KTB Business export.",
    "transferMode": "ExportKTBBulk",
    "attachments": [
      { "filename": "ktb-bulk.txt", "contentType": "text/plain", "content": "S1RCIGJ1bGsgZmlsZQ==" }
    ]
  }'
// 201 Created
{
  "data": { "accepted": ["you@yourdomain.com"] }
}
transferModeUI labelMeaning
KTB_AUTOKTBอัตโนมัติโอนผ่าน KTB Business API
EXPORT_KTB_BULKExportKTBBulkส่งออกไฟล์สำหรับ KTB Business
EXPORT_SCB_ANYWHEREExportSCBAnywhereส่งออกไฟล์สำหรับ SCB Anywhere

5. Webhooks — get notified the moment mail arrives

Instead of polling GET /messages, set a webhook URL in the Webhook tab and Mailkub will POST a JSON payload to it the instant new mail lands in this mailbox. A common pattern: your test/automation requests a password reset on some third-party site using you@yourdomain.com as the address — the moment their recovery email arrives here, your endpoint is called with the full message so you can pull out the code or link without a polling loop.

Fires on event message.received — covers direct delivery, mailbox-to-mailbox delivery, auto-replies, and forwards. It never fires for the copy Mailkub keeps in your own Sent folder when you send a message.

Request

ParamTypeNotes
Content-Typeheaderapplication/json
X-Mailkub-Eventheadermessage.received | webhook.test
X-Mailkub-Signatureheadert=<unix ms>,v1=<hmac-sha256 hex of `${t}.${body}`>
{
  "event": "message.received",
  "timestamp": "2026-09-09T10:15:00.000Z",
  "data": {
    "id": "cme_1",
    "threadId": "cmt_1",
    "messageId": "<a1b2c3@example.com>",
    "from": "no-reply@example.com",
    "to": "you@yourdomain.com",
    "cc": null,
    "bcc": null,
    "subject": "Reset your password",
    "text": "Your recovery code is 482913. It expires in 10 minutes.",
    "html": "<p>Your recovery code is <b>482913</b>...</p>",
    "folder": "INBOX",
    "isRead": false,
    "isStarred": false,
    "transferMode": "EXPORT_SCB_ANYWHERE",
    "createdAt": "2026-09-09T10:15:00.000Z",
    "attachments": []
  }
}

Verifying the signature (Node.js)

const crypto = require("crypto");

function isValidMailkubSignature(secret, header, rawBody) {
  const [tPart, vPart] = header.split(",");
  const timestamp = tPart.split("=")[1];
  const signature = vPart.split("=")[1];
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

// header = req.headers["x-mailkub-signature"], rawBody = the exact request body string
// secret = the whsec_... value shown once when you saved/regenerated the webhook

Respond with any 2xx status within 8 seconds. A non-2xx response or timeout triggers one retry after ~4 seconds — after that, Mailkub gives up and you'd need to fetch the message via GET /messages/:id instead.

Use the Send test event button in the Webhook tab to verify your endpoint is reachable before relying on it — it sends the same headers with event: "webhook.test".

Errors

Errors always look like this:

{ "error": { "code": "invalid_body", "message": "Provide `text` or `html`..." } }
ParamTypeNotes
400invalid_json / send_failedmalformed request or delivery failure
401unauthorizedmissing, invalid, or revoked API key
403mailbox_disabledthe mailbox this key belongs to is disabled
404not_foundmessage or attachment not found for this mailbox
413payload_too_largerequest body over the size limit
422invalid_query / invalid_bodyfailed schema validation
429rate_limitedtoo many requests — back off and retry

Rate limits

Up to 300 requests/minute per API key and 120 requests/minute per IP for authentication attempts. Exceeding either returns 429 — retry with backoff.

Node.js / JavaScript example

const API_KEY = process.env.MAILKUB_API_KEY;
const BASE_URL = "https://mailkub.cloud/api/v1";

async function listUnread() {
  const res = await fetch(`${BASE_URL}/messages?folder=INBOX&unread=true`, {
    headers: { Authorization: `Bearer ${API_KEY}` },
  });
  if (!res.ok) throw new Error((await res.json()).error.message);
  return (await res.json()).data;
}

async function sendMail({ to, subject, text }) {
  const res = await fetch(`${BASE_URL}/messages`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ to, subject, text }),
  });
  if (!res.ok) throw new Error((await res.json()).error.message);
  return (await res.json()).data;
}

Security notes

  • Keys are shown once, at creation. Mailkub only ever stores a one-way hash of the key.
  • Revoke a key immediately from the Keys tab if it may have leaked — the change takes effect instantly.
  • Each key is scoped to one mailbox only; create a separate key per mailbox/integration.
  • Always call the API over HTTPS and never embed a key in client-side code.