Median

Errors and limits

The error envelope, every error code, rate limits per plan and size limits for the REST API.

Updated Oct 1, 20268 minute read

Error response

Every error is JSON with a code and a message.

{
  "error": {
    "code": "invalid_session",
    "message": "Session tokens are 8 to 128 characters."
  }
}

Branch on code. The message is written for a person, names the fix, and can change.

Status codes

StatusMeaning
400The request is invalid, or it was refused by a rule with no status of its own
401The credential is missing or matches nothing
403The token's person does not hold the role this needs
404Not found, or not in your organization
409It already exists, or it was already settled
429Rate limited. Wait the seconds in Retry-After.
500internal_error. Retry, and contact support if it continues.

Error codes

Credentials and requests

CodeStatusWhen
missing_api_key401No Authorization: Bearer header
invalid_api_key401The key matches no organization or was revoked, or an OAuth token was sent to a messaging route
publishable_key401A median_pk_ key was sent. The API takes MEDIAN_KEY.
invalid_token401The OAuth token is unknown or expired, or its person left the organization
no_organization403The OAuth token has no organization bound, or its organization is gone
token_required401A key was sent to an account route
forbidden403The token's person lacks the role
needs_a_person400A key tried to invite or change members
legacy_api_key400A key from before Median keys was sent to PUT /v1/tool-endpoints
invalid_json400The body is not a JSON object
invalid_request400A field is missing or has the wrong type, or user, context or page holds a field that does not exist. In that last case the message lists the allowed fields. Unknown top-level fields are ignored.
not_found404No such route under /v1
rate_limited429See rate limits
internal_error500Median failed to handle the request

Messages and uploads

CodeStatusWhen
invalid_session400The session is not 8 to 128 characters after trimming
empty_message400No body and no attachments
message_too_long400The body is over 4,000 characters
too_many_attachments400More than 6 attachments
attachment_missing400An attachment id is not a file from POST /v1/uploads
attachment_wrong_type400The file is HTML, XHTML, SVG or XSLT
empty_file400The upload body is empty
file_too_big400The upload is over 20 MB

Keys, webhooks and tool endpoints

CodeStatusWhen
too_many_keys400The organization holds 10 Median keys
invalid_name400A key name is over 40 characters, or an agent name is not 2 to 40 characters
missing_median_key400Adding a webhook or tool endpoint before any Median key exists
invalid_url400The URL breaks the endpoint rules. The message says which.
no_events400A webhook endpoint with no events
too_many_endpoints400The organization holds 10 webhook endpoints
too_many_tool_endpoints400The organization holds 10 tool endpoints
no_endpoint400A sync with no url and no tool endpoint connected
endpoint_required400A sync with no url while several endpoints are connected
endpoint_not_found404A sync url that matches no connected endpoint
invalid_input400A tool's input does not match its schema
too_many_running400Three tools are already running in the conversation
conversation_archived400Running a tool in an archived conversation

Organization and members

CodeStatusWhen
invalid_slug400The slug is not 3 to 32 lowercase letters, numbers and single dashes, or it is reserved
slug_taken400Another organization has the slug
too_many_organizations400You are in 50 organizations
invalid_email400The invitation address is not an email address
too_many_invites400100 invitations are pending
cannot_grant400Only an owner can invite or make an owner
cannot_manage_self400Changing your own role or removing yourself
outranked400The member ranks at or above you and you are not an owner
last_owner400Demoting or removing the only owner
member_not_found404The user is not in the organization

Inbox, knowledge, signals and tasks

CodeStatusWhen
bad_snooze_time400The snooze time is invalid, under a minute away, or over a year away
not_archived400Deleting a conversation that is not archived
customer_unreachable400Reaching out to a customer who never opened the widget and has no email address
invalid_feedback400A feedback note over 2,000 characters
title_missing400A knowledge document with an empty title
body_missing400A knowledge document with an empty body
body_too_large400A knowledge document over 900,000 bytes
doc_is_synced400Editing a document synced from a repository or imported from Notion
folder_name_missing400A folder with an empty name
folder_too_deep400A fourth folder level
folder_cycle400Moving a folder into itself
order_invalid400The move destination no longer exists
bad_url400The crawl address is not a site address
upgrade_required400Starting a crawl without a paid plan
too_many_crawls400Three crawls are running
signal_empty400A signal with an empty title
title_required400A task with an empty title
key_prefix_invalid400A task key prefix that is not up to 8 letters or numbers starting with a letter
not_a_member400A task assignee who is not in the organization, or switching to an organization you are not in
invalid_query400An explorer query names a field or measure its dataset lacks
invalid_personality400Agent personality over 2,000 characters

Integrations

CodeStatusWhen
slack_not_connected, discord_not_connected, linear_not_connected, github_not_connected400Connect the app in the dashboard first. With several GitHub accounts connected, github_not_connected also means none of them owns the repository.
channel_not_found, role_not_found, team_not_found404No Slack or Discord channel, Discord role, or Linear team by that name. The message lists what exists.
mirror_bot_offline, mirror_bot_timeout, mirror_act_failed, discord_bot_offline, discord_bot_timeout, discord_act_failed400The bot could not look up Slack or Discord channels or roles. Try again.
repo_name_invalid400The repository is not written as owner/repo
repo_already_connected400The repository is already connected
bad_docs_url400The published address of a repository is not a valid URL
address_private400The published address is not on the public internet
repo_not_connected400The repository is not connected
commit_repo_not_found404The repository's commits are not read
issue_repo_missing400Changing the issue repository's settings without naming a repository when none is set
address_taken400The support email address belongs to another organization
linear_failed400Median could not read your Linear teams. The message says why.

Not found

