Tesselith
ProductSolutionsCompareFree toolsBlogPricing
Join the waitlist
  1. Home/
  2. Docs/
  3. API Error Codes

REST API

API Error Codes

Updated October 30, 2026

Every error code the Tesselith REST API returns, what it means and what to do about it, with retry rules and an example handler.

When a Tesselith API request fails, the response is an RFC 9457 problem document with Content-Type: application/problem+json. Its code is stable and meant for your code to switch on. Its type is a link to that code's entry on this page. Its detail is a sentence for humans and can change wording at any time.

{
  "type": "https://tesselith.com/docs/api/errors#no-queue-slot",
  "title": "Unprocessable content",
  "status": 422,
  "detail": "These channels have no free queue slot in common. Add times to their posting schedule, or pick a time.",
  "code": "NO_QUEUE_SLOT"
}

Key takeaways

  • Branch on code, never on detail or title.
  • Retry only 409 IDEMPOTENCY_IN_PROGRESS, 429 RATE_LIMITED, 500 and 503, with the same Idempotency-Key.
  • Every other 4xx means the request needs to change before it can succeed.
  • Extra fields (such as errors, required_permission or max_bytes) are snake_case and only added where they help.

Handling errors in code

const res = await fetch(`${API}/posts/${id}/queue`, { method: "POST", headers, body: "{}" })
if (!res.ok) {
  const problem = await res.json()
  switch (problem.code) {
    case "NO_QUEUE_SLOT":
      return scheduleAt(id, fallbackTime)        // no slot: pick a time instead
    case "RATE_LIMITED":
      await sleep(Number(res.headers.get("Retry-After")) * 1000)
      return queue(id)                            // safe to retry
    case "VALIDATION_ERROR":
      throw new Error(problem.errors.map((e) => `${e.path}: ${e.message}`).join("; "))
    default:
      throw new Error(`${problem.code}: ${problem.detail}`)
  }
}

Authentication and access

UNAUTHORIZED

HTTP 401. No Authorization: Bearer header, or the key is wrong, expired or revoked, or its creator is no longer in the workspace.

What to do: Check the key in Settings → Developers. Don't retry automatically: the same key will fail the same way.

FORBIDDEN

