Base URL
Authentication
Send your API token in thex-cominty-token header on every request. Create a
token on the API keys page at
platform.cominty.ai.
sk-cmt-. Paste it into the header exactly as
you received it, with or without a single Bearer in front. Both forms work:
sk-cmt- and keeps working when sent as is.
Authentication errors
Chat and threads are scoped to one end user via
user_id. Chat start sends
it in the body (options.user_id). Thread endpoints send it as a query
parameter. The SDKs fill this in from the client, so you never pass it on
those calls. Memory endpoints may accept user_id as an optional query, but
it does not select a memory namespace. See
Memory endpoints.Endpoints
Memory endpoints
Memory files live in a namespace you choose. For the concepts (identity of a file, isolating users, attaching a thread), see Memory namespaces. This section covers what is specific to the endpoints. The endpoint pages listnamespace as optional (max 128 characters). On the
platform API it is required for create, get, update, and delete: omit it and
the call returns 400 Missing namespace.
POST /memory sends namespace in the JSON body, next to path, purpose,
and content. The other memory calls send it as a query parameter. user_id
may still appear as an optional query. It does not choose the namespace. A
user_id in the body of POST /memory is ignored, with no error.
A thread’s memory namespace is a capability: send
options.capabilities.memory on POST /chat. See Capabilities.
options.memory_namespace still works but is deprecated.
POST /chat/{thread_id} accepts neither.
GET /memory/namespaces can still return stored names such as
user_abc::default. They hold files written before namespaces existed. See
Files written before namespaces existed.Capabilities
Capabilities decide what the agent can use:web, indexed_documents, mcp,
skills, image_generation, video_generation, music_generation, and
memory. For the concepts, see Capabilities. This
section covers what is specific to the endpoints.
- Each capability in
options.capabilitiesis an object with a requiredactivation:always,on_request, ornever.skillsandmemoryaccept onlyalwaysandnever. Aneverentry takes no other field. - A capability you send replaces the agent’s value entirely. An omitted
filter goes back to
"*"(no restriction). A capability you do not send keeps the agent’s value. - Filters (
source_ids,document_ids,connections,include) are either the string"*"or a list with at least one item.nulland[]return 422. - Each entry in
message.scopeis an object with a requiredenabled. Theskillsandmemorykeys return 422. - A scope can only narrow. It must stay inside the thread’s list.
options.capabilitiesonPOST /chat/{thread_id}returns 422. The OpenAPI schema lists the field there, but a follow-up cannot change the thread.- The thread’s capabilities are not returned by any endpoint.
Errors
The errordetail has two shapes.
Mixing the new and the legacy fields also returns 422:
options.capabilities with options.memory_namespace, or message.scope with
message.disabled_tools, message.source_ids or message.document_ids. The
legacy fields are deprecated and will be removed in a later version.
Configure with an API key
An API key acts as an admin of its own organization. It can call the agent, skill, drive, source, and document endpoints below, and read the model catalog. These endpoints do not takeuser_id. For the concepts and the
SDKs, see Custom agents, Skills,
and Sources. This section covers what is specific to the
endpoints.
- Everything a key creates is owned by the user who created the key.
owneron an agent andcreated_byon a source are that user’s id, not the key’s. - A key never sees another member’s private agents, skills, or drives. A
direct read, update, or delete returns 404
Not Found, and they are absent from lists. - A key only sees its own product surface. A Platform key does not see agents created on the other surface.
- Send one credential. If
x-cominty-tokenis present, anAuthorizationheader is ignored.
MCP endpoint
GET /mcp/manifest returns {"servers": [...]}. Use a server’s name in
capabilities.mcp.connections. Servers that are off are still listed, with
is_enabled false. The optional fields (connection_status, icon_uri,
mcp_url, owner_id, created_at, updated_at) are omitted when
unknown, not null. A manifest that cannot be loaded returns 500 with the
plain text Internal Server Error, so do not parse that body as JSON.
Agent endpoints
PUT /agents/{agent_pid}is partial. A JSONnullclearsdescription,instructions, andcapabilities.capabilitiesis merged capability by capability: each one you send replaces the stored one, the others stay.- Omit
model_idsonPOST /agentsto use the organization’s default model chain. The chain is a failover order: the first model answers. - On a built-in agent,
PUT /agents/{agent_pid}/modelschanges the chain for the whole organization. - An organization agent owned by someone else can be updated and deleted with the key.
execution_optionsandmemory_namespaceare deprecated. Usecapabilities(capabilities.memorysets the namespace).
Skill endpoints
POST /skills and POST /skills/{skill_pid}/versions are
multipart/form-data. Send the zip in the file field. POST /skills also
takes display_name (1 to 100 characters) and scope.
DELETE /skills/{skill_pid} returns 200 with a null body and removes
every version. Do not send a surface field: an API key cannot choose a
surface, and the call returns 400 Forbidden field.
Source endpoints
A source indexes the files of a drive. With an API key, onlystore: "draganddrop" works. Creating one is a 5-step flow, like a file
upload:
POST /drivesreturns the drive, with itsid.GET /drives/{drive_pid}/upload?filename=...&mimetype=...returns a presignedurlandfields.filenamecannot contain/.- POST the file to that
urlasmultipart/form-data, withfieldsas form fields, and read theETagresponse header. Do not sendx-cominty-tokento this host. POST /drives/uploadwith{"etag": ..., "key": ...}. Thekeycomes from thefieldsof step 2. The response is the file.POST /dc/sourceswithstore,scope, andconfig.drive_id. The first sync starts at once.
status pending or syncing. Poll GET /dc/sources until
the source is synced, then search it.
- Two ids.
idis a number: capabilities and scopes take it insource_ids.pidis a string: every path takes it. - No single read. There is no
GET /dc/sources/{pid}. Read the list and pick.GET /dc/sourcesincludes archived sources.archived=truekeeps only those,archived=falsehides them. - Files.
DELETE /files/{file_pid}returns 200 with anullbody.GET /files/{file_pid}returns a download URL as a bare JSON string, valid for 5 minutes. Fetch it without the key. After you add or delete a file, call thesyncoperation.
PUT /dc/sources/{source_pid}/status?operation=... runs one operation:
Any other combination returns 400
Operation is not valid. An unknown
operation returns 422.
A source created with a key is private to the key owner. A chat that searches
it must run with the owner’s
user_id, as the agent’s owner shows. With
another user_id, the agent’s document tool reports that it has no authorized
source. See Sources.Document endpoint
GET /documents?id=... resolves one document id, such as the one in a
<cite document_id="2292#8058" .../> tag of an answer. The id contains a #,
so URL-encode it (2292%238058). There is no list. An unknown id returns
404 Not Found.
Tool round cap
POST /chat and POST /chat/{thread_id} accept options.max_steps: an
integer >= 1 that caps the tool rounds of that message. Omit it and the
server applies its default (60 today, and it may change). The cap is per
message and is not stored or returned. Each sub-agent has its own counter. For
the behavior, see
Limiting agent steps.
Reaching the cap is not an error. The message ends with status success and
error_code null. Continue with POST /chat/{thread_id}.
No thread or message is created when the request is rejected.
One message at a time
A thread processes one message at a time. AfterPOST /chat or
POST /chat/{thread_id}, the assistant message is pending (live: true). It
only finishes when you read its events to the end with
GET /chat/messages/{message_id}/stream, or when you cancel it. Until then,
posting another message to the same thread returns 400:
Closing the stream connection does not stop the message. The server keeps it
pending. To free the thread:
- Find the pending message:
GET /chat/{thread_id}returns each message withlive. A message withlive: trueis still pending. - Read it to the end with
GET /chat/messages/{message_id}/stream, or cancel it withPOST /chat/messages/{message_id}/cancel. - Post the next message.
Too many concurrent requests when your plan’s limit on simultaneous chats is reached.
Cancel and export a message
Cancelling is not idempotent: a second cancel returns 400. The export
response carries no file name. Choose one when you save the bytes.
Files and exports
Limits to plan for:- A file is at most 500 MiB on the hosted API. The storage host refuses a bigger one, and another deployment may set a lower limit.
- Your organization has a daily upload quota. When it is used up, the storage host refuses the upload.
- The download URL is short-lived (5 minutes). Fetch it right away.
- No endpoint lists or deletes uploaded files.
- A presigned URL carries a signature in its query string. Do not log it.