Docs / Integration guide
Integration

Integrate Mailbot with any stack

Mailbot is a plain HTTPS API. Create an account, verify your sender domain, then any backend, app, or automation that can make an HTTP request can send transactional email through Mailbot.

Answer first: create an account and verify your sender domain first. After that, integration is one authenticated HTTPS request: POST https://api.mailbot.id/v1/send with your Mailbot API key and a JSON body containing to, subject, and text or html.

The integration model

Mailbot uses plain HTTPS and JSON. There is no proprietary protocol and no required client library. Every integration — a web app, a mobile backend, a cron job, a CI pipeline, a serverless function, or a no-code automation — performs the same three steps:

  1. Authenticate with the Bearer API key from your verified Mailbot account.
  2. POST a JSON body describing one email (to, subject, text and/or html) to /v1/send.
  3. Read the JSON response — a 202 on acceptance, or a documented error code you can act on.

The same endpoint powers every use case in these docs, from OTP and reset links to invoice, order, and alert emails.

Base URL & environments

PurposeValue
Production base URLhttps://api.mailbot.id
Send endpointPOST https://api.mailbot.id/v1/send
Service healthGET https://api.mailbot.id/v1/status
Standard test emailPOST https://api.mailbot.id/v1/test-email

Use the same base URL for integration and production. For safe testing, use the standard test endpoint and keep the base URL configurable in your app environment.

Authentication

Every send is authenticated with a developer API key passed as a Bearer token:

HTTP
Authorization: Bearer mb_live_xxx
Content-Type: application/json
  • Keep the key server-side. Never embed it in browser JavaScript, mobile binaries, or public repositories.
  • Store it in an environment variable or secret manager (for example MAILBOT_API_KEY).
  • A missing, unknown, or revoked key returns 401 Unauthorized.
Never expose secrets. The Bearer key is your Mailbot API key for /v1/send. Keep it server-side and never share it with end users or ship it to clients.

JSON request contract

Send POST /v1/send with a single JSON object describing one email.

FieldTypeRequiredNotes
tostringYesOne recipient email address.
subjectstringYesUp to 998 characters.
textstringOne of text/htmlPlain-text body.
htmlstringOne of text/htmlHTML body. You may send both text and html.
fromstringNoVerified sender. If omitted, Mailbot uses the sender configured for your account.
idempotency_keystringNoUp to 128 characters. See Idempotency.
JSON request
{
  "from": "noreply@yourdomain.com",
  "to": "user@example.com",
  "subject": "Your verification code",
  "text": "Your code is 884921",
  "html": "<p>Your code is <strong>884921</strong></p>",
  "idempotency_key": "otp-user-142-1718000000"
}

JSON response contract

On acceptance the API returns HTTP 202 and a JSON body with an id you can log for correlation. Production queue mode returns queued; dry-run validation returns validated; delivery mode returns sent after handoff succeeds.

JSON response · queued
{
  "ok": true,
  "id": "msg_3f8c1a...",
  "status": "queued"
}
JSON response · validated
{
  "ok": true,
  "id": "msg_3f8c1a...",
  "status": "validated",
  "note": "Validated by Mailbot ID. No email was sent."
}

Always read ok and the HTTP status. Use id for your own logging and correlation.

Copy-paste code examples

The same request in four common stacks. Each reads the key from an environment variable and sends one email.

cURL
curl https://api.mailbot.id/v1/send \
  -H "Authorization: Bearer $MAILBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "subject": "Your verification code",
    "text": "Your code is 884921"
  }'
Node.js (fetch)
const res = await fetch("https://api.mailbot.id/v1/send", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.MAILBOT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    to: "user@example.com",
    subject: "Your verification code",
    text: "Your code is 884921",
  }),
});

const data = await res.json();
if (!res.ok) throw new Error(data.error || "Mailbot send failed");
console.log(data.id, data.status);
Python (requests)
import os, requests

res = requests.post(
    "https://api.mailbot.id/v1/send",
    headers={
        "Authorization": f"Bearer {os.environ['MAILBOT_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "to": "user@example.com",
        "subject": "Your verification code",
        "text": "Your code is 884921",
    },
    timeout=15,
)

data = res.json()
res.raise_for_status()
print(data["id"], data["status"])
PHP / Laravel (HTTP client)
use Illuminate\Support\Facades\Http;

$response = Http::withToken(env('MAILBOT_API_KEY'))
    ->acceptJson()
    ->post('https://api.mailbot.id/v1/send', [
        'to' => 'user@example.com',
        'subject' => 'Your verification code',
        'text' => 'Your code is 884921',
    ]);

$response->throw();
$data = $response->json();
// $data['id'], $data['status']

Serverless & no-code automation

Any platform that can make an outbound HTTP request can call Mailbot. Configure a generic HTTP/webhook action with these settings — the same contract applies whether it runs on a serverless function, a workflow automation, or a no-code tool:

SettingValue
MethodPOST
URLhttps://api.mailbot.id/v1/send
HeaderAuthorization: Bearer <your key>
HeaderContent-Type: application/json
Body (JSON){ "to": "...", "subject": "...", "text": "..." }
Map the platform's variables into the JSON body fields. Store the API key in the platform's secret/credential store, not in the workflow body.

Safe testing

Mailbot gives you a standard test endpoint for checking an integration safely:

  • POST /v1/test-email: sends a standardized Mailbot test message to an address you control. It accepts to, optional from, optional label, and optional idempotency_key.
cURL · test email
curl https://api.mailbot.id/v1/test-email \
  -H "Authorization: Bearer $MAILBOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "safe@yourdomain.com", "label": "Smoke test" }'
For the first delivery test, use an address you control. You can also send a test from the dashboard.

Error handling & common failures

Errors return a non-2xx HTTP status and a JSON body with an error string (and details for validation errors). Handle these explicitly:

StatusMeaningWhat to do
400Invalid payload (bad/missing to, missing subject, or no body).Read details and fix the request. Do not retry unchanged.
401Missing, unknown, or revoked API key.Check the Authorization header and key status.
403Recipient or sender is not allowed for this account.Use an address you control and a verified sender.
429Daily or monthly send limit reached.Back off and retry later, or increase capacity with kredit/Pro.
502Delivery handoff could not be completed.Retry with backoff using the same idempotency_key.
503Mailbot is temporarily unable to accept the send.Retry later with the same idempotency_key.
JSON response · 400 invalid
{
  "error": "Invalid send request.",
  "details": ["Field \"to\" must be an email address."]
}

Idempotency & retries

Include an optional idempotency_key (up to 128 characters) on any send you might retry — for example, a value derived from your internal event id.

  • A repeated request from the same account with the same idempotency_key can return the same accepted id instead of creating a duplicate.
  • Use a stable value from your own system, such as an order id, invoice id, or alert event id.
  • Keep the same key when retrying after a timeout or temporary 5xx response.
Recommended: always set idempotency_key on retried sends, and retry only on 429, 502, 503, or network/timeout errors using exponential backoff. Do not retry 400 or 401 unchanged.

Production checklist

  • API key stored server-side in a secret manager, never shipped to clients.
  • Sender domain verified; from set to a verified address (or rely on the configured default sender).
  • idempotency_key set on every send that can be retried.
  • Explicit handling for 400, 401, 403, 429, 502, and 503.
  • Retries limited to 429/5xx/network errors with exponential backoff.
  • Request timeouts set on your HTTP client.
  • Integration smoke-tested with /v1/test-email and verified against /v1/status before relying on live delivery.