Tenants & data model
The short version
Organisation (billing: plan, status)
└── Workspace = tenant (all your data)
├── API keys
├── End-users ──── Devices (push tokens)
├── Conversations ── Memberships (user + role)
│ ├── Messages ── Reactions, Attachments
│ └── Calls ── Participants
├── Webhooks ── Deliveries
├── Push credentials (APNs key, Firebase service account)
├── Settings (read receipts, call limits, notifications)
└── Audit log
- The organisation is what gets billed. It carries the plan and the subscription status.
- The workspace (called a tenant in the API) is the unit of data isolation. Every row poolse stores for you belongs to exactly one workspace, and nothing crosses between workspaces.
- An end-user is one of your application's users.
When you sign up in the dashboard you get one organisation with one workspace. The dashboard manages one workspace per account.
Organisation
Holds:
- Plan: no paid plan means the Free tier; a paid plan (today: Pro) lifts the quotas. See Limits & quotas and Billing.
- Subscription status: one of
active,trialing,past_due,canceled,suspended, or none (Free tier).canceledandsuspendedblock chargeable actions: sending messages, requesting upload URLs and creating webhooks. Reads keep working.
Workspace (tenant)
The workspace owns everything in the tree above. It also has its own data encryption key, which encrypts message bodies, webhook signing secrets and push credentials. See Encryption & retention.
Each workspace has an id (a UUID). You can copy it from
Account → Workspace → Workspace ID in the dashboard, or read it from
GET /v1/whoami.
Deleting the workspace deletes every row that belongs to it, including the audit log. See Danger zone.
End-user
An end-user is a user of your product, not a dashboard account. End-users have no password in poolse: your backend vouches for them by minting a token. See Authentication.
| Field | Type | Meaning |
|---|---|---|
id | UUID | poolse's id for the user. Needed to mint a token (POST /v1/users/:user_id/tokens). |
external_id | string, 1–255 chars | Your id for the user. Unique within the workspace. Required. |
display_name | string or null, up to 255 chars | Name shown in the UI components. |
avatar_url | string or null, up to 2048 chars | Avatar shown in the UI components. |
custom_data | object | Anything you want to attach. |
is_blocked | boolean | A blocked user's token is refused on REST and on the WebSocket, and their open sockets are closed when you block them. Blocked users don't count towards the user quota. |
The full shape is on Users.
Creating users
There are two ways a user comes to exist:
POST /v1/userswith your API key. This is an upsert keyed onexternal_id: it creates the user, or updates the existing one. Only the fields you send change; fields you leave out keep their value. You need the returnedidto mint a token.- Lazy provisioning. When a user creates a conversation or adds
members by
external_id, anyexternal_idpoolse hasn't seen yet is created on the spot with only itsexternal_id. This is capped at 50 new users per hour per caller; see Limits & quotas.
Both ways count towards your plan's end-user quota.
Conversations and memberships
A conversation is direct (between two people; creating a direct
conversation that already exists for the pair returns the existing one)
or group. Each member has a role:
owner, admin or member.
| Role | Can |
|---|---|
owner | Everything an admin can. |
admin | Update the conversation's fields, add and remove members. |
member | Read and send messages. |
There is no API to delete a conversation, and no API to transfer ownership. Details: Conversations & roles.
Messages
Messages belong to a conversation and have a per-conversation sequence
number. Their body is encrypted at rest. Deleting a message is a soft
delete: the row stays as a tombstone, the body is cleared and its
attachments are removed from storage. Details: Messages.
Attachments
An attachment's bytes are stored in poolse's object storage (Cloudflare
R2), or in your own S3-compatible bucket if you connect one
(Bring your own storage). poolse keeps the metadata (content type, size, filename) in its
database. An attachment starts as pending when you request an upload
URL and becomes ready when it is linked to a message. Pending
attachments that are never linked are removed after 24 hours. See
Attachment uploads.
Calls, devices and settings
- Calls and their participants are recorded per conversation. See Calls & rooms and Call history.
- Devices are the push tokens your apps register for a user. See Devices.
- Settings for read receipts, call limits and notifications are set per workspace in the dashboard: Messaging, Calls, Push.