unauthorized | 401 | Missing, malformed, or invalid API key (or an expired dashboard session on browser-session routes). | Check the Authorization: Bearer header. Re-issue or rotate the key from the dashboard. Not retryable without fixing credentials. |
forbidden | 403 | The account is valid but not allowed to do this — an expired or banned account, or a feature (like DM/engagement automation) not included in the current plan. | Don’t retry as-is. Check account status or upgrade the plan. |
not_found | 404 | The route doesn’t exist, or a referenced resource (profile, etc.) doesn’t belong to your account. | Check the URL and IDs. Not retryable without changing the request. |
invalid_request | 400 | The request failed validation, either here or at the target platform — a required field is missing, a caption or title is over a platform’s character limit, an unsupported platform was listed, a URL isn’t a valid https:// link, the platform rejected the content. | Fix the request per message. Not retryable without changing the payload. |
quota_exceeded | 429 | A metered allowance is exhausted: monthly FFmpeg minutes or the daily DM cap. Publishing has no monthly cap on a paid plan, so on a publish call this only means the account has no active plan at all. | Not retryable until the allowance resets or the plan is activated/upgraded. Check Usage and surface the message to the user rather than looping retries. |
no_active_plan | 403 | You’re trying to connect a social account (mint a connect link) but the account has no active plan (zero profile allowance). | Activate a plan from the dashboard billing page first. Not retryable as-is. |
profile_limit_reached | 403 | Creating a new profile would exceed the current plan’s profile limit. | Upgrade the plan or delete an unused profile, then retry. |
rate_limited | 429 | You’ve exceeded the per-minute request rate limit (separate from the metered allowances — see Rate limits), or the publishing backend rate-limited the call. | Back off and honour the Retry-After header (seconds) before retrying. |
idempotency_conflict | 409 | The Idempotency-Key you sent was already used for a request with different parameters. | Use a new key for a genuinely new request, or confirm the payload matches the original attempt. Not safely retryable with the same key + different body. |
idempotency_in_progress | 409 | A request with this Idempotency-Key is still being processed (a concurrent or overlapping retry landed while the first attempt hadn’t finished). | Wait briefly and retry the same request with the same key — it will pick up the stored result once the first attempt completes. |
platform_not_startable | 400 | The platform is supported for publishing but cannot be started from the per-platform connect endpoint (Bluesky, which uses an app password rather than OAuth). | Use the shared connect link from POST /v1/connections/start for this platform instead. |
link_not_found | 404 | A connect-link token that does not exist or has expired (links live 48 hours). One code covers both, so a token cannot be probed for existence. | Mint a fresh link with POST /v1/connections/start. |
platform_not_connected | 409 | The Profile has no account connected for a platform the request targeted, so the post can never go out as sent. | Connect the account under Kết nối in the dashboard, or drop that platform from platforms. Retrying the same request unchanged cannot succeed. If it keeps happening right after each successful post, the platform is restricting the account and reconnecting will not lift it — see the message. |
upstream_error | 502 | A genuine failure of the publishing backend: a network error, or a 5xx from it. Content and permission problems are not in here — those are 400/409. | Transient. Safe to retry the whole request only if you sent an Idempotency-Key, so a retry can’t duplicate a post. |
upstream_timeout | 502 | The publish took longer than MADIAD Hub waits, so the outcome is unknown — the post may already be live. Nothing was refunded and the Idempotency-Key you sent is closed against this answer, so replaying it returns this same verdict rather than publishing a second copy. | Do not retry blindly. Check history or the platform itself first; if you decide to send it again, use a NEW Idempotency-Key. |
internal_error | 500 (rarely 502) | An unhandled error inside MADIAD Hub (database error, unexpected exception). Rare, and not something you caused. A few operations may return 502 instead of 500. | Treat both as retryable — retry with backoff. If it persists, contact support with the request details. |