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:
| Scope | Allows |
|---|
read | List brands, list and fetch content, read analytics. |
write | Everything 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.
| Status | Code | Meaning |
|---|
| 401 | missing_key / invalid_key / revoked_key | No key, an unknown key, or a revoked key. |
| 403 | not_entitled | The workspace isn't on the Scale plan. |
| 403 | insufficient_scope | A read-only key called a write endpoint. |
| 400 | invalid_request | A parameter failed validation; the message says which. |
| 402 | insufficient_credits | Generation needs more credits than the workspace has. |
| 404 | not_found / brand_not_found | No such content item or brand slug. |
| 429 | rate_limited | Over 60 requests in the current minute. |
| 5xx | server_error / provider_error | Unexpected 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 param | Description |
|---|
brandSlug | Filter to one brand. |
type | One of script, hook, caption, carousel, ad, video, image, thumbnail, story, blog, email, campaign. |
status | Workflow state, e.g. draft, approved, scheduled, published. |
limit | 1–100, default 20. |
before | ISO 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 field | Description |
|---|
brandSlug | Required. From GET /v1/brands. |
contentType | Required. e.g. caption, script, hook, carousel, ad. |
topic | Required. What to create, 3–4000 characters. |
goal | Optional. awareness, engagement, conversion, retention, or launch. |
platform | Optional. e.g. instagram, tiktok, youtube. |
variationCount | Optional. 1–5 variants, default 3. |
idempotencyKey | Optional. 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 param | Description |
|---|
range | 7, 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"
}
}