The 404 codes are conversation_not_found, customer_not_found, fact_not_found, knowledge_doc_not_found, knowledge_folder_not_found, suggestion_not_found, signal_not_found, commit_not_found, approval_not_found, invite_not_found, endpoint_not_found, tool_not_found, key_not_found, org_not_found, task_not_found and log_not_found, and any other code ending in _not_found, such as member_not_found, channel_not_found, role_not_found, team_not_found, repo_not_found and commit_repo_not_found. An id from another organization reads as not found.

Conflicts

CodeStatusWhen
already_a_member409The invited address is already in the organization
already_invited409An invitation to that address is pending
approval_settled409The tool call was already decided
approval_expired409The tool call expired, or its conversation ended
suggestion_settled409The suggestion was already approved or dismissed
suggestion_stale409The document changed after the suggestion was written
suggestion_gone409The suggestion's document was deleted
signal_exists409A signal with the same title or alias exists
crawl_running409That site is already being crawled
already_a_task409The signal is already on the task board
not_a_request409Declining a card that is not in Requests

Rate limits

Limits apply per organization. Every key, OAuth token, MCP session and assistant action in the organization draws from one allowance. Each class is a token bucket with a sustained rate per minute and a burst that can be spent at once.

Tier (tier)PlanReads a minuteWrites a minuteUploads a minute
exploreExplore120, burst 2030, burst 105, burst 2
standardStandard6,000, burst 1,0001,200, burst 300300, burst 100
higherPro, or Standard with the API limits add-on12,000, burst 2,0002,400, burst 600600, burst 200
highestPro with the API limits add-on24,000, burst 4,0004,800, burst 1,2001,200, burst 400
unlimitedUnlimited API add-onNo fixed limit. Fair use applies.

Plan and add-on prices are in Plans.

What counts

ClassRequests
ReadEvery GET, plus POST /v1/analytics/explore and POST /v1/analytics/records
UploadPOST /v1/uploads
WriteEvery other POST, PUT, PATCH and DELETE
  • Each median.* call inside an MCP median_run counts as one request of its class.
  • The assistant's actions count the same way.
  • A request is charged before it runs, so a request that fails afterwards still counts.
  • POST /v1/organizations and POST /v1/me/organization always draw from a per-person allowance. GET /v1/me does too while the token has no organization, or its person has left it. The allowance is 600 reads a minute with a burst of 100, and 120 writes a minute with a burst of 30.

When you hit a limit

HTTP/1.1 429 Too Many Requests
retry-after: 3
content-type: application/json

{"error":{"code":"rate_limited","message":"Your organization's API allowance is temporarily full. Please retry shortly."}}
  • Retry-After is in whole seconds, at least 1.
  • Median can restrict an organization under fair use. The response is the same 429 rate_limited, with "reason": "fair_use" in error and "API access is temporarily limited to protect shared capacity. Please retry shortly." or "API access is temporarily limited because unusual automated traffic was detected. Contact support for review."
  • Each refusal of the organization's allowance is recorded in Logs as API limit reached.

Read your limits

curl https://api.median.sh/v1/billing/limits \
  -H "Authorization: Bearer $MEDIAN_KEY"
{
  "tier": "standard",
  "version": "2026-09-22",
  "limits": {
    "read": { "perMinute": 6000, "burst": 1000 },
    "write": { "perMinute": 1200, "burst": 300 },
    "upload": { "perMinute": 300, "burst": 100 }
  }
}

limits is null on unlimited. Any member can call it. The CLI is median billing limits. The dashboard shows the same numbers in Settings → Billing on the API limits row.

Other limits

These are separate buckets. A REST call that meets one is still charged to the tier as well.

WhatLimitCounted per
Manifest syncs from POST /v1/tool-endpoints/sync, the Sync button, and one per endpoint from POST /v1/tools/sync60 an hour, burst 10Organization
Invitation emails, sent or resent30 an hour, burst 10Organization
MCP client registration, POST /oauth/register300 an hour, burst 50Caller IP address
Device login start, POST /oauth/device_authorization300 an hour, burst 50Caller IP address
  • Adding a tool endpoint or changing its URL is not counted as a sync.
  • Registration and device login also share a ceiling of 6,000 an hour across all callers.
  • The REST buckets refuse with 429 rate_limited and "Too many requests. Wait a moment and try again." The OAuth routes refuse with 429 and the OAuth error slow_down.

Size limits

LimitValuePast it
Message body4,000 characters after trimmingmessage_too_long
Attachments6 per messagetoo_many_attachments
Upload20 MB per filefile_too_big
Upload file name200 charactersCut to fit
Attachment typestext/html, application/xhtml+xml, image/svg+xml, text/xsl and application/xslt+xml upload, but are refused at sendattachment_wrong_type
Session token8 to 128 characters after trimminginvalid_session
user.name80 charactersCut to fit
user.email320 charactersCut to fit
user.avatarUrlAn https URL, up to 512 charactersDropped
user.metadata16 entries. Keys and values up to 200 characters.Extra entries dropped, text cut
Thread history200 messages across the session's 10 most recently started conversations. The most recently active fill it first.Older messages left out
Knowledge document900,000 bytesbody_too_large
Feedback note2,000 charactersinvalid_feedback
Median keys10 per organizationtoo_many_keys
Webhook endpoints10 per organization, URLs up to 512 characterstoo_many_endpoints
Tool endpoints10 per organization, URLs up to 512 characterstoo_many_tool_endpoints
Pending invitations100 per organizationtoo_many_invites
Organizations50 per persontoo_many_organizations
Crawls running3 per organizationtoo_many_crawls
Tools running3 per conversationtoo_many_running
Knowledge folders3 levels deepfolder_too_deep

Still need help?

    Esc