Errors and limits
The HTTP status is the failure's status. The body always follows the same envelope; code is stable (English, snake_case) and message is Portuguese text.
{
"error": {
"code": "time_in_past",
"message": "O horário já passou ou está perto demais.",
"details": {}
}
}401comes withWWW-Authenticate: Bearer;429comes withRetry-After(seconds).- With
422 invalid_fieldandinvalid_request,details.errorslists every problem at once. - Portuguese field names are rejected: send the contract names (in English) and the
X-Praeko-Contract: enheader.
Limits
| Limit | Value |
|---|---|
| Requests | 300 per minute per key (approximate, per instance). Over it: 429 rate_limited with Retry-After. |
| JSON body | 1 MB (413 body_too_large) |
| Media file | Up to 50 MiB in one request (simple: true); above that, in 5 to 95 MiB parts. Video up to 5 GiB, cover and photo up to 20 MiB. |
| Webhooks | 10 per workspace; 10 s delivery timeout |
| Usage log | 30 days, metadata only (route, status, duration; never the body) |
The codes (116)
Status and text come from the documented routes and, when a route does not list them, from the server's behavior. Only codes from internal platform operation routes are left out. A dash (—) in the status means the current server does not return that code.
| Status | `code` | Meaning |
|---|---|---|
| 404 | route_not_found |
No route matches this method and path. |
| 405 | method_not_allowed |
The path exists but does not accept this method. |
| 500 | internal_error |
Unexpected server error. The message is generic; try again. |
| 401 | unauthorized |
The Authorization: Bearer … header is missing. |
| 401 | invalid_api_key |
The key does not exist. |
| 401 | revoked_api_key |
The key has been revoked. |
| 401 | expired_api_key |
The key has expired. |
| 401 | mfa_required |
Confirm the second factor to continue. |
| 401 | invalid_code |
Wrong code. |
| 409 | mfa_already_enabled |
The authenticator app is already on: turn it off before setting it up again. |
| 409 | mfa_not_started |
Start by setting up the authenticator app. |
| 409 | mfa_not_enabled |
Turn on the authenticator app first. |
| 409 | current_session |
This is the session you are using: sign out instead. |
| 404 | session_not_found |
Session not found. |
| 422 | invalid_confirmation |
The body is missing the confirmation this destructive action requires. |
| 401 | invalid_session |
The panel session expired or is no longer valid: sign in again. |
| 403 | invalid_origin |
A request with a panel session came from another origin and was rejected. |
| 403 | forbidden |
The key's scope is not enough for this route (see the scope badge). |
| 429 | rate_limited |
The per-minute request limit was exceeded. |
| 400 | empty_body |
The request body is empty. |
| 400 | invalid_json |
The request body is not a JSON object. |
| 413 | body_too_large |
The request body is larger than 1 MB. |
| 422 | invalid_field |
A body, query or header field has the wrong format or is out of range. The message says which one. |
| 422 | invalid_request |
Something is missing; the full list comes in details.errors. |
| 422 | missing_schedule |
Missing scheduledFor, queue or draft. |
| 422 | missing_time |
Missing scheduledFor. |
| 422 | time_in_past |
The time has already passed or is too close. |
| 409 | no_slots |
queue on a channel without time slots. |
| 409 | no_free_slot |
The channel has no free slot in the next 120 days. |
| 404 | post_not_found |
The post does not exist. |
| 404 | item_not_found |
The item does not exist in this post. |
| 404 | action_not_found |
This item has no saved comment. |
| 404 | channel_not_found |
The channel does not exist in this workspace, or the network is not connected. |
| 409 | channel_not_connected |
The network is not connected. |
| 404 | api_key_not_found |
The key does not exist. |
| 403 | oauth_requires_panel |
Connecting an account happens in the panel (Channels › Connect), not with an API key. |
| 409 | video_not_private |
YouTube, already uploaded: the video is already public on YouTube, so its time and metadata can only change in Studio (details.studio has the link). |
| 409 | channel_in_use |
Pending items use this account: cancel or move them before removing it. |
| 409 | channel_connected |
Disconnect the account before removing it from the list. |
| 409 | channel_is_buffer |
This is the Instagram channel that publishes through Buffer: it cannot be removed. |
| 401 | invalid_credentials |
Wrong e-mail or password. |
| 422 | weak_password |
The password breaks the rules: 12 to 128 characters and nothing predictable (such as the e-mail or repeated characters). |
| 400 | invalid_link |
Invalid or expired link: ask for a new one. |
| 429 | account_locked |
Too many wrong attempts: the account is locked for a few minutes. |
| 401 | invalid_passkey |
The passkey failed verification. |
| 404 | passkey_not_found |
Passkey not found. |
| 409 | passkey_exists |
This passkey is already registered. |
| 400 | invalid_challenge |
Invalid or expired challenge: start again. |
| 409 | passkey_limit |
The limit is 20 passkeys per account. |
| 401 | code_required |
Send the authenticator app code (code). |
| 409 | api_key_in_use |
It is the key making this call. |
| 401 | invalid_token |
OAuth token is invalid, expired or issued for another server (on /mcp). |
| 404 | request_not_found |
The agent authorization request does not exist or has expired: start again from the app. |
| 403 | request_from_another_browser |
The authorization request was started in another browser: start the connection again from the app. |
| 404 | connection_not_found |
Agent connection not found. |
| 409 | video_not_found |
YouTube, already uploaded: the video was deleted on YouTube. |
| 404 | no_video |
The post has no video on YouTube yet. |
| 404 | no_avatar |
The channel has no profile picture available. |
| 404 | media_not_found |
The media does not exist in this workspace. |
| 409 | media_in_use |
A pending post uses this media item. |
| 409 | media_not_ready |
The media upload has not been completed yet. |
| 422 | media_type_mismatch |
The media is the wrong type (a video where a cover goes, or the reverse), or the cover is not JPEG or PNG. |
| 409 | media_locked |
The video can only be replaced in an adopted post or in a draft; the image of an image post cannot be replaced by PATCH. |
| 404 | unknown_network |
Unknown network. |
| 422 | network_not_supported |
This action does not support that network yet. |
| 409 | invalid_state |
The media is not waiting for this upload (it was created another way, or it was already sent). |
| 409 | id_exists |
A post with this id already exists. |
| 409 | already_adopted |
This Buffer post is already in Praeko. |
| 409 | nothing_to_publish |
This post has no pending item (or none for the requested network). |
| 409 | not_editable |
The item has already gone out or is in progress (YouTube, already uploaded: it can only change while the video is still private and scheduled; once the scheduled time has passed, it can no longer change). |
| 409 | post_adopted |
Post adopted from Buffer: only text, time and draft can change. |
| 409 | post_prepared |
This Reel is already being prepared on Meta: the caption can no longer change; you can only cancel. |
| 409 | oauth_not_configured |
Connecting that network is not configured on this server. |
| 409 | followers_from_api |
The network already provides followers through its API (only instagram accepts a manual value). |
| 409 | youtube_not_connected |
YouTube is not connected. |
| 409 | instagram_meta_not_connected |
The Meta API is not connected. |
| 422 | download_failed |
The file could not be downloaded from the URL (redirect without a target, error status or empty body). |
| 422 | unsupported_mime |
The file type is not accepted for that type (video: MP4 or MOV; cover: PNG or JPEG). |
| 422 | file_too_large |
The file is over the limit of that upload path (for example, simple: true above 50 MiB). |
| 413 | part_too_large |
The part is larger than 95 MiB. |
| 422 | part_too_small |
A part (other than the last) is smaller than 5 MiB. |
| 422 | part_empty |
The part is empty. |
| 422 | parts_unequal |
The parts have different sizes: all must be equal, only the last can be smaller. |
| 422 | parts_missing |
A part is missing from the sequence: parts go from 1 to N with no gaps. |
| 422 | no_parts |
No part was uploaded. |
| 422 | size_mismatch |
The total uploaded does not match the declared size. |
| 422 | storage_rejected |
Storage refused to join the parts; upload the parts again. |
| — | identity_not_linked |
Reserved in the contract; the current server does not return it. |
| — | last_login_method |
Reserved in the contract; the current server does not return it. |
| 409 | missing_oauth_credential |
The Meta connection is not configured on this server. |
| 409 | already_connected |
Instagram is already connected; nothing changed. |
| 400 | oauth_state_invalid |
Meta return page: the request is incomplete, expired or from another session. Start the connection again in the panel. |
| 400 | oauth_denied |
Meta return page: authorization was denied. Nothing changed. |
| 422 | no_instagram_account |
Meta return page: the sign-in gave access to no Instagram professional account. |
| 409 | multiple_instagram_accounts |
Meta return page: the sign-in gives access to more than one account; pick one. |
| 502 | token_exchange_failed |
Meta return page: Meta refused to exchange the code for a token. Nothing changed. |
| 422 | publish_permission_missing |
Meta return page: the token lacks the publish permission. |
| 422 | token_cannot_read_account |
Meta return page: the token cannot read the Instagram account. |
| 404 | webhook_not_found |
The webhook does not exist. |
| 404 | delivery_not_found |
The delivery does not exist. |
| 422 | unsafe_url |
The url is not https, or points to a private network or localhost. |
| 409 | webhook_limit_reached |
This workspace already has 10 webhooks. |
| 404 | idea_not_found |
The idea does not exist. |
| 409 | idea_limit_reached |
This workspace already has 2000 ideas. |
| 422 | idempotency_key_reuse |
The Idempotency-Key was already used with a different request (different method, path, query or body). |
| 409 | idempotency_in_progress |
A request with the same Idempotency-Key is still in progress (retry in a moment). |
| 409 | idempotency_response_too_large |
The original response was larger than 256 KB and was not stored; fetch the resource with GET instead. |
| 422 | invalid_image |
An image media item whose file is not a JPEG (checked on upload; for uploads in parts, on complete). |
| 422 | image_aspect_ratio |
The image aspect ratio is outside 4:5 to 1.91:1 (Instagram would refuse it; use 1080x1350). |
| 422 | image_too_large |
The image is over 8 MB (Instagram limit). |
| 422 | kind_not_supported_by_network |
kind: image on a YouTube or TikTok item. |
| 422 | carousel_not_supported |
More than one image in media.images (carousel arrives later). |
| 502 | buffer_error |
Buffer refused to edit or cancel the post. |
| 502 | instagram_error |
Meta (Instagram) rejected the request or did not respond. |
| 502 | tiktok_unavailable |
The TikTok account could not be queried. |
| 502 | youtube_error |
YouTube did not respond or rejected the check/write; nothing was changed (or itemResults says what was). |
The old Portuguese paths answer { "erro": { "codigo", "mensagem", "detalhes" } } with the old code; the mapping is one to one.
Question or mistake on this page? contato@praeko.appView .md