For AI Agents

Give your agent a shipping department.

Self-serve signup to first test label in one API call. REST and MCP on one platform, a free sandbox that runs on production, and guardrails a human actually controls. UPS, FedEx, and USPS — no carrier accounts required.

Quickstart

Sandbox label in three calls. Live in four.

1.Open an account — no human required to start

POST /api/v1/signups
curl -X POST https://app.mailroom.software/api/v1/signups \
  -H "Content-Type: application/json" \
  -d '{
    "companyName": "Acme Robotics",
    "email": "ops@acme-robotics.com",
    "contactName": "Dana Smith",
    "contactPhone": "+1 555 010 4477",
    "shipFrom": {
      "name": "Acme Robotics", "phone": "+1 555 010 4477",
      "line1": "500 Warehouse Way", "city": "Columbus",
      "state": "OH", "zip": "43004"
    },
    "termsAccepted": true
  }'

# 201 →
# {
#   "orgId": "…",
#   "apiKey": "mk_test_…",        ← shown once
#   "mode": "test",
#   "sandbox": "synthetic (built in — use this key against this host)",
#   "docs": "https://app.mailroom.software/docs/agents",
#   "legal": { "terms": "…", "privacy": "…" }
# }

The signup names a reachable human contact — that's deliberate. Your key arrives in the response and works immediately.

2.Quote — free, no side effects

POST /api/v1/quotes
curl -X POST https://app.mailroom.software/api/v1/quotes \
  -H "Authorization: Bearer mk_test_…" \
  -H "Content-Type: application/json" \
  -d '{
    "shipTo": {
      "name": "Fred Smith", "phone": "+1 555 010 9922",
      "line1": "1 Delivery Dr", "city": "Memphis",
      "state": "TN", "zip": "38103"
    },
    "package": { "weightLbs": 2 }
  }'

# 200 → { "quoteId": "…", "synthetic": true,
#         "rates": [ { "rateId": "…", "carrier": "usps",
#                      "service": "Ground Advantage",
#                      "amountCents": 842, … } ] }

Test keys run synthetic mode on production itself — same host, same code path, simulated carriers. Responses are stamped synthetic: true, prices are deterministic (and deliberately not real — never use them as cost estimates), and a line1 containing INVALID or AMBIGUOUS exercises the failure paths.

3.Buy the label

POST /api/v1/shipments
curl -X POST https://app.mailroom.software/api/v1/shipments \
  -H "Authorization: Bearer mk_test_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "quoteId": "…", "rateId": "…" }'

# 201 → { "shipmentId": "…", "trackingNumber": "…",
#         "labelUrl": "…", "synthetic": true }
#        (sandbox labels are watermarked NOT FOR SHIPPING)

4.Graduate to live shipping

billing setup → top-up → live key
# 1. Get a billing setup link — hand the URL to your human.
#    They add a card with Stripe and sign the billing authorization.
#    Card details never pass through this API.
curl -X POST https://app.mailroom.software/api/v1/billing/setup-link \
  -H "Authorization: Bearer mk_test_…"

# 2. Fund the prepaid balance ($50 minimum).
curl -X POST https://app.mailroom.software/api/v1/billing/top-up \
  -H "Authorization: Bearer mk_test_…" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{ "amount_cents": 5000 }'

# 3. Activate a live key.
curl -X POST https://app.mailroom.software/api/v1/keys/activate-live \
  -H "Authorization: Bearer mk_test_…"
# 402 → itemizes anything still missing (card, authorization, balance)
# 201 → { "apiKey": "mk_live_…" }

Card entry is human-only by design: your agent gets a time-limited URL to hand to its admin, and payment details never touch the API.

Two protocols, one platform

REST when you want control. MCP when you want tools.

Both surfaces share one code path, one policy engine, and one auth model: Authorization: Bearer mk_… or OAuth 2.1 with dynamic client registration (RFC 7591) and automatic discovery (RFC 9728). The MCP endpoint is stateless streamable HTTP at POST app.mailroom.software/mcp.

Shipping

  • get_shipping_rates
  • create_shipment
  • track_shipments
  • void_shipment
  • validate_address
  • search_contacts

Billing

  • get_billing_status
  • get_billing_setup_link
  • add_funds
  • check_top_up
  • configure_auto_refill
  • activate_live_key

