Mailbots
Back to home

API

Programmatic access to your Mailbots account. Place orders, upload recipient lists, pull tracking data, and receive webhook notifications when pieces deliver or QR codes are scanned. REST + JSON, key-authed, the same model as Stripe.

Authentication

Every request needs an Authorization header with your API key. Keys start with mb_live_ (production) or mb_test_ (test mode). Mint keys at your dashboard and treat them like passwords โ€” they grant full account access at the scopes you select.

Authorization: Bearer mb_live_<your-key-here>

Endpoints

MethodPathDescriptionScope
POST/api/v1/ordersCreate a new order with quantity, message, and campaign options.orders.create
GET/api/v1/ordersList your orders. Filter by ?status=, paginate with ?limit=&offset=.orders.read
GET/api/v1/orders/:idOrder details + drops + payment status.orders.read
PATCH/api/v1/orders/:idUpdate message, sender info, return address, or cancel a draft.orders.update
DELETE/api/v1/orders/:idCancel a draft or pre-payment order.orders.delete
POST/api/v1/orders/:id/recipientsUpload your recipient list (multipart CSV/XLSX).orders.update
GET/api/v1/orders/:id/trackingPer-piece USPS tracking events for the order.orders.read
GET/api/v1/orders/:id/analyticsDelivery rate, QR scans, response counts.orders.read
GET/api/v1/pieces/:id/trackingTracking timeline for a single mail piece.orders.read
POST/api/v1/api-keysCreate a new API key (returned once).account.manage
GET/api/v1/api-keysList your API keys.account.manage
DELETE/api/v1/api-keys/:idRevoke an API key.account.manage
POST/api/v1/webhooksRegister a webhook URL. Returns the signing secret once.webhooks.manage
GET/api/v1/webhooksList your webhook subscriptions.webhooks.manage
DELETE/api/v1/webhooks/:idDisable a webhook.webhooks.manage
GET/api/v1/accountAccount profile, credit balance, plan info.account.read

Examples

Create an order

curl -X POST \
  -H "Authorization: Bearer mb_live_..." \
  -H "Content-Type: application/json" \
  -d '{"quantity":500,"message":"Hi {{first_name}}, โ€ฆ","campaign_type":"handwritten"}' \
  https://mailbots.ai/api/v1/orders

The response includes the order id. Upload your recipient list to /orders/:id/recipients next, then pay through the dashboard or by hitting /orders/:id/checkout.

List mailed orders

curl -H "Authorization: Bearer mb_live_..." \
  "https://mailbots.ai/api/v1/orders?status=mailed&limit=20"

Pull tracking for an order

curl -H "Authorization: Bearer mb_live_..." \
  "https://mailbots.ai/api/v1/orders/01K.../tracking"

Webhooks

Get pushed updates instead of polling. Mailbots POSTs JSON to your URL with two headers: X-Mailbots-Event and X-Mailbots-Signature (HMAC-SHA256 of the raw body, hex-encoded, prefixed sha256=).

Register

curl -X POST \
  -H "Authorization: Bearer mb_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-server.example.com/mailbots-webhook","events":["order.mailed","piece.delivered"]}' \
  "https://mailbots.ai/api/v1/webhooks"

The response includes a secret shown ONCE โ€” store it. Use it to verify every incoming delivery.

Verify a delivery (Node)

import crypto from 'node:crypto';

function verifyMailbotsSignature(rawBody, signatureHeader, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  const [, received] = signatureHeader.split('=');
  return crypto.timingSafeEqual(
    Buffer.from(expected, 'hex'),
    Buffer.from(received, 'hex')
  );
}

// In your handler:
const raw = await readRawBody(req);
const sig = req.headers['x-mailbots-signature'];
if (!verifyMailbotsSignature(raw, sig, process.env.MAILBOTS_WEBHOOK_SECRET)) {
  return res.status(401).end();
}
const event = JSON.parse(raw);
console.log(event.event, event.order_id);

Event types

order.createdYou created a draft order.
order.paidPayment cleared.
order.production_startedVendor started writing your cards.
order.mailedYour campaign hit the post office.
piece.deliveredA specific piece was delivered.
piece.returnedA specific piece was undeliverable / returned.
qr.scannedRecipient scanned the QR code on your card.

Permission scopes

When you mint a key you select which scopes it carries. Default keys carry all scopes; restrict if a key only needs read access.

  • orders.create โ€” POST /orders
  • orders.read โ€” GET /orders, /orders/:id, tracking, analytics
  • orders.update โ€” PATCH /orders/:id, upload recipients
  • orders.delete โ€” DELETE /orders/:id
  • account.read โ€” GET /account
  • account.manage โ€” manage API keys
  • webhooks.manage โ€” manage webhook subscriptions

Pagination

List endpoints accept ?limit= and ?offset=. Default limit=20, max 100. Total row count returns in the pagination.total field.

Test mode

Prefix your key with mb_test_ instead of mb_live_ to test against Stripe's test environment. Test orders never charge real money or mail real cards. Switch back to your live key when you're ready to ship.

Rate limits

Standard limit: 60 requests/minute per key. List endpoints: 30 requests/minute. Hit the limit and you'll get a 429 with a Retry-After header. Need higher limits? Email support@mailbots.ai.

Error codes

  • 401 โ€” missing, malformed, or revoked API key
  • 403 โ€” your key lacks the required permission scope
  • 404 โ€” order, piece, or webhook not found
  • 400 โ€” validation error (details in details)
  • 429 โ€” rate limit exceeded
  • 500 โ€” server error; safe to retry with backoff

Need help?

Email support@mailbots.ai with your account email and a sample request โ€” we usually respond within a business day.