API v1 · Scale plan

BrandFleet API

Wire BrandFleet into your own systems: list brands, trigger real content generation, fetch what's been created, and pull analytics — all with a simple REST API authenticated by org-scoped keys.

Authentication

Every request is authenticated with an API key sent as a bearer token. Workspace admins create keys in Settings → API. A key looks like bf_live_… and is shown exactly once at creation — BrandFleet stores only a hash, so it can never be recovered, only replaced.

curl https://www.brandfleet.ai/api/v1/me \ -H "Authorization: Bearer bf_live_YOUR_KEY"

Keys belong to one workspace and only see that workspace's data. API access requires the Scale plan; if the workspace moves off Scale, every key stops working immediately (403 not_entitled). Revoking a key in Settings also takes effect immediately.

Treat API keys like passwords: keep them in environment variables or a secrets manager, never in client-side code or a public repository. If a key leaks, revoke it in Settings → API and create a new one.

Key scopes

Choose the smallest scope that does the job:

ScopeAllows
readList brands, list and fetch content, read analytics.
writeEverything read allows, plus POST /v1/generate — which spends the workspace's credits exactly like in-app generation.

Rate limits

Each key may make 60 requests per minute. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining headers; exceeding the limit returns 429 with a Retry-After: 60 header. Batch jobs should simply pause and resume — nothing is lost.

Errors

Failures return a JSON body { "error": { "code", "message" } } with a matching HTTP status. Codes are stable — branch on code, not the message.

StatusCodeMeaning
401missing_key / invalid_key / revoked_keyNo key, an unknown key, or a revoked key.
403not_entitledThe workspace isn't on the Scale plan.
403insufficient_scopeA read-only key called a write endpoint.
400invalid_requestA parameter failed validation; the message says which.
402insufficient_creditsGeneration needs more credits than the workspace has.
404not_found / brand_not_foundNo such content item or brand slug.
429rate_limitedOver 60 requests in the current minute.
5xxserver_error / provider_errorUnexpected failure — safe to retry.

Endpoints

All endpoints live under https://www.brandfleet.ai/api/v1 and return JSON.

GET/api/v1/mescope: read

Identifies the key and workspace — call it first to verify your setup.

Response
{ "organization": { "id": "…", "name": "Acme Studio", "creditBalance": 412 }, "plan": "scale", "keyScope": "write" }
GET/api/v1/brandsscope: read

Lists the workspace's brands. Use a brand's slug wherever an endpoint takes brandSlug.

Response
{ "brands": [ { "id": "…", "slug": "acme", "name": "Acme", "createdAt": "2026-05-01T09:00:00Z" } ] }
GET/api/v1/contentscope: read

Lists generated content, newest first.

Query paramDescription
brandSlugFilter to one brand.
typeOne of script, hook, caption, carousel, ad, video, image, thumbnail, story, blog, email, campaign.
statusWorkflow state, e.g. draft, approved, scheduled, published.
limit1–100, default 20.
beforeISO timestamp cursor for paging: pass the createdAt of the last item you received (the response's nextBefore).
Example
curl "https://www.brandfleet.ai/api/v1/content?brandSlug=acme&status=approved&limit=10" \ -H "Authorization: Bearer bf_live_YOUR_KEY"
Response
{ "items": [ { "id": "…", "brandId": "…", "contentType": "caption", "goal": "conversion", "platform": "instagram", "topic": "Spring sale launch", "title": null, "body": "…", "variants": [ { "title": null, "body": "…" } ], "status": "approved", "creditCost": 2, "createdAt": "2026-07-16T18:12:03Z" } ], "nextBefore": "2026-07-16T18:12:03Z" }
GET/api/v1/content/:idscope: read

Fetches a single content item by id. Returns { "item": … } with the same shape as the list items above, or 404 not_found.

POST/api/v1/generatescope: write

Triggers real content generation — the same engine, brand context, and credit pricing as the in-app generator. The finished piece is saved to the workspace (visible in the app) and returned in the response.

Body fieldDescription
brandSlugRequired. From GET /v1/brands.
contentTypeRequired. e.g. caption, script, hook, carousel, ad.
topicRequired. What to create, 3–4000 characters.
goalOptional. awareness, engagement, conversion, retention, or launch.
platformOptional. e.g. instagram, tiktok, youtube.
variationCountOptional. 1–5 variants, default 3.
idempotencyKeyOptional. Reuse the same value to make retries safe — a repeat returns the original result instead of generating (and charging) twice.
Example
curl -X POST https://www.brandfleet.ai/api/v1/generate \ -H "Authorization: Bearer bf_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "brandSlug": "acme", "contentType": "caption", "topic": "Announce our spring sale — 20% off everything this week", "goal": "conversion", "platform": "instagram", "idempotencyKey": "spring-sale-ig-001" }'
Response
{ "result": { "id": "…", "contentType": "caption", "topic": "…", "title": null, "body": "…", "variants": [ { "title": null, "body": "…" }, … ], "status": "draft", "creditCost": 2, "balance": 410, "createdAt": "2026-07-17T10:04:11Z" } }

Generation charges the workspace's credit balance (visible in the response as balance). If credits run short you get 402 insufficient_credits and nothing is charged.

GET/api/v1/analyticsscope: read

The workspace's analytics overview: credits spent, pieces created by type and by brand, videos, thumbnails, and published pages — each KPI with a per-day series and a delta versus the previous period.

Query paramDescription
range7, 30, or 90 days. Default 30.
Response (abridged)
{ "analytics": { "rangeDays": 30, "kpis": [ { "id": "credits", "label": "Credits spent", "value": 184, "deltaPct": 12, "good": false, "spark": [3, 0, 8, …] }, … ], "byBrand": [ { "brandSlug": "acme", "brandName": "Acme", "creditsSpent": 96, "pieces": 41, "videos": 3, "thumbnails": 6 } ], "byType": [ { "type": "caption", "count": 18, "credits": 36 } ], "generatedAt": "2026-07-17T10:05:00Z" } }