API reference · v1

Super Mail Hub API documentation

Everything needed to authenticate, send transactional email, track delivery, handle failures, and verify signed webhooks.

Base URLhttps://your-domain.example/api/v1
Overview

Authenticate every request with a scoped key

Create a key in Workspace → API & SMTP. Send it as a Bearer token from trusted server-side code. The full secret is shown once and must never be committed, logged, or exposed in frontend JavaScript.

Authorization header
Authorization: Bearer $SUPERMAILHUB_API_KEY
mail.sendQueue email through an active workspace mailbox.
mail.status.readRead status only for outbound messages in the same workspace.
JSON over HTTPSUse Content-Type: application/json for request bodies.
Asynchronous deliveryA 202 response means accepted, not yet delivered.
POST/api/v1/send

Queue a transactional email

Validates the workspace, sender mailbox, recipient, plan limits, suppressions, and attachments before accepting the message for asynchronous delivery.

Required scopemail.send

JSON request body

FieldTypeDescription
mailboxId *uuid

An active mailbox owned by the API key’s workspace.

recipient *email

One valid recipient address. Suppressed recipients are rejected.

subject *string

Message subject. Line breaks are not accepted.

bodyText *string

Plain-text message content.

attachmentsAttachment[]

Optional. Up to 10 files and 20 MB decoded total; every file is malware-scanned.

attachments[].filenamestring

Safe display filename without line breaks.

attachments[].contentTypeMIME type

Defaults to application/octet-stream.

attachments[].contentBase64base64

Required attachment bytes encoded with standard Base64.

cURL · send request
curl -X POST https://your-domain.example/api/v1/send \
  -H "Authorization: Bearer $SUPERMAILHUB_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mailboxId": "YOUR_MAILBOX_ID",
    "recipient": "customer@example.com",
    "subject": "Your receipt",
    "bodyText": "Thanks for your order."
  }'

Responses

202Accepted and queued. Store the returned message ID.
400Invalid JSON, sender, recipient, subject, or attachment.
401Missing, invalid, or revoked API key.
402API sending is unavailable on the current plan.
403Missing mail.send scope or blocked workspace.
422Recipient is on the workspace suppression list.
429Rolling-hour, daily, or monthly sending limit reached.
GET/api/v1/messages/{messageId}

Read message delivery status

Returns the current queue-processing state plus provider-reported delivery, bounce, and complaint events for an outbound message in the authenticated workspace.

Required scopemail.status.read

Path parameters

FieldTypeDescription
messageId *uuid · path

The id returned by POST /api/v1/send.

cURL · status request
curl https://your-domain.example/api/v1/messages/MESSAGE_ID \
  -H "Authorization: Bearer $SUPERMAILHUB_API_KEY"

Responses

200Message, processingStatus, deliveryStatus, and delivery events.
400The message ID is not a valid UUID.
401Missing, invalid, or revoked API key.
403The key lacks mail.status.read.
404No matching outbound message exists in this workspace.
Delivery lifecycle

Processing state and provider outcome are separate

processingStatus describes Super Mail Hub’s queue. deliveryStatus advances when a receiving provider reports delivery, bounce, or complaint activity.

queuedWaiting for a delivery worker.
sendingClaimed by a worker.
sentSubmitted successfully over SMTP.
retryingSafe to retry because SMTP was not attempted.
failedConfirmed failure; no further automatic attempt.
delivery_unknownRemote acceptance cannot be proven; no retry to avoid duplicates.
deliveredProvider confirmed delivery.
soft_bounceTemporary provider rejection.
hard_bouncePermanent provider rejection.
complaintSpam complaint received.
Signed webhooks

Receive delivery changes without polling

Configure one public HTTPS endpoint in Workspace → API & SMTP. Return a 2xx response promptly. Failed deliveries use exponential backoff and stop after eight attempts.

Webhook-IdStable UUID for deduplicating retries.
Webhook-TimestampUnix timestamp used in the signature.
Webhook-Signaturev1= followed by the HMAC-SHA256 hex digest.

Supported event types

message.queuedAccepted into the delivery queue.
message.sendingA worker claimed the message.
message.sentSMTP submission completed.
message.retryingA safe pre-SMTP failure will be retried.
message.deliveredThe receiving provider reported delivery.
message.soft_bouncedA temporary provider rejection was reported.
message.hard_bouncedA permanent rejection was reported and the recipient is suppressed.
message.complainedThe recipient reported the message as spam.
message.failedDelivery reached a confirmed terminal failure.
message.delivery_unknownSMTP outcome is ambiguous; automatic retry is disabled to prevent duplicates.
webhook.testA dashboard-generated endpoint test.

Signature verification · Node.js

HMAC verification
const signed = timestamp + '.' + rawRequestBody;
const expected = 'v1=' + crypto
  .createHmac('sha256', process.env.SUPERMAILHUB_WEBHOOK_SECRET)
  .update(signed)
  .digest('hex');

const supplied = Buffer.from(signature || '');
const calculated = Buffer.from(expected);
if (supplied.length !== calculated.length ||
    !crypto.timingSafeEqual(supplied, calculated)) {
  throw new Error('Invalid webhook signature');
}

Replay protection: compute the signature from the unmodified raw body, reject stale timestamps, compare signatures in constant time, and deduplicate using Webhook-Id.

Errors and limits

Handle failures deliberately

4xx responsesCorrect the request, credentials, entitlement, suppression, or quota condition. Do not retry blindly.
5xx responsesRetry with exponential backoff and jitter. Preserve the original message ID when one was returned.
AttachmentsMaximum 10 files and 20 MB decoded total. Scanning must succeed before queue admission.
Ambiguous SMTPdelivery_unknown is intentionally not retried because the remote server may already have accepted the message.

All error responses contain an error string. Upgrade responses can also include code: "upgrade_required" and an upgradeUrl.