Authentication
Every v1 call is a Bearer token on https://www.brainpercent.app/api/v1. Keys are minted in the app. A key cannot create another key.
01Bearer token
Send Authorization: Bearer bp_… on every request.
curl https://www.brainpercent.app/api/v1/projects \
-H "Authorization: Bearer bp_your_key"02Key format
bp_ plus 64 hex characters. Shown once at creation. The server stores a SHA-256 hash, so a lost key cannot be recovered. Revoke it and mint another.
03Creating keys
Mint and revoke on Developer settings. Those routes read the signed-in session cookie. A Bearer header against /api/v1/api-keys does not authenticate, and the body is a flat { "error": "…" }, not the envelope below.
A key created without an explicit permissions list gets ["read"]. Every write then returns 403. You can hold ten active keys.
04Permissions and scopes
A request needs both the HTTP permission and the resource scope.
| Permission | Methods | What it covers |
|---|---|---|
| read | GET | List and fetch articles, social, projects, credits, usage |
| write | POST | Generate articles, generate social, publish |
| delete | DELETE | None of the Bearer routes require it. Revoke is session-only. |
| Scope | Routes |
|---|---|
| articles | /api/v1/articles/* |
| social | /api/v1/social/* |
| projects | /api/v1/projects/* |
| user | /api/v1/user/credits, /api/v1/user/usage |
05Error envelope
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Body or query failed validation |
| 400 | NO_PROJECT | No project yet. Create one in the app. |
| 401 | UNAUTHORIZED | Missing or invalid key |
| 402 | INSUFFICIENT_CREDITS | Wallet cannot cover the job |
| 403 | FORBIDDEN | Missing permission or scope, or consent required |
| 404 | NOT_FOUND | Missing, or not yours |
| 409 | CONFLICT | Already in the target state |
| 412 | PRECONDITION_FAILED | Not ready, or a channel is missing |
| 429 | RATE_LIMIT_EXCEEDED | Too many requests. Retry-After is set. |
| 500 | INTERNAL_ERROR | Quote the request_id |
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please slow down."
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-02-01T00:00:00Z"
}
}06Response headers
| Header | Meaning |
|---|---|
| X-Request-Id | Quote this in any report |
| X-RateLimit-Limit | Requests allowed this minute |
| X-RateLimit-Remaining | Requests left this minute |
| X-RateLimit-Reset | UTC epoch seconds when the minute resets |
| X-RateLimit-Daily-Limit | Daily allowance. Omitted when unlimited. |
| X-RateLimit-Daily-Remaining | Daily left. Omitted when unlimited. |
| Retry-After | On 429 only |
07Rate limits
Per API key, not per account. Generation still costs credits.
| Plan | Per minute | Per day |
|---|---|---|
| Free | 100 | 5,000 |
| Starter, Plus, Pro, Business | 1000 | 50,000 |
| Enterprise | 10000 | Unlimited |
08CORS
| Header | Value |
|---|---|
| Access-Control-Allow-Origin | * |
| Access-Control-Allow-Methods | GET, POST, PUT, DELETE, OPTIONS |
| Access-Control-Allow-Headers | Authorization, Content-Type, X-Request-Id |
| Access-Control-Max-Age | 86400 |