API overview
Base URLs, which API to call, credentials, Median keys and roles.
Base URLs
| Surface | URL |
|---|---|
| REST API | https://api.median.sh/v1 |
| MCP server | https://api.median.sh/mcp |
| OAuth | https://api.median.sh/oauth/register, /oauth/authorize, /oauth/token, /oauth/device_authorization, /oauth/revoke |
| OAuth discovery | https://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.
| Endpoint | Does |
|---|---|
GET /v1/config | Organization name and the agent that answers |
GET /v1/thread | A session's conversation history |
POST /v1/messages | Send a visitor message |
POST /v1/typing | Set the visitor's typing state |
POST /v1/uploads | Upload 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.
| Endpoint | Does |
|---|---|
GET /v1/tool-endpoints | Every connected route and what its last sync found |
PUT /v1/tool-endpoints | Add a route, or re-sync one already connected |
POST /v1/tool-endpoints/sync | Re-read one route's manifest |
Management
Everything the dashboard does, one row per area. Each row links to that area in the management reference.
| Area | Covers |
|---|---|
| Account | Who a token is, creating and switching organizations, Median keys |
| Conversations | List, read, reply, note, resolve, archive, snooze, pause the AI, delete |
| Tool approvals | Calls waiting for approval, approve, deny, run a tool by hand, the tool list, switches, sync, test |
| Tool suggestions | Tools the agent needed and did not have |
| Customers | List, read with learned facts, refresh a profile, reach out, delete |
| Knowledge | The library tree, search, documents, folders, the review queue, crawls, source syncs |
| Signals | File, edit, move, merge and accept bugs and suggestions, and apply fix commits |
| Feedback | Send one raw note and get the verdict back |
| Tasks | Cards, columns, requests and task settings. See Tasks. |
| Integrations | Email, Slack, Discord, Linear and GitHub settings after the consent screen |
| Organization | The organization, members, invitations |
| Agent | Name, personality, behavior switches |
| Webhooks | Add, change and remove webhook endpoints |
| Analytics | Dashboard numbers, charts, the explorer, dataset fields |
| Billing | API limits, usage, plan overview, invoices, the activity log |
| Docs | Search Median's documentation and read a page |
| Call | Any 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"| Credential | Starts with | Opens | Acts 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 client | median_oat_ | Tool endpoint, management, account routes and MCP. Not messaging. | The person who approved it, with their current role |
| Publishable key | median_pk_ | None of the REST API | Only 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/organizationsandPOST /v1/me/organization. A key gets400 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 gets400 token_required. - A token with no organization bound gets
no_organization. Runmedian orgs createormedian 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 productioncurl 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.
| Rule | Value |
|---|---|
| Keys per organization | 10. The button reads Key limit reached, and the API returns too_many_keys. |
| Name | Optional, up to 40 characters. Defaults to Median key N. |
| Who can create, list or revoke | Admins and owners |
| Last used | Shown 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.
| Thing | Signed with |
|---|---|
| Widget and its identity signatures | The Median key the widget's median_pk_ belongs to |
Tool endpoint added with PUT /v1/tool-endpoints and a key | That key |
| Tool endpoint added from the dashboard, the CLI or an OAuth token | The key it already had, else the newest key |
| Webhook endpoint | The 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 key | After revoking |
|---|---|
| REST and MCP calls | 401 invalid_api_key on the next request |
The widget with its median_pk_ | Stops connecting, identity included |
| Webhook endpoints it signed | Deliveries keep arriving, but the signature never verifies. Remove the endpoint and add it again. |
| Tool endpoints it signed | Median'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.
| Area | Any member | Admins and owners |
|---|---|---|
| Account | GET /v1/me, create and switch organizations | Keys |
| Conversations, customers, signals, feedback | Everything, delete included | |
| Tool approvals | Approve, deny, run a tool, list tools, read tool endpoints | Switch tools on or off, sync, test, add or remove tool endpoints |
| Tool suggestions, agent, webhooks | Everything | |
| Knowledge | Tree, search, read a document | Writes, folders, the review queue, crawls, source syncs |
| Tasks | Cards, requests, reading task settings | Changing task settings |
| Integrations | Read the overview | Every change |
| Organization | Read the organization and members | Rename, invitations, roles, removing members |
| Analytics | Everything else | GET /v1/analytics/activity and the activity log dataset |
| Billing | Limits and usage | Overview, invoices, logs |
| Docs | Everything | |
| Call | Whatever the method allows | Whatever 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.
:::