API Overview
Base URL, authentication, request format, error handling, rate limits, and async patterns for the Boring Marketing API.
Reading these docs. This reference is written to be read by both humans and AI agents. Most steps are identical for either audience. When the steps genuinely diverge — usually around signup, API key retrieval, billing portal, or account recovery — you'll see a callout whose first words are Path split. describing what each audience does. Agents consuming /llms.txt or .md page variants can grep for Path split. to find every audience-dependent handoff.
Base URL
All requests go to:
https://api.boringmarketing.com
Authentication
All authenticated requests require the X-API-Key header:
X-API-Key: bm_your_api_key_here
You receive your API key by completing Stripe checkout via POST /auth/checkout — see the Quickstart or the Authentication guide for the full flow. Store it securely — it is your sole credential.
Request format
- Content-Type:
application/jsonfor all POST/PATCH requests - Query parameters: used for filtering on GET endpoints (
?brand_id=,?run_id=,?status=) - Path parameters: resource IDs in the URL path (
/brands/{brand_id}/opportunities)
Response format
All responses are JSON. Successful responses return the resource directly. Some list endpoints wrap results with {brand_id, total, items}; others return a bare array. Each endpoint reference page documents its exact shape — do not assume a uniform envelope.
Example wrapped response:
{
"brand_id": "uuid",
"total": 42,
"opportunities": [...]
}
Example bare array response (e.g. GET /brands):
[
{ "id": "uuid-1", "domain": "...", "name": "...", "created_at": "...", "is_managed": false },
{ "id": "uuid-2", "domain": "...", "name": "...", "created_at": "...", "is_managed": false }
]
Response headers
Every response includes:
| Header | Description |
|---|---|
X-Process-Time | Request execution time in seconds |
X-Request-ID | Unique 8-character request identifier |
X-Skill-Latest | Latest skill version (authenticated only) |
X-Skill-Update-URL | Skill update URL (authenticated only) |
Async endpoints (202 pattern)
Pipeline endpoints return 202 Accepted immediately. The work runs in the background.
// 202 Accepted
{
"run_id": "uuid",
"status": "queued"
}
Poll GET /brands/{id}/runs/{run_id} for progress. See Polling Runs for details.
Endpoints that return 202:
POST /brands/{id}/analyzePOST /brands/{id}/enrich/brandPOST /brands/{id}/enrich/technicalPOST /brands/{id}/enrich/llmPOST /brands/{id}/discoverPOST /brands/{id}/discover-competitorsPOST /brands/{id}/synthesizePOST /brands/{id}/scorePOST /brands/{id}/briefPOST /brands/{id}/execute
Error responses
Rate limits
Exceeding the daily limit returns 402 credits_exhausted. Per-IP and per-email rate limits return 429 rate_limit_exceeded with a Retry-After header and a retry_after body field.
Path conventions
All brand CRUD and pipeline endpoints use the plural /brands/{id}/... namespace:
POST /brands— create a brandGET /brands/{id}— read a brandPOST /brands/{id}/analyze— run the full pipelineGET /brands/{id}/opportunities— read scored opportunities
A legacy singular /brand/* router exists for backward compatibility with older integrations but is not recommended for new work. Always prefer the plural /brands/* endpoints.