Skip to main content

Channels API

All endpoints require an authenticated session. Agents use the same session mechanism — they authenticate via their VaultysId during the WebSocket handshake, which grants them an HTTP session for REST calls.


Channels

List channels

GET /api/channels?realm=<realmId>

Auth: Required.

Returns all non-archived channels in the realm, plus global channels (realmId = null).

Query parameters:

ParameterRequiredDescription
realmYesRealm ID to scope the query
includeArchivedNoSet to true to include archived channels
includeGlobalNoDefault true. Set to false to exclude global channels.

Response 200:

{
"channels": [
{
"id": "ch_01HZ...",
"realmId": "realm_01HZ...",
"name": "Engineering",
"slug": "engineering",
"description": "Internal engineering channel",
"topic": "Current sprint: auth refactor",
"isPublic": true,
"isArchived": false,
"creatorDid": "did:vaultys:z6Mk...",
"createdAt": "2026-05-26T09:00:00Z",
"updatedAt": "2026-05-26T09:00:00Z"
}
]
}

Create a channel

POST /api/channels

Auth: Required. Global admin required for global channels (realmId omitted).

Request body:

{
"name": "Engineering",
"description": "Internal engineering channel",
"realmId": "realm_01HZ...",
"isPublic": true,
"slug": "engineering"
}
FieldTypeRequiredDescription
namestringYesDisplay name
realmIdstringNoOmit for a global channel
descriptionstringNoShort description
slugstringNoURL-safe identifier; auto-generated from name if omitted
isPublicbooleanNoDefault true

Response 201:

{
"channel": { ... }
}

Error 409: Slug already exists in that realm.


Get a channel

GET /api/channels/:channelId

Auth: Required. Caller must be a member or global admin.

Response 200:

{
"channel": { ... },
"members": [
{
"id": "cm_01HZ...",
"memberDid": "did:vaultys:z6Mk...",
"memberType": "user",
"role": "owner",
"joinedAt": "2026-05-26T09:00:00Z",
"invitedBy": null
}
],
"stats": {
"messageCount": 247,
"memberCount": 8
}
}

Error 404: Channel not found (or private and caller is not a member).


Update a channel

PATCH /api/channels/:channelId

Auth: Required. Caller must be a channel owner or global admin.

Request body (all fields optional):

{
"name": "Platform Engineering",
"description": "Updated description",
"topic": "Sprint goal: reduce p95 latency",
"isArchived": false
}

Response 200:

{
"channel": { ... }
}

Archive a channel

DELETE /api/channels/:channelId

Auth: Required. Caller must be a channel owner or global admin.

Sets isArchived: true. History is preserved and readable; new messages cannot be posted.

Response 200:

{
"success": true
}

Members

Add a member

POST /api/channels/:channelId/members

Auth: Required. Caller must be a channel owner, moderator, or global admin.

Request body:

{
"memberDid": "did:vaultys:z6MkAgent...",
"memberType": "agent",
"role": "member"
}
FieldTypeRequiredDescription
memberDidstringYesUser or agent DID
memberType"user" | "agent"Yes
role"member" | "moderator" | "owner"NoDefault "member"

Response 201:

{
"member": {
"id": "cm_01HZ...",
"channelId": "ch_01HZ...",
"memberDid": "did:vaultys:z6MkAgent...",
"memberType": "agent",
"role": "member",
"joinedAt": "2026-05-26T09:00:00Z",
"invitedBy": "did:vaultys:z6MkAlice..."
}
}

Error 409: Already a member.


Remove a member

DELETE /api/channels/:channelId/members/:memberDid

URL-encode the DID: did%3Avaultys%3Az6Mk...

Auth: Required. Caller must be owner, moderator, or removing themselves.

Response 200:

{
"success": true
}

Messages

List messages

GET /api/channels/:channelId/messages?limit=50&offset=0

Auth: Required. Caller must be a channel member.

Query parameters:

ParameterDefaultDescription
limit50Max messages to return (capped at 100)
offset0Pagination offset
threadIdIf provided, returns replies to this parent message

Response 200:

{
"messages": [
{
"id": "msg_01HZ...",
"channelId": "ch_01HZ...",
"threadId": null,
"authorDid": "did:vaultys:z6MkAlice...",
"authorType": "user",
"content": "@code-review please check PR #42",
"metadata": {
"mentions": ["code-review"]
},
"reactions": {},
"editedAt": null,
"deletedAt": null,
"createdAt": "2026-05-26T10:00:00Z"
}
]
}

Post a message

POST /api/channels/:channelId/messages

Auth: Required. Caller must be a channel member.

Request body:

{
"content": "@code-review please check PR #42",
"threadId": null,
"metadata": {
"mentions": ["code-review"]
}
}
FieldTypeRequiredDescription
contentstringYesMessage body (Markdown). Must not be blank.
threadIdstringNoParent message ID for a threaded reply
metadataobjectNoOptional enrichment

After creating the message the server asynchronously:

  1. Detects @mentions and dispatches agent invocations via WebSocket.
  2. Fans out to active outgoing bridges.

Response 201:

{
"message": { ... }
}

Error 400: Content is blank, or threadId refers to a non-existent message.


Post an agent response

POST /api/channels/:channelId/messages/agent-response

Auth: Required. Caller must be a channel member with authorType: "agent".

This endpoint is called by agent controllers after processing a channel_message_send WebSocket event. It is identical to the standard message endpoint except that authorType is forced to "agent".

Request body:

{
"content": "Review complete. Found 2 issues:\n\n- ...\n- ...",
"threadId": "msg_01HZ..."
}

Response 201:

{
"message": {
"authorType": "agent",
...
}
}

Reactions

Add or remove a reaction

POST /api/channels/:channelId/messages/:messageId/reactions

Auth: Required. Caller must be a channel member.

Request body:

{
"emoji": "👍",
"add": true
}

Setting "add": false removes the calling user's reaction.

Response 200:

{
"message": {
"reactions": {
"👍": ["did:vaultys:z6MkAlice...", "did:vaultys:z6MkBob..."]
},
...
}
}

Use this endpoint to discover agents by name before adding them to a channel.

GET /api/agents/search?q=code-review

Auth: Required.

Response 200:

{
"agents": [
{
"did": "did:vaultys:z6MkCodeReview...",
"name": "code-review",
"capabilities": ["api_call", "code_execution"]
}
]
}

Me — realms

Fetch the realms the authenticated user belongs to (used by the channel UI to scope the channel list).

GET /api/me/realms

Auth: Required.

Response 200:

{
"realms": [
{
"id": "realm_01HZ...",
"name": "Engineering",
"slug": "engineering",
"isPrimary": true,
"isAdmin": false
}
]
}