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/json for 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:

HeaderDescription
X-Process-TimeRequest execution time in seconds
X-Request-IDUnique 8-character request identifier
X-Skill-LatestLatest skill version (authenticated only)
X-Skill-Update-URLSkill 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}/analyze
  • POST /brands/{id}/enrich/brand
  • POST /brands/{id}/enrich/technical
  • POST /brands/{id}/enrich/llm
  • POST /brands/{id}/discover
  • POST /brands/{id}/discover-competitors
  • POST /brands/{id}/synthesize
  • POST /brands/{id}/score
  • POST /brands/{id}/brief
  • POST /brands/{id}/execute

Error responses

⚠ This content couldn’t be displayed(snippet error-codes.mdx)

Rate limits

⚠ This content couldn’t be displayed(snippet tier-table.mdx)

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 brand
  • GET /brands/{id} — read a brand
  • POST /brands/{id}/analyze — run the full pipeline
  • GET /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.