Getting started

Errors

Read the error envelope, branch on type and code, know which failures to retry, and handle per-platform publishing errors.

Pozy uses HTTP status codes and returns a JSON body on every failed request. Branch your code on the HTTP status and the code field. Show error to people, but never parse it: the wording can change.

#The error envelope

400
{
  "error": "`name` must be 1 to 50 characters.",
  "type": "invalid_request_error",
  "code": "invalid_field",
  "param": "name"
}
Field Always present Meaning
error Yes A sentence for humans. May be reworded at any time.
type Usually The class of error. See the table below.
code Usually A stable, machine-readable reason, such as read_only_key.
param When one field is at fault The field or query parameter, dotted when nested.
details Sometimes Structured context: the conflicting id, field errors, limits.
platform, platformError When a platform refused Which platform said no, and its original error payload.

Some endpoints add their own fields next to these. Payment errors carry reason and dashboard_url, for example (billing).

#Status codes and types

Status type When
400 invalid_request_error A field is missing or invalid, the JSON is malformed, or a precondition is not met.
401 authentication_error No credential, or it is invalid, revoked or expired.
402 payment_required The action needs a payment method or would pass a spend cap, or the workspace is paused because a payment failed.
403 permission_error The credential is valid but not allowed: read-only key, disabled group, role, scope, an unconfirmed email address, a feature that is not enabled, or a workspace paused by Pozy.
404 not_found The resource does not exist, or this credential cannot see it.
405 invalid_request_error The path exists but not with this method. error lists the allowed methods.
409 invalid_request_error A conflict: a duplicate post, an externalId already in use, a queue slot already taken, or a request with the same Idempotency-Key still running.
422 invalid_request_error The request is well formed but cannot be processed as sent.
429 rate_limit_error Too many requests, or a daily cap was reached. Wait Retry-After seconds when present (rate limits).
500 api_error Something failed on Pozy's side.
501 api_error The endpoint exists in the spec but is not available yet (not_implemented).
502 platform_error or api_error A platform returned an error or did not answer, or Pozy could not send an email.
503 platform_error A platform service Pozy relies on is unavailable right now. Nothing is wrong with your request. Retry later, after Retry-After seconds when present.

#Common codes

code Status Meaning
invalid_api_key 401 Missing or invalid credential.
read_only_key 403 A write with a read-only key.
resource_group_disabled 403 The key cannot use this area of the API.
insufficient_permissions 403 The key type cannot do this.
role_forbidden 403 Your workspace role cannot do this.
profile_out_of_scope 403 A profile-scoped key named another profile, or reached for the balance, transfers or payouts.
account_out_of_scope 403 A profile-scoped key named an account that belongs to another profile.
feature_not_available 403 Not enabled for the workspace. Contact support@pozy.ai.
payment_required 402 Add a payment method to continue.
workspace_suspended 402 The workspace is paused because a payment failed. Update the card in Billing to resume. Reads, billing and paying keep working; writes, connects and publishing are refused.
workspace_suspended 403 Pozy paused the workspace. Write to support@pozy.ai to resume it.
email_not_verified 403 Confirm your email address first, or add a payment method. Needed to send invitation emails and to connect accounts without a payment method.
missing_field, missing_required_field 400 A required field is absent. param names it.
invalid_field, invalid_field_value 400 Wrong type, format or value. param names it.
method_not_allowed 405 Wrong HTTP method for this path.
endpoint_not_found 404 No endpoint at this method and path. Check for typos and the /v1 prefix.
resource_not_found 404 The id is unknown or not visible to this credential. Specific variants exist, such as profile_not_found and webhook_not_found.
rate_limit_exceeded 429 Your workspace used its requests for this minute.
rate_limited 429 A platform or a per-endpoint quota said wait.
invite_limit_reached 429 The workspace sent its invitation emails for today (20 without a payment method, 500 with one), or has 50 email invitations waiting without a payment method. Share an invite link instead.
invite_resend_too_soon 429 An invitation can be emailed again once an hour.
support_ticket_limit 429 A workspace without a payment method sent its 5 questions to the Pozy team for today. Write to support@pozy.ai for anything urgent.
idempotency_key_in_use 409 A request with this Idempotency-Key is still running. Retry in a moment with the same key.
email_not_sent 502 Pozy could not send the email. Copy the invite link and share it yourself.
service_unavailable 503 Pozy cannot reach a platform service it relies on. Retry later.
temporarily_unavailable 503 A platform service Pozy relies on is temporarily unavailable, for example for new connections. Retry later.
platform_api_error 4xx or 502 The platform refused the call. Read platform and platformError.
not_implemented 501 Not available yet.

