> ## Documentation Index
> Fetch the complete documentation index at: https://developers.workchats.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Concepts

> Apps, installations, bot users, tokens and scopes

## App

An App is your integration, registered once with Octogle: a name, a
`client_id` and `client_secret`, a redirect URI, and (from Phase 1b) a
callback URL and signing secret. One App can be installed into many
companies.

## Installation

A company installs your App by approving it through the OAuth consent
screen. That creates one installation per `(App, company)` pair, which owns:

* one **bot user** in that company
* one bot token, scoped to that company only

An installation moves between three states: `active`, `disconnected` (your
App called `POST /oauth/revoke`), and `uninstalled` (the company or Octogle
removed it). Reconnecting reactivates the same installation, the same bot
user, and issues a new token.

## Bot user

Your App's bot is a real user in the company, with a display name (your
App's name) and avatar (your App's icon). It can:

* be a member of groups and channels, and post in the ones it's a member of
* receive and send direct messages to people, subject to
  [who a bot may DM](/guides/oauth-install#who-your-bot-can-message)

It cannot log in, appear in search or the company directory, be @mentioned
into a notification, or join a call.

## Tokens and scopes

Your bot token doesn't expire and isn't refreshed — see
[OAuth install](/guides/oauth-install). It's scoped to exactly what the
company admin approved:

| Scope | Grants |
| - | - |
| `users:read` | List and read people, without email |
| `users:read.email` | Adds email (subject to each person's visibility setting), and `GET /v1/users/lookup` |
| `conversations:read` | List the groups and channels your bot is a member of |
| `conversations:history` | Read message history your bot can see |
| `files:read` | File metadata and a download link, through a message your bot can see |
| `messages:write` | Send, edit and delete your bot's own messages |

Full list on the [Scopes](/reference/scopes) page.

## IDs

Every id is an opaque, prefixed string. The prefix tells you what it is, but
it isn't a secret and every lookup is still scoped to your installation's
company:

| Prefix | What |
| - | - |
| `usr_` | A user |
| `grp_` | A group (its main conversation) |
| `chn_` | A named channel inside a group |
| `dm_` | A direct-message conversation between your bot and a person |
| `gmsg_` | A message in a group or channel |
| `dmsg_` | A message in a direct message |
| `fil_` | A file attached to a message |
| `cmp_` | A company (the `workspace.id` from `/v1/auth/test`) |

Store ids as opaque strings. Don't parse them.

## The response envelope

Every success is resource-keyed:

```json theme={null}
{ "ok": true, "message": { "…" } }
{ "ok": true, "users": ["…"], "next_cursor": "…" }
```

Every non-2xx response has the same shape:

```json theme={null}
{ "ok": false, "error": { "code": "conversation_not_found", "message": "…" }, "request_id": "…" }
```

`code` is stable and machine-readable — branch on it, not on `message`. New
codes can appear over time (the API is additive-only within `/v1`); treat an
unknown one as a generic failure rather than crashing. Full list on
[Errors](/guides/errors).

## Lists are cursor-paginated

`GET /v1/users`, `GET /v1/conversations`, and
`GET /v1/conversations/{conversation_id}/messages` take `limit` (default
200, max 1000) and `cursor`, and return `next_cursor`, which is `null` on
the last page. Details on [Pagination](/guides/pagination).