Limits

  • request_limit_increase
  • list_limit_requests
  • reply_to_limit_request

Settings

  • get_settings_link

16 tools. Full schemas in the OpenAPI spec and the agent guide.

Guardrails

Built so your operator can say yes

Giving an agent spending power is a trust decision a human makes. Every limit below exists so that decision is easy to defend.

Per-key spending caps

Self-serve keys start at $100 per shipment, $300 per day, 10 shipments per day, 100 quotes per day, US-only — defaults; current values live in the API docs. Rejected attempts don't burn the day's budget.

Humans review increases

Cap raises are requested through the API and reviewed by a human operator by default. The operator can ask your agent follow-up questions before deciding — and the answer arrives as a webhook.

Prepaid, never overdrawn

Live shipping draws from a balance that must be funded first. An agent structurally cannot spend money that isn't there — an empty balance is a 402, not a surprise invoice.

Optional purchase approval

Keys can require a human sign-off on every purchase or over a threshold. A gated purchase returns 202 pending_approval and pings a manager in Slack; your agent polls for the outcome.

Errors that tell you what to do

Every error is { code, message, suggested_action } with a stable code enum. A cap breach names the limit you hit, the amount you tried, and the exact endpoint to request more headroom.

Signed webhooks + self-monitoring

Eight HMAC-signed events cover label creation, approvals, delivery, exceptions, and limit decisions. GET /api/v1/usage returns rolling 30-day spend, request counts, and your key's full policy.

Pricing

Sandbox free. Live is pay-per-label.

No subscription, no seat fees, no minimums. Live shipping draws from a prepaid balance, and the exact all-in price is on every rate quote beforeyour agent buys the label — it can only spend money that's already there, at prices it saw first.

FAQ

The questions your operator will ask

Can an AI agent sign up without a human?

Yes. POST /api/v1/signups creates an organization and returns a test API key in one call — no human approval needed to start. The signup does require the name, email, and phone number of a reachable human contact, so no autonomous account is a black box, and going live with real money later requires a human to add the payment card.

How does the sandbox work?

Test keys (mk_test_) run in synthetic mode on production itself: quotes, labels, tracking, and voids are simulated end-to-end with deterministic realistic prices, zero carrier calls, and zero charges. Responses are stamped synthetic: true, labels are watermarked as not shippable, and sandbox prices never reflect real production rates. Special test addresses (a line1 containing INVALID or AMBIGUOUS) exercise the failure paths.

How does an agent go from sandbox to live shipping?

Three steps, with a human in the money loop: the agent requests a billing setup link and hands the URL to its human admin, who adds a card and signs the billing authorization with Stripe (card details never pass through the API); the agent tops up the prepaid balance; then it calls activate-live-key to receive an mk_live_ key. If anything is missing, the API returns a 402 that itemizes exactly which prerequisites remain.

What does it cost?

The sandbox is free. Live shipping is pay-per-label from a prepaid balance — no subscription, no seat fees. Every rate quote shows the exact all-in price before the agent buys the label, so there is never a surprise charge: an agent can only spend money that has already been deposited, and only at prices it saw up front.

What stops an agent from overspending?

Four per-key spending caps (per-shipment dollar limit, rolling daily dollar limit, daily shipment count, and daily quote quota), a prepaid balance it cannot overdraw (402 insufficient_balance), and optional per-purchase human approval (a gated purchase returns 202 pending_approval and pings a manager). Cap increases are requested through the API and reviewed by a human by default. Current default limits are listed in the API docs.

Which carriers are supported?

UPS, FedEx, and USPS, quoted side-by-side in a single rate call. Agent organizations ship on Mailroom's own carrier accounts, so no carrier relationship or account setup is required.

How does my agent get support?

Email help@support.mailroom.software — a support agent answers around the clock and escalates to a human when needed. There is no dedicated support API endpoint, so an agent should email like anyone else (or route the question through its human operator). API errors also include a machine-readable suggested_action field that resolves most issues without support.

Does my agent have to accept legal terms?

Yes. The signup call requires termsAccepted: true, and the current terms and privacy policy versions are available machine-readably at GET /api/v1/legal. An agent should fetch and review the terms (or surface them to its human operator) before signing up.

Point your agent here

one request to orient
curl https://app.mailroom.software/llms.txt