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). canceled and suspended block 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.

FieldTypeMeaning
idUUIDpoolse's id for the user. Needed to mint a token (POST /v1/users/:user_id/tokens).
external_idstring, 1–255 charsYour id for the user. Unique within the workspace. Required.
display_namestring or null, up to 255 charsName shown in the UI components.
avatar_urlstring or null, up to 2048 charsAvatar shown in the UI components.
custom_dataobjectAnything you want to attach.
is_blockedbooleanA 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:

  1. POST /v1/users with your API key. This is an upsert keyed on external_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 returned id to mint a token.
  2. Lazy provisioning. When a user creates a conversation or adds members by external_id, any external_id poolse hasn't seen yet is created on the spot with only its external_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.

RoleCan
ownerEverything an admin can.
adminUpdate the conversation's fields, add and remove members.
memberRead 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.
Tenants & data model · poolse docs