New codes can appear at any time, so always keep a default branch.

#Platform errors

When Instagram, Google, Meta or another platform refuses a request, the response says which one and includes its payload untouched:

400
{
  "error": "Google rejected the ad: NOT_ENOUGH_SQUARE_MARKETING_IMAGE_ASSET",
  "type": "platform_error",
  "code": "platform_api_error",
  "platform": "google",
  "platformError": { "code": 3, "message": "Request contains an invalid argument." }
}

A platform 4xx usually means the input needs fixing. A 502 means the platform failed or timed out, and a retry often works.

#Publishing errors live on the post

A scheduled post fails later, long after your request returned 200. Those failures do not come back as an error response. Instead, the post ends with status: "failed" (no target published) or "partial" (some did), and each failed entry in platforms[] explains why:

JSON
{
  "platform": "instagram",
  "status": "failed",
  "errorMessage": "The aspect ratio of this video is not supported for reels.",
  "errorCategory": "user_content",
  "errorSource": "user"
}
errorCategory Meaning What to do
auth_expired The platform revoked access. Ask the owner to reconnect the account, then retry.
user_content The content broke a platform rule: length, format, media size. Fix the post and retry.
user_abuse The platform flagged the content or the account. Review the content. Do not retry as is.
account_issue The account is restricted or missing a permission. Fix it on the platform side.
platform_rejected The platform refused without a clearer reason. Read errorMessage, adjust, retry.
platform_error The platform failed on its side. Retry later.
platform_rate_limit The platform throttled the account. Retry later.
quota_exhausted A daily or per-app quota is used up. Retry after the quota resets.
system_error Pozy failed to publish. Retry. Contact support if it repeats.
unknown Not classified. Read errorMessage.

errorSource tells you who has to act: user, platform or system. POST /v1/posts/{postId}/retry runs only the failed targets again. Subscribe to post.failed, post.partial and post.platform.failed to hear about these as they happen (post lifecycle).

207 is a success code

Publishing now (publishNow: true) or retrying can return 207 Multi-Status when the post was saved but at least one platform failed. Most HTTP clients treat 207 as success, so check post.status as well as the status code.

#What to retry

Response Retry? How
429 Yes Wait Retry-After seconds, then send the same request.
500, 502, 503 Yes Back off exponentially (1 s, 2 s, 4 s, up to about a minute). For creates, send the same Idempotency-Key (idempotency).
Network timeout Yes, carefully The request may have succeeded. Retry with the same Idempotency-Key, or read the resource first.
409 idempotency_key_in_use Yes Wait a moment, then send the same request with the same Idempotency-Key.
Other 409 No Read details. A duplicate post comes with the id of the existing one.
Other 4xx No Fix the request. Retrying the same body fails the same way.

#Request ids

Every response carries an X-Request-Id header. Log it with the error. Support can trace any request from that id (support).

You can send your own x-request-id (for example the id of your job) and Pozy uses it for that request, so your logs and Pozy's line up.

Terminal
curl -i https://api.pozy.ai/v1/posts/6721a0c47b2e5f9d3a18c6e0 \
  -H "Authorization: Bearer $POZY_API_KEY" \
  -H "x-request-id: 3e0f7a52-9b1c-4c6d-8f2e-5a7b9c1d3e4f"

#Handle errors in code

// A network error throws here: it is safe to retry with the same Idempotency-Key.
const res = await fetch("https://api.pozy.ai/v1/posts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.POZY_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ content: "Hello", platforms: [] }),
});
if (!res.ok) {
  const body = await res.json();
  const requestId = res.headers.get("x-request-id");
  if (res.status === 429 || res.status >= 500) {
    // retry later, see "What to retry"
  } else if (body.type === "invalid_request_error") {
    console.error(`Fix ${body.param ?? "the request"}:`, body.error, body.details);
  } else {
    console.error(res.status, body.code, body.error, `request ${requestId}`);
  }
}