Skip to content

Machine scopes

Your backend calls Chat with a backend client and a machine token. Its scopes decide which Chat permissions it holds, through a fixed mapping. This page lists the mapping, what a machine can never do, and how it acts for one of your users.

chat:sync is the scope for a trusted backend. The granular scopes let you give a client less.

Scope Chat permissions it carries
chat:sync conversations.create, conversations.read, conversations.update, groups.create, groups.manage, channels.create, channels.manage, messages.send, messages.read, users.lookup
chat:conversations.read conversations.read, messages.read
chat:conversations.manage conversations.create, conversations.update
chat:groups.manage groups.create, groups.manage
chat:channels.manage channels.create, channels.manage
chat:messages.send messages.send
chat:users.lookup users.lookup

Creating a GROUP or a CHANNEL needs two scopes: chat:conversations.manage for creating a conversation at all, plus chat:groups.manage or chat:channels.manage for the type.

A client with only chat:messages.send can send but cannot read. Give it chat:conversations.read too if it must list messages.

Some permissions are never granted to a machine, whatever its scopes:

  • messages.delete
  • users.lookup.directory
  • administration.read and administration.manage

No scope carries conversations.delete or messages.update either, so your backend archives conversations instead of deleting them, and does not edit messages.

Some routes act as a signed-in person, so a machine token cannot use them:

What What a machine gets
Reactions, read state, typing 400 user_required
Realtime token, presence, push devices, Chat Administration 403 principal_not_allowed

A machine token works only in the tenant and application its client is registered for. Any other context answers 403 client_context_mismatch. One backend client serves one application.

Machine clients are rate limited per client: 600 requests per 60 s per client. See Limits.

A machine token has no user. When your backend does something that belongs to a person, it names them with actor_user_id:

{ "type": "DIRECT", "member_user_ids": ["coach-ana", "client-john"], "actor_user_id": "coach-ana" }

How it works:

  • Create. The actor is recorded as the creator, and as OWNER of a GROUP or CHANNEL. A machine must always send member_user_ids, and a DIRECT conversation has exactly two members including the actor.
  • Send. The message is stored with the actor as sender_user_id and your client as sender_client_id, so your backend’s messages can be told apart from the user’s own. The actor must be a member of the conversation, or the call fails with 422 actor_not_member.
  • Eligible users. Every user you name must be an active tenant member with access to your application, or the call fails with 422 target_user_not_eligible.
  • A user token that sends actor_user_id has it ignored.

A SYSTEM message has message_type: SYSTEM and no sender. Your backend sends one with message_type: SYSTEM and no actor_user_id, for example “Coaching has ended”. It still carries your sender_client_id.

Only a machine may send one. A user who tries gets 403 system_message_not_allowed.

Chat permission: messages.sendMachine scope (any of): chat:messages.send

OAuth access and Chat permissions are different layers. A scope opens the API to a client. The Chat permissions inside a context decide what a user may do. Your machine client never uses the role mapping that your users’ roles use, so you do not grant it permissions in Chat Administration.