API keys & programmatic access¶
API keys let you drive Buzzator from outside the app — from your own scripts and integrations over a REST API, and from AI assistants over the MCP server (Model Context Protocol). One key, scoped to exactly the permissions you choose, authenticates both.
- REST API —
https://app.buzzator.com/api/pub/v1— for scripts, automations, and integrations. - MCP server —
https://app.buzzator.com/api/mcp— connect an AI assistant or any MCP-compatible client so it can operate your account.
Everything a key can do is bounded by the scopes, brands, and platforms you give it when you create it.
Creating a key¶
Settings → API keys → Create key. Choose:
| Setting | What it controls |
|---|---|
| Name | A label so you can recognise the key later (e.g. "Zapier", "Reporting bot"). |
| Permissions (scopes) | Which actions the key may perform — see the table below. |
| Brands | All brands (current and future) or a specific set. A brand-restricted key can only ever touch those brands. |
| Platforms | All platforms or a specific set (Instagram, LinkedIn, X, …). |
| Expiration | Optional — the key stops working after this date. |
The full secret (bztr_live_… in production, bztr_test_… outside it) is shown
once, at creation. Copy it then — it is stored only as a hash and can never
be retrieved again. Lost it? Regenerate the key (rotates the secret, keeps
the same scopes) or delete it (permanent — the secret stops working
immediately).
A key acts as the teammate who created it, intersected with the key's own scopes. If that teammate loses access to a brand, the key does too. This is the least‑privilege model — give each integration its own key with the narrowest scopes it needs.
What's possible — capabilities by scope¶
| Scope | Lets the key… |
|---|---|
brands:read |
List the brands the key can access (id, name, handle, logo). |
accounts:read |
List a brand's connected social accounts (which platforms are live). |
posts:read |
List and read posts (drafts, scheduled, published), with filters and pagination. |
posts:write |
Create posts — as a draft or scheduled (auto‑publish at a set time). |
posts:generate |
Start AI generation — on‑brand captions + images across platforms (async job). |
publish |
Publish an existing post to its connected account now. |
media:write |
Upload an image or video and get a media URL to attach to a post. |
analytics:read |
Read aggregated engagement analytics for a brand. |
inbox:read |
List inbox conversations (DMs, comments, mentions). |
inbox:write |
Send a reply on a conversation (posts a real outbound message). |
A key only exposes the scopes you granted it — everything else returns
403 insufficient_scope.
Common things you can build¶
- Cross‑post from your own tools — create drafts or schedule posts on any connected platform.
- Schedule at a specific time — create a post with
status: "scheduled"and a futurescheduled_at. - AI content at scale — kick off brand‑aware generation for one prompt across several platforms, then collect the drafts.
- Reporting — pull a brand's analytics into a dashboard or a weekly digest.
- Community management — read the inbox and (with
inbox:write) send replies. - Give an AI assistant hands — connect the MCP server so an assistant can do all of the above conversationally.
The REST API¶
Base URL: https://app.buzzator.com/api/pub/v1
Auth: send Authorization: Bearer <your-api-key> on every request.
| Method & path | Scope | What it does |
|---|---|---|
GET /me |
— | Introspect the key: its org, scopes, and brand/platform restrictions. |
GET /brands |
brands:read |
List accessible brands. |
GET /accounts?brand_id=… |
accounts:read |
List a brand's connected accounts. |
GET /posts |
posts:read |
List posts (brand_id, status, platform, page, per_page). |
GET /posts/{id} |
posts:read |
Fetch a single post. |
POST /posts |
posts:write |
Create a draft or scheduled post. |
POST /posts/{id}/publish |
publish |
Publish a post now. |
POST /generations |
posts:generate |
Start an AI generation job → 202 { job_id }. |
GET /generations/{job_id} |
posts:generate |
Poll a generation job's status + drafts. |
POST /media |
media:write |
Upload media (multipart) → a bare media URL. |
GET /analytics?brand_id=…&days=… |
analytics:read |
Aggregated brand analytics. |
GET /inbox?brand_id=… |
inbox:read |
List conversations (cursor‑paginated). |
POST /inbox/{conversation_id}/reply |
inbox:write |
Send an outbound reply. |
brand_id is a query parameter on brand‑scoped endpoints. A brand‑restricted
key must supply it (or gets 400 brand_required).
Creating and scheduling a post¶
# A draft
curl -X POST "https://app.buzzator.com/api/pub/v1/posts?brand_id=<brand-uuid>" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"platform":"instagram","caption":"Hello world","status":"draft"}'
# Scheduled — same call, add status=scheduled + an absolute ISO 8601 time
curl -X POST "https://app.buzzator.com/api/pub/v1/posts?brand_id=<brand-uuid>" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"platform":"instagram","caption":"Launch!","status":"scheduled","scheduled_at":"2026-08-01T09:00:00-07:00"}'
There is no separate "schedule" endpoint — scheduling is just creating a post
with status: "scheduled" and a future scheduled_at. At that time Buzzator's
normal publish workflow fires it to the connected account.
AI generation is asynchronous¶
POST /generations returns 202 { "job_id": …, "status": "queued" } immediately.
Poll GET /generations/{job_id} every 5–10 s (a run takes ~1–3 min) as it moves
queued → running → done | failed. On done, the response includes the draft
posts it created.
Errors & rate limits¶
Errors are JSON: { "detail": { "code": "…", "message": "…" } }.
| Status | Meaning |
|---|---|
401 invalid_api_key |
Missing / malformed / revoked / expired key. |
403 insufficient_scope |
The key lacks the scope for that action. |
403 brand_out_of_scope / platform_out_of_scope |
The key isn't scoped to that brand/platform. |
404 Not found |
The resource doesn't exist — or the API‑keys feature is disabled on this deployment. |
422 |
Request validation failed. |
429 Rate limit exceeded |
Slow down — see below. |
Rate limits: ~600 requests/minute per key and ~1000/minute per IP. Keep a gentle pace with small pauses.
The MCP server (for AI assistants)¶
The MCP server lets an AI assistant (or any MCP‑compatible client) operate your account with the same API key — read brands and posts, create, schedule, generate and publish content, upload media, and work the inbox — all bounded by the key's scopes.
Endpoint: https://app.buzzator.com/api/mcp · Transport: streamable HTTP ·
Auth: Authorization: Bearer <your-api-key>
Add it to any MCP client with a standard configuration:
{
"mcpServers": {
"buzzator": {
"type": "http",
"url": "https://app.buzzator.com/api/mcp",
"headers": { "Authorization": "Bearer YOUR_API_KEY" }
}
}
}
Tools exposed¶
whoami · list_brands · list_accounts · list_posts · get_post ·
create_post · publish_post · generate_post · get_generation_job ·
upload_media_from_url · get_analytics · list_inbox · reply_to_conversation.
Each tool requires the matching scope (e.g. create_post needs posts:write),
so a key with only posts:read + analytics:read gives the assistant a
read‑only, reporting‑only surface. Scheduling works the same way as the REST API
— create_post with status: "scheduled" and a scheduled_at.
Least privilege for assistants: mint a dedicated key per assistant with only the scopes (and brands/platforms) it needs. A support bot might get
inbox:read+inbox:writeon one brand; a reporting bot onlyanalytics:read.
Security model at a glance¶
- Keys are hashed at rest (HMAC‑SHA256) — the plaintext is shown once and never stored.
- Scoped three ways — permissions (scopes) × brands × platforms. Every request is checked against all three.
- Acts as its creator — a key can never exceed what the teammate who made it can do; losing brand access revokes it for the key too.
- Rotate or revoke instantly — Regenerate invalidates the old secret and issues a new one; Delete is permanent and immediate.
- Availability — programmatic access is gated per deployment; on production it must be enabled by an admin before keys work.