Authentication, errors and limits
Everything that applies to every route: how to authenticate, what each scope allows, the error format and how many requests fit in a minute.
Authentication
Send your API key in the Authorization header with the Bearer prefix. The base URL is https://praeko.app; everything is JSON in UTF-8.
Authorization: Bearer praeko_…
X-Praeko-Contract: en| Item | Detail |
|---|---|
| Key format | Starts with praeko_. Older keys start with arauto_ and still work. |
X-Praeko-Contract: en |
Selects the English contract on the paths that exist in both contracts (/v1/posts, /v1/insights, /v1/youtube/videos). Always send it. |
| Secret | Shown once, when you create the key. Praeko stores only the hash. |
| Panel cookie | For the panel only. Programs should use an API key. |
| AI agents (MCP) | The MCP server at https://praeko.app/mcp accepts the API key or an OAuth sign-in (the agent opens a consent screen and you choose the access). See MCP server. |
Scopes
Each key has one scope and each level includes the one before. The minimum scope of each route shows as a badge in the reference.
| Scope | Allows | Routes |
|---|---|---|
| read | Read channels, posts, calendar, metrics, comments, usage. | GET on most resources |
| write | Create, edit and cancel posts; upload media; reply to comments; slots; ideas. | POST, PUT, PATCH, DELETE on content |
| admin | Keys, webhooks, Instagram token, metrics import. | api-keys, webhooks, insights/import |
Errors
The HTTP status is the status of the failure. The body always has the same envelope; code is stable, and message is human-readable text, currently in Portuguese.
{
"error": {
"code": "time_in_past",
"message": "tiktok: 2026-11-01T10:00:00Z já passou ou é daqui a menos de 30 s",
"details": {}
}
}| Status | code | Means |
|---|---|---|
| 400 | empty_body, invalid_json |
Empty body, or a body that is not a JSON object. |
| 401 | unauthorized, invalid_api_key, revoked_api_key, expired_api_key |
No key, or a key that does not exist, was revoked or has expired. Includes WWW-Authenticate: Bearer. |
| 403 | forbidden |
The key's scope is not enough. |
| 404 | post_not_found, media_not_found, webhook_not_found… |
The resource does not exist in this workspace. |
| 409 | channel_not_connected, no_slots, media_not_ready… |
The current state blocks the action. |
| 413 | body_too_large |
The body is over 1 MB. |
| 422 | invalid_field, invalid_request, time_in_past… |
Invalid field; details.errors lists all of them. Portuguese field names are rejected. |
| 429 | rate_limited |
Per-minute limit. Includes Retry-After. |
| 502 | youtube_error, instagram_error, tiktok_unavailable, buffer_error |
The network refused the request; its message comes in the body. |
The full list of contract codes, with status and meaning, is in Errors and limits.
Limits
| Limit | Value |
|---|---|
| Requests | 300 per minute per key (approximate, per instance). Over the limit: 429 with Retry-After. |
| JSON body | 1 MB |
| Media file | Up to 50 MiB in one request (simple: true); above that, in parts of at least 5 MiB |
| Webhooks | 10 per workspace; each delivery has a 10 s timeout |
| Usage log | 30 days, metadata only |
Idempotency
Send the Idempotency-Key header (a UUID) on POST, PATCH and DELETE, and a retry after a network failure returns the first response, with Idempotent-Replayed: true, without creating anything new. The key lasts 24 hours, per workspace and per route. A key reused with a different request returns 422 idempotency_key_reuse; a first request that is still running returns 409 idempotency_in_progress. Without the header nothing changes. Details, curl, SDK and CLI in Retry a request safely.
curl -X POST https://praeko.app/v1/posts \
-H "Authorization: Bearer $PRAEKO_KEY" -H "X-Praeko-Contract: en" \
-H "Idempotency-Key: $(uuidgen)" -H "Content-Type: application/json" -d @post.jsonVersions and changelog
The version is in the path: /v1. The Portuguese paths still answer, marked with Deprecation: true and Link: …; rel="successor-version". The date to switch them off has not been set. The public changelog lists the changes, with the date of each one.
Deprecated paths
These Portuguese paths still work and answer with Deprecation: true and Link: <new>; rel="successor-version": the Portuguese /v1/... aliases (for example /v1/canais, instead of /v1/channels), /saude (use /health) and /conexoes/:network/retorno (use /connections/:network/callback). In the panel, the old addresses (#/publicar, #/canais, #/conectar-agente…) are rewritten to the new ones (#/publish, #/channels, #/connect-agent…) and /entrar redirects (301) to /sign-in. Move your integrations to the new paths. Before any of them is switched off, the notice appears here in the changelog, at least 90 days ahead; the date has not been set.