HTTP 403. The key is valid but not allowed to do this. Either it lacks the scope (the response's required_permission names it), or its creator's current role doesn't include that permission.

What to do: Create a key with the missing scope, or ask an owner to raise the creator's role. A key never has more access than its creator.

POST_LIMIT_REACHED

HTTP 403. Scheduling this post would go past the plan's monthly post allowance. Each channel a post goes to counts as one, and scheduled posts count as soon as they're scheduled.

What to do: Wait for the next billing period or upgrade the plan. Drafts don't count, so you can keep writing them.

PLAN_UPGRADE_REQUIRED

HTTP 403. The workspace's plan doesn't include this feature. The API, webhooks and MCP are included from the Pro plan; the response's required_plan names the lowest plan that has it.

What to do: Upgrade the workspace under Plans & billing. Existing keys start working again as soon as the plan changes.

Requests

VALIDATION_ERROR

HTTP 422. The body or query didn't match the schema. The errors array lists each problem with a dotted path (for example thread.0.channel_id) and a message.

What to do: Fix the listed fields. The OpenAPI document at /v1/openapi.json describes every field and its limits.

BAD_REQUEST

HTTP 400. The request couldn't be read at all, usually malformed JSON or the wrong Content-Type.

What to do: Send Content-Type: application/json with a valid JSON body (or multipart for file uploads).

NOT_FOUND

HTTP 404. The post, channel, endpoint or route doesn't exist in this workspace. Objects in other workspaces are reported as not found, never as forbidden.

What to do: Check the id and that the key belongs to the workspace that owns the object.

INTERNAL_ERROR

HTTP 500. Something failed on our side. It has been logged.

What to do: Retry with backoff and the same Idempotency-Key. If it persists, email [email protected] with the time of the request.

Posts and scheduling

UNKNOWN_CHANNEL

HTTP 422. One or more channel_ids (or a thread item's channel_id) aren't channels in this workspace.

What to do: Use ids from GET /channels.

UNKNOWN_MEDIA

HTTP 422. One or more media_ids aren't media files in this workspace.

What to do: Upload with POST /media first and use the returned id.

INVALID_TRANSITION

HTTP 422. The post can't move to that status from where it is, for example editing a post that is already publishing or has been published.

What to do: Read the post's current status and act on that. Create a new post to repost published content.

SCHEDULE_TIME_REQUIRED

HTTP 422. A post was set to scheduled without a time.

What to do: Use POST /posts/{id}/schedule with scheduled_at, or POST /posts/{id}/queue to take a slot.

NO_CHANNELS

HTTP 422. The post has no channels, so there is nothing to queue it on.

What to do: Set channel_ids with PATCH /posts/{id} first.

NO_QUEUE_SLOT

HTTP 422. The post's channels share no free posting slot in the planning window. Either a channel has no weekly schedule, or every slot is taken.

What to do: Add times with PUT /channels/{id}/schedule, or schedule for an exact time instead.

QUEUE_CHANGED

HTTP 409. The queue was changed by someone else while a reorder was being saved.

What to do: Fetch the queue again and retry.

APPROVAL_DISABLED

HTTP 400. The post was sent for client approval in a workspace that hasn't turned approvals on.

What to do: Enable approvals in Settings → Approvals, or schedule the post directly.

Media

UNSUPPORTED_MEDIA_TYPE

HTTP 422. The file's type isn't accepted. Allowed: JPEG, PNG, GIF, WebP, MP4, MOV, WebM, AVI, WMV, MPEG, 3GP, FLV, PDF, VTT, SRT and TTML.

What to do: Convert the file, and make sure multipart uploads send the right Content-Type for the part.

FILE_TOO_LARGE

HTTP 422. The file is over the limit for its type: 32 MB for images, 100 MB for everything else through the API. max_bytes gives the exact limit.

What to do: Compress the file or upload a smaller rendition.

URL_UNAVAILABLE

HTTP 422. A media URL couldn't be fetched safely: it isn't public HTTPS, resolves to a private or metadata address, redirects, or took longer than 15 seconds.

What to do: Host the file at a public HTTPS URL that serves it directly, or upload the bytes as multipart.

STORAGE_UNAVAILABLE

HTTP 503. Media storage is temporarily unavailable.

What to do: Retry with backoff.

Webhooks

INVALID_URL

HTTP 422. The endpoint URL isn't allowed: it must be public HTTPS, and private, loopback, link-local and cloud-metadata addresses are refused.

What to do: Use a publicly reachable HTTPS URL. For local testing, expose your server with a tunnel.

LIMIT_REACHED

HTTP 409. The workspace already has 20 webhook endpoints.

What to do: Delete unused endpoints, or subscribe one endpoint to several event types.

Retries, idempotency and limits

RATE_LIMITED

HTTP 429. The key went over its plan's requests per minute: 120 on Pro, 300 on Team, 600 on Agency.

What to do: Wait the number of seconds in Retry-After. The RateLimit header on every response tells you how many requests remain.

BAD_IDEMPOTENCY_KEY

HTTP 400. The Idempotency-Key header is empty or longer than 255 characters.

What to do: Send a UUID or your own record id.

IDEMPOTENCY_IN_PROGRESS

HTTP 409. A request with the same Idempotency-Key is still being processed.

What to do: Retry after a short delay; you'll get the original response once it finishes.

IDEMPOTENCY_KEY_REUSED

HTTP 422. The Idempotency-Key was already used in the last 24 hours for a request with a different method, path or body.

What to do: Use a new key for each distinct request. Reuse a key only to retry the identical request.

Questions developers ask

Which API errors are safe to retry?
409 IDEMPOTENCY_IN_PROGRESS, 429 RATE_LIMITED (after Retry-After), 500 INTERNAL_ERROR and 503 STORAGE_UNAVAILABLE. Retry with the same Idempotency-Key so a request that actually succeeded isn't repeated.
Why do I get NOT_FOUND for an object I know exists?
The key belongs to a different workspace. Objects outside the key's workspace are always reported as not found, so the API never confirms they exist.

Build on Tesselith

Create a workspace, connect your channels and generate an API key in Settings → Developers.

Join the waitlist

Related pages

API getting startedWebhooks guideREST API overview

More docs

Tesselith API: Getting Started GuideWebhooks: Real-Time Events From TesselithConnect Claude and Other AI Assistants to Tesselith (MCP)

Opening soon

Be first in when the doors open.

Join the waitlist and you'll be in the first wave of invites. One email when it opens, nothing else.

Join the waitlist
Tesselith

The social scheduler for creators, teams and agencies. One calendar, every network you post to.

Product

  • Composer
  • Calendar
  • Analytics
  • Automation
  • AI assistant
  • Posting queue
  • API & webhooks
  • MCP server
  • All features

Solutions

  • Creators
  • Agencies
  • Small business
  • E-commerce
  • All solutions

Compare

  • vs Buffer
  • vs Hootsuite
  • vs Later
  • vs Sprout Social
  • All comparisons
  • Alternatives

Free tools

  • Character counter
  • Best time to post
  • UTM builder
  • Engagement rate
  • All tools

Company

  • About
  • Blog
  • Developer docs
  • Pricing
  • Contact
  • Security
  • Status

Legal

  • Privacy
  • Terms
  • Cookies
  • Acceptable Use
  • DPA
  • Refunds

Schedule posts for

  • X (Twitter)
  • Instagram
  • Facebook Pages
  • LinkedIn
  • YouTube
  • TikTok
  • Threads
  • Bluesky
  • Mastodon
  • Pinterest
  • Reddit
  • Discord
  • Telegram
  • Dev.to
  • Hashnode
© 2026 Tesselith. All rights reserved.
PrivacyTermsCookiesSecurityData deletion
Tesselith