Search the complete documentation

Try idempotency, proposal lifecycle, authentication, or ordering.

Navigate Open
繁體中文
Browse documentation

Relay · Channels

Channels, membership, and permissions

Relay provides a small transport permission model. It isolates tenants, requires membership for conversation writes, and leaves business authorization to the host.

The current read policy is broader than the write policy. Treat the matrix below as the public behavior, not as a private-channel RBAC system.

Create a channel

Any authenticated tenant user can create a channel:

POST /api/channels
Authorization: Bearer <jwt>
Content-Type: application/json

{
  "metadata": {
    "name": "support"
  }
}

Relay returns 201 Created and automatically creates a membership for the user who created the channel.

Channel metadata is host-defined JSON with a maximum encoded size of 4096 bytes. Relay stores it but does not assign business meaning to its keys.

Current permission matrix

OperationCurrent requirement
List channels in the tenantAny authenticated user in that tenant
Get a channelAny authenticated user in that tenant
List channel membersAny authenticated user in that tenant
Join the WebSocket topicChannel member
Send a messageChannel member and open channel
List messagesNon-members currently receive an empty list, not 403
Add a memberExisting channel member
Remove a membershipThe user may remove only their own membership
Close a channelChannel member
Change channel metadataChannel agent member or tenant admin
Mute notification eventsThe current member only

The three tenant-wide read operations are not filtered by channel membership. Do not treat channel existence, metadata, or member lists as confidential between users who hold tokens for the same tenant.

The empty-list behavior for non-member message reads comes from the current policy filter. It is not a strong authorization signal and may be tightened in a future contract.

Add a member

An existing member can add another host user by user_id:

POST /api/channels/{channel_id}/members
Authorization: Bearer <jwt>
Content-Type: application/json

{
  "user_id": "user-uuid"
}

A new membership returns 201 Created. Adding the same user twice returns a 422 validation response because (channel_id, user_id) is unique.

The endpoint does not evaluate host roles, teams, subscriptions, or case ownership. The host must decide whether a user should be added before making this request.

Leave a channel

The delete endpoint accepts a membership ID, not a user ID:

DELETE /api/channels/{channel_id}/members/{member_id}
Authorization: Bearer <jwt>

A user can delete only their own membership. Success returns 204 No Content. Attempting to remove another user’s membership returns 403; an unknown membership returns 404.

There is no member or moderator endpoint for removing another member. Tenant-wide user offboarding exists on the admin surface, but it is not channel moderation.

Close a channel

Any member can close an open channel:

POST /api/channels/{channel_id}/close
Authorization: Bearer <jwt>

Close is idempotent. Repeating the request returns the already closed channel without changing the original closed_at value.

A closed channel keeps its history but rejects new messages with a 422 validation response. The current public API has no reopen or channel delete endpoint.

Change metadata

Ordinary user members cannot change channel metadata. A channel member whose kind is agent, or a tenant admin, can use either operation:

PATCH /api/channels/{channel_id}/metadata
PUT /api/channels/{channel_id}/metadata

PATCH performs a shallow merge of top-level keys. Nested maps are replaced, not deep-merged. PUT replaces the complete metadata map. Invalid or oversized metadata returns 422.

Admin requests must identify the tenant explicitly. Agent requests derive the tenant from the signed token and still require channel membership.

Mute notification events

The current member can mute or unmute Relay-generated notification webhook events:

POST /api/channels/{channel_id}/notification_mute
DELETE /api/channels/{channel_id}/notification_mute

Mute changes member.muted_at. It does not block message reads, writes, or WebSocket fan-out. Relay does not decide whether the host sends email, mobile push, or an in-product badge.

Product boundary

Relay enforces tenant isolation and coarse conversation membership. The host owns business roles and the decision to create a channel, add a member, or expose a Relay token.

Private channel discovery, owner or moderator roles, removing other members, and reopening a channel are not present in the current tenant API. Products that need those guarantees require additional Relay contract work; naming a host role in channel metadata does not create authorization.

Next: upload and bind attachments.