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
Status
Meaning
400
The request is invalid, or it was refused by a rule with no status of its own
401
The credential is missing or matches nothing
403
The token's person does not hold the role this needs
404
Not found, or not in your organization
409
It already exists, or it was already settled
429
Rate limited. Wait the seconds in Retry-After.
500
internal_error. Retry, and contact support if it continues.
Error codes
Credentials and requests
Code
Status
When
missing_api_key
401
No Authorization: Bearer header
invalid_api_key
401
The key matches no organization or was revoked, or an OAuth token was sent to a messaging route
publishable_key
401
A median_pk_ key was sent. The API takes MEDIAN_KEY.
invalid_token
401
The OAuth token is unknown or expired, or its person left the organization
no_organization
403
The OAuth token has no organization bound, or its organization is gone
token_required
401
A key was sent to an account route
forbidden
403
The token's person lacks the role
needs_a_person
400
A key tried to invite or change members
legacy_api_key
400
A key from before Median keys was sent to PUT /v1/tool-endpoints
invalid_json
400
The body is not a JSON object
invalid_request
400
A 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.
The bot could not look up Slack or Discord channels or roles. Try again.
repo_name_invalid
400
The repository is not written as owner/repo
repo_already_connected
400
The repository is already connected
bad_docs_url
400
The published address of a repository is not a valid URL
address_private
400
The published address is not on the public internet
repo_not_connected
400
The repository is not connected
commit_repo_not_found
404
The repository's commits are not read
issue_repo_missing
400
Changing the issue repository's settings without naming a repository when none is set
address_taken
400
The support email address belongs to another organization
linear_failed
400
Median 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
Code
Status
When
already_a_member
409
The invited address is already in the organization
already_invited
409
An invitation to that address is pending
approval_settled
409
The tool call was already decided
approval_expired
409
The tool call expired, or its conversation ended
suggestion_settled
409
The suggestion was already approved or dismissed
suggestion_stale
409
The document changed after the suggestion was written
suggestion_gone
409
The suggestion's document was deleted
signal_exists
409
A signal with the same title or alias exists
crawl_running
409
That site is already being crawled
already_a_task
409
The signal is already on the task board
not_a_request
409
Declining 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.
Every GET, plus POST /v1/analytics/explore and POST /v1/analytics/records
Upload
POST /v1/uploads
Write
Every 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 Requestsretry-after: 3content-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.
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.
What
Limit
Counted per
Manifest syncs from POST /v1/tool-endpoints/sync, the Sync button, and one per endpoint from POST /v1/tools/sync
60 an hour, burst 10
Organization
Invitation emails, sent or resent
30 an hour, burst 10
Organization
MCP client registration, POST /oauth/register
300 an hour, burst 50
Caller IP address
Device login start, POST /oauth/device_authorization
300 an hour, burst 50
Caller 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
Limit
Value
Past it
Message body
4,000 characters after trimming
message_too_long
Attachments
6 per message
too_many_attachments
Upload
20 MB per file
file_too_big
Upload file name
200 characters
Cut to fit
Attachment types
text/html, application/xhtml+xml, image/svg+xml, text/xsl and application/xslt+xml upload, but are refused at send
attachment_wrong_type
Session token
8 to 128 characters after trimming
invalid_session
user.name
80 characters
Cut to fit
user.email
320 characters
Cut to fit
user.avatarUrl
An https URL, up to 512 characters
Dropped
user.metadata
16 entries. Keys and values up to 200 characters.
Extra entries dropped, text cut
Thread history
200 messages across the session's 10 most recently started conversations. The most recently active fill it first.