Median

API overview

Base URLs, which API to call, credentials, Median keys and roles.

Updated Oct 4, 20265 minute read

Base URLs

SurfaceURL
REST APIhttps://api.median.sh/v1
MCP serverhttps://api.median.sh/mcp
OAuthhttps://api.median.sh/oauth/register, /oauth/authorize, /oauth/token, /oauth/device_authorization, /oauth/revoke
OAuth discoveryhttps://api.median.sh/.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource

The management endpoints are also reachable over MCP and through the CLI.

Which API

Messaging

Do what the widget does, from your server. These five routes accept only a Median key.

EndpointDoes
GET /v1/configOrganization name and the agent that answers
GET /v1/threadA session's conversation history
POST /v1/messagesSend a visitor message
POST /v1/typingSet the visitor's typing state
POST /v1/uploadsUpload a file to attach to a message

Tool endpoint

Point the agent at the routes you serve. These accept a Median key or an OAuth token.

EndpointDoes
GET /v1/tool-endpointsEvery connected route and what its last sync found
PUT /v1/tool-endpointsAdd a route, or re-sync one already connected
POST /v1/tool-endpoints/syncRe-read one route's manifest

Management

Everything the dashboard does, one row per area. Each row links to that area in the management reference.

AreaCovers
AccountWho a token is, creating and switching organizations, Median keys
ConversationsList, read, reply, note, resolve, archive, snooze, pause the AI, delete
Tool approvalsCalls waiting for approval, approve, deny, run a tool by hand, the tool list, switches, sync, test
Tool suggestionsTools the agent needed and did not have
CustomersList, read with learned facts, refresh a profile, reach out, delete
KnowledgeThe library tree, search, documents, folders, the review queue, crawls, source syncs
SignalsFile, edit, move, merge and accept bugs and suggestions, and apply fix commits
FeedbackSend one raw note and get the verdict back
TasksCards, columns, requests and task settings. See Tasks.
IntegrationsEmail, Slack, Discord, Linear and GitHub settings after the consent screen
OrganizationThe organization, members, invitations
AgentName, personality, behavior switches
WebhooksAdd, change and remove webhook endpoints
AnalyticsDashboard numbers, charts, the explorer, dataset fields
BillingAPI limits, usage, plan overview, invoices, the activity log
DocsSearch Median's documentation and read a page
CallAny MCP method by name, such as POST /v1/call/conversations.reply

Tools you serve

Each route you connect answers Median's signed manifest reads and tool calls. Its contract is in the tool endpoint reference. Build it with custom tools.

Authentication

Send the credential as a bearer token.

curl https://api.median.sh/v1/config \
  -H "Authorization: Bearer $MEDIAN_KEY"
CredentialStarts withOpensActs as
Median key (MEDIAN_KEY)median_key_Messaging, tool endpoint, management and MCP. Not the account routes.The organization, with admin rights
OAuth access token from median login or an MCP clientmedian_oat_Tool endpoint, management, account routes and MCP. Not messaging.The person who approved it, with their current role
Publishable keymedian_pk_None of the REST APIOnly the widget uses it
  • A Median key cannot send invitations or change members. Those return needs_a_person. Use an OAuth token.
  • The account routes are GET /v1/me, POST /v1/organizations and POST /v1/me/organization. A key gets 400 token_required.
  • An OAuth token on a messaging route gets 401 invalid_api_key.
  • A publishable key gets 401 publishable_key, except on the account routes, where it gets 400 token_required.
  • A token with no organization bound gets no_organization. Run median orgs create or median orgs use.
  • An access token lasts 8 hours and the client refreshes it. Token lifetimes and revocation are on the MCP page.

Error codes and statuses are in Errors and limits.

Keys

A Median key has two halves. The server half, MEDIAN_KEY, authenticates the API and signs identity, tool calls and webhooks. The public half, median_pk_, runs the widget. publicKeyFromMedianKey from @mediansh/agent-tools extracts it.

Create a key

In Settings → API, under Median keys, press Create key. From a terminal or a script:

median keys create --name production
curl https://api.median.sh/v1/keys \
  -H "Authorization: Bearer $MEDIAN_KEY" \
  -H "content-type: application/json" \
  -d '{"name":"production"}'

The dialog shows both values once, labeled Median key · server only and Public key · safe for the browser. POST /v1/keys returns { id, key, publicKey }. Only the response holds the full key. Every later read shows it masked.

RuleValue
Keys per organization10. The button reads Key limit reached, and the API returns too_many_keys.
NameOptional, up to 40 characters. Defaults to Median key N.
Who can create, list or revokeAdmins and owners
Last usedShown on each row, updated at most once an hour

Which key signs what

The widget's public key and its identity signatures must come from the same Median key.

ThingSigned with
Widget and its identity signaturesThe Median key the widget's median_pk_ belongs to
Tool endpoint added with PUT /v1/tool-endpoints and a keyThat key
Tool endpoint added from the dashboard, the CLI or an OAuth tokenThe key it already had, else the newest key
Webhook endpointThe newest key when the endpoint was added

Adding a webhook or a tool endpoint fails with missing_median_key until a key exists.

Revoke a key

In Settings → API, press Revoke on the row, then Revoke key. The CLI is median keys revoke <id> and the API is DELETE /v1/keys/{id}. It cannot be undone. Other keys keep working.

What used the keyAfter revoking
REST and MCP calls401 invalid_api_key on the next request
The widget with its median_pk_Stops connecting, identity included
Webhook endpoints it signedDeliveries keep arriving, but the signature never verifies. Remove the endpoint and add it again.
Tool endpoints it signedMedian's calls fail verification on your server. Send PUT /v1/tool-endpoints with the URL and a live key.

Roles

A Median key acts as an admin. An OAuth token acts with the role its person holds now, so a role change applies to the next request. A refusal returns 403 forbidden with a sentence such as "Only admins and owners can edit the agent." The full matrix is in Roles.

AreaAny memberAdmins and owners
AccountGET /v1/me, create and switch organizationsKeys
Conversations, customers, signals, feedbackEverything, delete included
Tool approvalsApprove, deny, run a tool, list tools, read tool endpointsSwitch tools on or off, sync, test, add or remove tool endpoints
Tool suggestions, agent, webhooksEverything
KnowledgeTree, search, read a documentWrites, folders, the review queue, crawls, source syncs
TasksCards, requests, reading task settingsChanging task settings
IntegrationsRead the overviewEvery change
OrganizationRead the organization and membersRename, invitations, roles, removing members
AnalyticsEverything elseGET /v1/analytics/activity and the activity log dataset
BillingLimits and usageOverview, invoices, logs
DocsEverything
CallWhatever the method allowsWhatever the method allows

CORS

/v1 sends no CORS headers. Call it from your server. /mcp, the /.well-known discovery documents and the OAuth endpoints except /oauth/authorize send Access-Control-Allow-Origin: *.

:::warning MEDIAN_KEY must never reach a browser. For a panel of your own, see Build your own widget. :::

Still need help?

    Esc