Encryption & retention
This page lists exactly what poolse encrypts, what it does not, and how long it keeps things. Read it before you put sensitive data in messages.
How encryption works
Each workspace has its own 32-byte data encryption key (DEK), created with the workspace. The DEK is stored wrapped (encrypted) by a server master key with AES-256-GCM. Fields that are encrypted use AES-256-GCM under the workspace's DEK, with a fresh random 12-byte IV for every value.
poolse's servers hold the master key and decrypt these fields whenever they serve your API, realtime, webhook or push traffic. This is encryption at rest, not end-to-end encryption.
Encrypted with the workspace key
| Data | Notes |
|---|---|
Message body | Encrypted on send and on every edit. An edit overwrites the old body; no history is kept. |
| Webhook signing secrets | Decrypted on each delivery to sign it. |
| Push credentials | Your APNs .p8 key and Firebase service account JSON. Write-only: the dashboard never shows them again. |
| Storage credentials | The secret key of your own bucket, if you connect one. Write-only, like push credentials. |
Stored without application-level encryption
These are stored as plain values in the database or object storage.
| Data | Notes |
|---|---|
Conversation preview (last_message_preview) | The first 80 characters of the conversation's latest message, or "Attachment" / "N attachments" when it has no text. System messages (call records) are stored whole. Editing or deleting the latest message rewrites it. Returned on conversations in the API. |
| Webhook delivery payloads | The full event body, including message text and the preview field, kept for 30 days. See Retention. |
| Attachment files | Stored as uploaded in poolse's object storage (Cloudflare R2), or, with your own bucket connected, in your bucket under your provider's settings. poolse does not encrypt the bytes itself. |
| Attachment metadata | Content type, size, original filename, SHA-256. |
| Conversations | name, avatar_url, custom_data, settings. |
| End-users | external_id, display_name, avatar_url, custom_data. |
| Call records | Who called whom, when, how long, the outcome. |
| Audit log | Actions, actor and target ids, and metadata. Message text is not included. |
API key secrets are not stored at all: poolse keeps the key's prefix and an HMAC-SHA256 hash of the secret, made with a server-side pepper. That is why the dashboard shows a key only once.
In transit
The hosted API is served over HTTPS (https://api.poolse.dev), and the
SDK derives the WebSocket URL from it, so production traffic uses
wss://.
Who at poolse can see what
The poolse operator console shows metadata only: message counts, member lists and timestamps. It has no code path that decrypts a message body. That is a property of the console's code, not a cryptographic barrier: the same servers that decrypt bodies to serve your app hold the key.
Retention
| Data | Kept |
|---|---|
| Webhook deliveries (payload, your response status and body, error) | 30 days, removed by a daily sweep. Deleting a webhook deletes its deliveries straight away. |
| Pending attachments (upload URL requested, never sent in a message) | Removed after 24 hours. |
| Deleted messages | The row stays as a tombstone; the body is cleared and its attachments are removed from storage at once. |
| Everything else | Until you delete it, or delete the workspace. poolse does not expire messages, conversations, users, call records or audit log entries. |
There is no API to delete an end-user or a conversation. To stop a user,
block them (is_blocked: true on POST /v1/users).
Deleting a workspace
Deleting your workspace from the Danger zone removes, in this order: the attachment files from storage (best effort, one by one; with your own bucket connected, the files poolse wrote there under the key prefix), the workspace's audit log, then the workspace row. That cascades to every row that belongs to it, including the wrapped DEK, messages, users, conversations, API keys, webhooks and their deliveries, push credentials, devices and call records.
With the DEK gone, nothing in the live database can decrypt that workspace's message bodies any more. This page makes no statement about copies held in database backups.
What this means for you
- Keep your own copy of anything you must retain. Subscribe to
message.createdand store what you need when it happens. - Treat previews as message content.
last_message_preview, webhook payloads and push notifications all carry message text. - Don't put secrets in
custom_dataor names. They are not encrypted.