Authentication
API key authentication, tier system, rate limits, key rotation, and creating an account via Stripe checkout.
The API uses a single API key for authentication. No sessions, no OAuth, no passwords. One key, one header.
API key format
All keys start with bm_ followed by a hex string:
bm_54249af28748e0e24b4d2782122e2de9335627ef0f800747
Pass it in the X-API-Key header on every request:
curl -H "X-API-Key: $BM_API_KEY" \
https://api.boringmarketing.com/auth/me
Store your key in an environment variable. Never hardcode it in source files.
export BM_API_KEY="bm_your_key_here"Getting an API key
Accounts are created via Stripe checkout. You choose a tier, pay, then retrieve your key from the dashboard. There is no free tier and no self-serve /auth/register endpoint.
curl -s -X POST \
https://api.boringmarketing.com/auth/checkout \
-H "Content-Type: application/json" \
-d '{
"email": "you@example.com",
"name": "Your Name",
"tier": "builder"
}'
Response:
{
"status": "email_sent",
"session_id": "bmc_k7f3...",
"poll_url": "https://api.boringmarketing.com/auth/checkout/bmc_k7f3.../status",
"sent_at": "2026-04-08T18:42:11.123Z"
}
Check your inbox. The server emailed you a Stripe checkout link — click it, complete payment, then poll poll_url until status is completed:
{
"status": "completed",
"dashboard_url": "https://dashboard.boringmarketing.com"
}
The poll endpoint does not return your API key. Open dashboard_url in a browser, request a magic-link with your email, and copy your key from Settings → API Access. Then export it:
export BM_API_KEY="bm_your_key_here"
Already have a key but need to upgrade? The same POST /auth/checkout endpoint accepts an X-API-Key header for an authenticated fast path. In that mode, the response includes checkout_url inline (no email) and opens the Stripe billing portal for active users. See the checkout endpoint reference for details.
Tiers
| Builder | Pro | Agency | |
|---|---|---|---|
| Price | $49/mo | $149/mo | $399/mo |
| Calls/day | 500 | 5,000 | 50,000 |
| Brands | 1 | 3 | 10 |
| Content production | Yes | Yes | Yes |
Start with Builder to run a full pipeline on one brand. Upgrade to Pro or Agency when you need more brands or higher daily call volume.
Rate limits
Rate limits protect infrastructure. They are separate from tier call limits.
| Endpoint | Limit |
|---|---|
POST /auth/checkout (anonymous) | 3 per hour per destination email + 5 per hour per IP |
POST /auth/checkout (authenticated) | 5 per hour per IP |
POST /auth/recover | 3 per hour per IP |
| All authenticated endpoints | Tier-based daily call limit |
When rate limited, the response includes a Retry-After header:
// 429 Too Many Requests
{
"error": "rate_limited",
"message": "Too many requests. Retry after 60 seconds."
}
Error handling
| Status | Error Code | Meaning | What to Do |
|---|---|---|---|
401 | authentication_required | Missing or invalid X-API-Key header | Check your API key is set correctly |
402 | tier_limit_exceeded | Daily call limit reached for your tier | Upgrade via Stripe billing portal |
404 | — | Resource not found | Verify the brand_id or resource ID |
409 | — | Pipeline run already in progress | Poll the existing run instead (check X-Running-Run-Id header) |
422 | — | Validation error | Check request body against the docs |
429 | — | Rate limited | Wait and retry after Retry-After seconds |
All error responses follow this shape:
{
"error": "error_code",
"message": "Human-readable explanation",
"actions": [
{
"rel": "checkout",
"href": "/auth/checkout",
"method": "POST",
"description": "Start Stripe checkout to create an account"
}
]
}
The actions array provides machine-readable next steps — useful for AI agents to self-recover from errors.
HATEOAS actions
Error responses include an actions array with machine-readable recovery steps. This is designed for AI agents:
{
"error": "tier_limit_exceeded",
"message": "Daily limit reached for your tier.",
"usage": { "limit": 500, "used": 500 },
"actions": [
{
"rel": "upgrade",
"href": "/auth/billing-portal",
"method": "POST",
"description": "Open Stripe billing portal to change plan"
}
]
}
An agent can read the actions array and automatically offer the user an upgrade path.
Key rotation
Rotate your key without downtime. The old key is invalidated in the same transaction that creates the new one:
curl -s -X POST \
-H "X-API-Key: $BM_API_KEY" \
https://api.boringmarketing.com/auth/rotate-key
{
"api_key": "bm_new_key_here",
"message": "API key rotated. Old key is now invalid."
}
Update your environment variable immediately after rotation.
Upgrading your plan
Change plans via the Stripe billing portal. Open the portal URL in a browser to manage subscription, payment method, or invoices:
curl -s -X POST \
-H "X-API-Key: $BM_API_KEY" \
https://api.boringmarketing.com/auth/billing-portal
Lost your API key?
If you lose your key, sign into the dashboard with your email to view or rotate it from the Settings page. The dashboard uses a magic-link login — no password required.