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
| Method | Path | Description | Scope |
|---|---|---|---|
| POST | /api/v1/orders | Create a new order with quantity, message, and campaign options. | orders.create |
| GET | /api/v1/orders | List your orders. Filter by ?status=, paginate with ?limit=&offset=. | orders.read |
| GET | /api/v1/orders/:id | Order details + drops + payment status. | orders.read |
| PATCH | /api/v1/orders/:id | Update message, sender info, return address, or cancel a draft. | orders.update |
| DELETE | /api/v1/orders/:id | Cancel a draft or pre-payment order. | orders.delete |
| POST | /api/v1/orders/:id/recipients | Upload your recipient list (multipart CSV/XLSX). | orders.update |
| GET | /api/v1/orders/:id/tracking | Per-piece USPS tracking events for the order. | orders.read |
| GET | /api/v1/orders/:id/analytics | Delivery rate, QR scans, response counts. | orders.read |
| GET | /api/v1/pieces/:id/tracking | Tracking timeline for a single mail piece. | orders.read |
| POST | /api/v1/api-keys | Create a new API key (returned once). | account.manage |
| GET | /api/v1/api-keys | List your API keys. | account.manage |
| DELETE | /api/v1/api-keys/:id | Revoke an API key. | account.manage |
| POST | /api/v1/webhooks | Register a webhook URL. Returns the signing secret once. | webhooks.manage |
| GET | /api/v1/webhooks | List your webhook subscriptions. | webhooks.manage |
| DELETE | /api/v1/webhooks/:id | Disable a webhook. | webhooks.manage |
| GET | /api/v1/account | Account 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/ordersThe 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.created | You created a draft order. |
| order.paid | Payment cleared. |
| order.production_started | Vendor started writing your cards. |
| order.mailed | Your campaign hit the post office. |
| piece.delivered | A specific piece was delivered. |
| piece.returned | A specific piece was undeliverable / returned. |
| qr.scanned | Recipient 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 /ordersorders.readโ GET /orders, /orders/:id, tracking, analyticsorders.updateโ PATCH /orders/:id, upload recipientsorders.deleteโ DELETE /orders/:idaccount.readโ GET /accountaccount.manageโ manage API keyswebhooks.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 key403โ your key lacks the required permission scope404โ order, piece, or webhook not found400โ validation error (details indetails)429โ rate limit exceeded500โ 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.

