Send a message
The first message creates the visitor and the conversation. The AI starts answering unless a person already holds the thread.
New user values overwrite old ones and omitted fields are not erased. Query strings are stripped from page URLs on arrival.
POST
/messagesAuthorization
AuthorizationBearer token · headerrequiredA MEDIAN_KEY from Settings under API. It starts with `median_key_` and stays on your server. The tool endpoint routes also accept an OAuth access token (`median_oat_`) from `median login` or an MCP client, acting as the person who approved it. The messaging routes accept only a Median key.
Request body
requiredapplication/jsonsessionstringrequiredThe visitor's session token.
min length 8 · max length 128
bodystringrequiredThe message. Can be empty when the message carries attachments.
max length 4000
userobjectWho this is, shown to your team.
Show propertiesHide properties
namestringCut to 80 characters.
emailstringCut to 320 characters.
avatarUrlstringAn HTTPS URL up to 512 characters. Anything else is dropped.
metadataobjectYour own facts about them: plan, seats, account age. The first 16 entries are kept, and keys and values are cut to 200 characters.
contextobjectThe visitor's browser, shown beside the thread.
Show propertiesHide properties
timeZonestringlocalestringbrowserstringosstringdevicestringAllowed:
desktoptabletmobilescreenstringpageobjectWhere they wrote from. Kept on the conversation's first message.
Show propertiesHide properties
urlstringrequiredtitlestringreferrerstringattachmentsobject[]Up to 6 files, with ids from POST /uploads.
max items 6
Show propertiesHide properties
Array of
objectidstringrequirednamestringrequiredResponses
200The conversation it landed in, and the message.
conversationIdstringrequiredmessageIdstringrequired400`invalid_json`: the body is not a JSON object. `invalid_request`: a field is missing, has the wrong type, or is unknown, and the message names the allowed fields. `invalid_session`: the session is not 8 to 128 characters. `empty_message`: no body and no attachments. `message_too_long`: the body is over 4,000 characters. `too_many_attachments`: more than 6. `attachment_missing`: an id is not a file from `POST /uploads`. `attachment_wrong_type`: the file is HTML, XHTML, SVG or XSLT.
errorobjectrequiredShow propertiesHide properties
codestringrequiredBranch on this rather than on the message.
messagestringrequired401`missing_api_key`: no bearer token. `invalid_api_key`: the key matches no organization or was revoked. `publishable_key`: a `median_pk_` key was sent. An OAuth access token is refused here with `invalid_api_key`.
errorobjectrequiredShow propertiesHide properties
codestringrequiredBranch on this rather than on the message.
messagestringrequired429The organization's API allowance for this class of request is used up. Wait the `Retry-After` header's seconds. Limits depend on the plan. See [rate limits](/api/errors-and-limits#rate-limits).
errorobjectrequiredShow propertiesHide properties
codestringrequiredBranch on this rather than on the message.
messagestringrequiredRequest
curl -X POST "https://api.median.sh/v1/messages" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"session": "user_42",
"body": "How do I export my data?",
"user": {
"name": "Ada",
"email": "ada@example.com"
}
}'const response = await fetch("https://api.median.sh/v1/messages", {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
"session": "user_42",
"body": "How do I export my data?",
"user": {
"name": "Ada",
"email": "ada@example.com"
}
})
});Response
{
"conversationId": "js7...",
"messageId": "jd2..."
}{
"error": {
"code": "empty_message",
"message": "Enter a message or attach a file."
}
}{
"error": {
"code": "invalid_api_key",
"message": "That Median key does not match any organization. Copy the median_key_ key again from Settings under API."
}
}{
"error": {
"code": "rate_limited",
"message": "Your organization's API allowance is temporarily full. Please retry shortly."
}
}