Reference

Error reference

Every error code the API returns, what causes it, and whether retrying helps.

Every failure from /v1 and /mcp uses one envelope. Branch on code; it is stable. Never branch on message, which is written for humans and will change.

{
  "error": {
    "code": "accounts_not_found",
    "message": "None of the supplied accountIds matched a connected account in this profile.",
    "docsUrl": "https://cutedyno.com/docs/errors#accounts_not_found",
    "requestId": "8f14e45f-ea0c-4d7a-9f1a-2b3c4d5e6f70"
  },
  "message": "None of the supplied accountIds matched a connected account in this profile."
}

Four fields carry the useful information:

  • code — the stable identifier to switch on.
  • message — a human explanation, safe to log and usually safe to show an operator.
  • docsUrl — a deep link to this page, anchored at the code.
  • requestId — echoes the X-Request-Id header. Quote it when reporting a problem and we can find the exact request.

Some codes add a details object. plan_limit carries entitlement, usage, and limit; insufficient_permission carries the required permission; daily_post_limit carries limit, used, and resetsAt.

Handling errors in code

import { CuteDynoError } from '@cutedyno/node';

try {
  await cutedyno.posts.create(input);
} catch (error) {
  if (!(error instanceof CuteDynoError)) throw error;

  switch (error.code) {
    case 'no_accounts_connected':
    case 'accounts_not_found':
      return promptUserToReconnect();

    case 'plan_limit':
    case 'trial_expired':
      return showUpgradePrompt(error.details);

    case 'rate_limit_exceeded':
      return retryAfter(error.retryAfter ?? 60);

    default:
      if (error.isRetryable) return scheduleRetry();
      log.error('CuteDyno rejected the post', {
        code: error.code,
        requestId: error.requestId,
      });
      throw error;
  }
}

The rule of thumb: 4xx is your bug or your user's state, 5xx and 429 are ours. Retry the second group with the same idempotency key; fix or surface the first.

Codes by status

400Bad request

CodeWhat it meansRetry?
invalid_request

Invalid request

The request body or query string failed validation. The message names the offending field.No
invalid_profile_id

Invalid profile id

profileId was supplied but was not a string.No
invalid_scheduled_at

Invalid scheduledAt

scheduledAt could not be parsed as an ISO 8601 datetime, or it is in the past.No
invalid_state_transition

Invalid state transition

The post is in a state that does not allow this operation, for example editing a post that already published.No
key_not_linked_to_user

API key not linked to a user

Publishing records a human actor. Recreate the key from the dashboard so it carries an owner.No

401Unauthenticated

CodeWhat it meansRetry?
authentication_required

Authentication required

No Authorization header was sent, or it was not a Bearer token.No
invalid_api_key

Invalid API key

The key does not exist, was revoked, or is malformed. Keys start with cdyn_live_.No
api_key_expired

API key expired

The key passed its expiresAt date. Create a replacement key.No

402Payment required

CodeWhat it meansRetry?
trial_expired

Trial expired

The account trial ended. Billing affects every profile at once, so alert an operator instead of retrying.No

403Forbidden

CodeWhat it meansRetry?
insufficient_permission

Insufficient permission

The key is missing the scope this endpoint needs, for example posts:write on a readonly key.No
profile_not_accessible

Profile not accessible

The requested profile is outside this key’s scope, or belongs to another account.No
plan_limit

Plan limit reached

A plan quota was exhausted. The response carries entitlement, usage, and limit so you can surface the reason.No
account_not_allowed

Account not allowed

The key is restricted to specific connected accounts and one of the supplied accountIds is not among them.No
platform_not_allowed

Platform not allowed

The profile policy restricts which platforms may be posted to, and one of the target accounts is on a platform outside that list.No
approval_required

Approval required

This profile or key forces posts through review, and no approver could be determined. Supply approvers, or recreate the key so it carries an owner.No
daily_post_limit

Daily post limit reached

The key has a maxPostsPerDay cap and it has been reached. The cap resets at midnight UTC.No

404Not found

CodeWhat it meansRetry?
not_found

Not found

The resource does not exist inside the resolved profile.No
no_accounts_connected

No accounts connected

The profile has no connected social accounts yet. Run the connect flow first.No
accounts_not_found

Accounts not found

None of the supplied accountIds matched a connected account in this profile.No

409Conflict

CodeWhat it meansRetry?
idempotency_key_reused

Idempotency key reused

This Idempotency-Key was already used with a different request body. Use a fresh key.No
profile_has_connected_accounts

Profile still has connected accounts

Disconnect the profile’s social accounts before deleting it, so tokens are revoked deliberately.No

415Error

CodeWhat it meansRetry?
unsupported_media_type

Unsupported media type

The fileType passed to POST /v1/media/upload is not an accepted image or video type.No

429Too many requests

CodeWhat it meansRetry?
rate_limit_exceeded

Rate limit exceeded

Too many requests for this key. Honour the Retry-After header before retrying.Yes

500Server error

CodeWhat it meansRetry?
internal_error

Internal error

Something failed on our side. Retry with the same Idempotency-Key; report the requestId if it persists.Yes

Legacy error format

Before this envelope existed, errors were { "error": "some string" }. If you have a client written against that shape and cannot change it yet, send:

CuteDyno-Error-Format: legacy

and responses revert to { "error": "<message>", "code": "<code>" }. This is a migration aid with a limited life. Prefer reading error.code from the structured shape, which every current response already includes.

MCP errors

Tool calls surface the same codes. A failing tool returns isError: true with the code, message, and request ID in the text, so an agent can explain what went wrong rather than retrying blindly. See MCP.