Beeper Messages API
Messages inside a Chat: list, search, send, retrieve, edit, delete, and react.
Messages inside a Chat: list, search, send, retrieve, edit, delete, and react.
openapi: 3.1.0
info:
title: Beeper Desktop Accounts Messages API
version: 5.0.0
description: 'Beeper Desktop''s local HTTP and WebSocket API. One auth flow and one chat shape work across WhatsApp, iMessage, Telegram, Slack, Matrix, Discord, Twitter/X, Signal, and more.
Beeper is built on the Matrix standard. Identifiers and rich text use Matrix conventions: `mxc://` and `localmxc://` URLs reference media on the Matrix homeserver and on this device''s local bridge respectively; message text is Matrix HTML on the wire; `@room` is a group-mention sentinel.
## Quickstart
1. Discover the server with `GET /v1/info`. The Desktop API is local-only unless the user has enabled remote access.
2. Authenticate with an access token from Beeper Desktop, or run OAuth2 Authorization Code with PKCE under the OAuth tag.
3. Call `GET /v1/accounts` to see connected Chat Accounts, then `GET /v1/chats` for the unified inbox.
## WebSocket
Connect to `/v1/ws` with the same Bearer token in the upgrade request. Browser `new WebSocket()` clients are not supported yet because browsers cannot set the Authorization header. After the server sends `ready`, send `{"type":"subscriptions.set","chatIDs":["*"]}` to receive every chat update, or pass specific chat IDs. The server replies with `subscriptions.updated`, then streams `chat.upserted`, `chat.deleted`, `message.upserted`, and `message.deleted`.
Delivery is at-most-once. There is no replay on reconnect, and `seq` is per connection. Refetch via HTTP after a disconnect to reconcile drift. Initial subscription state is empty; `subscriptions.set` replaces previous state; `["*"]` cannot be combined with specific chat IDs.
## Conventions
- IDs and cursors are opaque strings.
- Timestamps are ISO 8601 with timezone, except OAuth fields that use Unix seconds per RFC.
- Pagination is `cursor` plus `direction=before|after`.
- Sends return a `pendingMessageID`; resolve it with `GET /v1/chats/{chatID}/messages/{messageID}` or wait for `message.upserted` over the WebSocket.
- Optional fields may be omitted when unknown. Nullable write fields use `null` as an explicit clear operation.
- Every response carries `X-Beeper-Desktop-Version` so clients can tell which app version produced it.'
termsOfService: https://www.beeper.com/terms
contact:
name: Beeper
email: help@beeper.com
url: https://www.beeper.com
license:
name: Proprietary
url: https://www.beeper.com/terms
servers:
- url: http://localhost:23373
description: Beeper Desktop API server
security:
- bearerAuth: []
tags:
- name: Messages
description: 'Messages inside a Chat: list, search, send, retrieve, edit, delete, and react.'
paths:
/v1/messages/search:
get:
summary: Search messages
description: Search messages across chats.
tags:
- Messages
operationId: searchMessages
security:
- bearerAuth: []
parameters:
- schema:
type: string
minLength: 0
description: 'Literal word search (non-semantic). Finds messages containing these EXACT words in any order. Use single words users actually type, not concepts or phrases. Example: use "dinner" not "dinner plans", use "sick" not "health issues". If omitted, returns results filtered only by other parameters.'
example: dinner
required: false
description: 'Literal word search (non-semantic). Finds messages containing these EXACT words in any order. Use single words users actually type, not concepts or phrases. Example: use "dinner" not "dinner plans", use "sick" not "health issues". If omitted, returns results filtered only by other parameters.'
name: query
in: query
- schema:
type: string
description: Opaque pagination cursor; do not inspect. Use together with 'direction'.
example: 1725489123456|c29tZUltc2dQYWdl
x-stainless-pagination-property:
purpose: next_cursor_param
required: false
description: Opaque pagination cursor; do not inspect. Use together with 'direction'.
name: cursor
in: query
- schema:
type: string
enum:
- after
- before
description: 'Pagination direction used with ''cursor'': ''before'' fetches older results, ''after'' fetches newer results. Defaults to ''before'' when only ''cursor'' is provided.'
example: before
required: false
description: 'Pagination direction used with ''cursor'': ''before'' fetches older results, ''after'' fetches newer results. Defaults to ''before'' when only ''cursor'' is provided.'
name: direction
in: query
- schema:
type: array
items:
type: string
description: Limit search to specific chat IDs.
example:
- '!NCdzlIaMjZUmvmvyHU:beeper.com'
- '1231073'
required: false
description: Limit search to specific chat IDs.
name: chatIDs
in: query
- schema:
type: array
items:
type: string
description: Account ID this resource belongs to.
description: Limit search to specific account IDs.
example:
- matrix
- discordgo
- local-whatsapp_ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc
required: false
description: Limit search to specific account IDs.
name: accountIDs
in: query
- schema:
type: string
enum:
- group
- single
description: 'Filter by chat type: ''group'' for group chats, ''single'' for 1:1 chats.'
required: false
description: 'Filter by chat type: ''group'' for group chats, ''single'' for 1:1 chats.'
name: chatType
in: query
- schema:
type: array
items:
type: string
enum:
- any
- video
- image
- link
- file
description: Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering.
required: false
description: Filter messages by media types. Use ['any'] for any media type, or specify exact types like ['video', 'image']. Omit for no media filtering.
name: mediaTypes
in: query
- schema:
type: string
description: 'Filter by sender: ''me'' (messages sent by the authenticated user), ''others'' (messages sent by others), or a specific user ID string (user.id).'
required: false
description: 'Filter by sender: ''me'' (messages sent by the authenticated user), ''others'' (messages sent by others), or a specific user ID string (user.id).'
name: sender
in: query
- schema:
type: string
format: date-time
description: Only include messages with timestamp strictly after this ISO 8601 datetime (e.g., '2024-07-01T00:00:00Z' or '2024-07-01T00:00:00+02:00').
example: '2025-08-01T00:00:00Z'
required: false
description: Only include messages with timestamp strictly after this ISO 8601 datetime (e.g., '2024-07-01T00:00:00Z' or '2024-07-01T00:00:00+02:00').
name: dateAfter
in: query
- schema:
type: string
format: date-time
description: Only include messages with timestamp strictly before this ISO 8601 datetime (e.g., '2024-07-31T23:59:59Z' or '2024-07-31T23:59:59+02:00').
example: '2025-08-31T23:59:59Z'
required: false
description: Only include messages with timestamp strictly before this ISO 8601 datetime (e.g., '2024-07-31T23:59:59Z' or '2024-07-31T23:59:59+02:00').
name: dateBefore
in: query
- schema:
type: integer
minimum: 0
exclusiveMinimum: true
maximum: 20
default: 20
description: Maximum number of messages to return.
example: 20
required: false
description: Maximum number of messages to return.
name: limit
in: query
- schema:
type: boolean
nullable: true
default: true
description: 'Exclude messages marked Low Priority by the user. Default: true. Set to false to include all.'
required: false
description: 'Exclude messages marked Low Priority by the user. Default: true. Set to false to include all.'
name: excludeLowPriority
in: query
- schema:
type: boolean
nullable: true
default: true
description: 'Include messages in chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.'
required: false
description: 'Include messages in chats marked as Muted by the user, which are usually less important. Default: true. Set to false if the user wants a more refined search.'
name: includeMuted
in: query
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/SearchMessagesOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
/v1/chats/{chatID}/messages:
get:
summary: List messages
description: List all messages in a chat with cursor-based pagination. Sorted by timestamp.
tags:
- Messages
operationId: listMessages
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Opaque pagination cursor; do not inspect. Use together with 'direction'.
example: 1725489123456|c29tZUltc2dQYWdl
x-stainless-pagination-property:
purpose: next_cursor_param
required: false
description: Opaque pagination cursor; do not inspect. Use together with 'direction'.
name: cursor
in: query
- schema:
type: string
enum:
- after
- before
description: 'Pagination direction used with ''cursor'': ''before'' fetches older results, ''after'' fetches newer results. Defaults to ''before'' when only ''cursor'' is provided.'
example: before
required: false
description: 'Pagination direction used with ''cursor'': ''before'' fetches older results, ''after'' fetches newer results. Defaults to ''before'' when only ''cursor'' is provided.'
name: direction
in: query
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/ListMessagesOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
post:
summary: Send a message
description: Send a text message to a specific chat. Supports replying to existing messages. Returns a pending message ID.
tags:
- Messages
operationId: sendMessage
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
text:
allOf:
- $ref: '#/components/schemas/MessageTextInput'
- description: Text input. Markdown is converted to Matrix HTML. To provide Matrix HTML verbatim, pass a JSON-stringified HTML string.
replyToMessageID:
type: string
description: Provide a message ID to send this as a reply to an existing message
attachment:
allOf:
- $ref: '#/components/schemas/MessageAttachmentInput'
- description: Single attachment to send with the message
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/SendMessageOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
/v1/chats/{chatID}/messages/{messageID}:
get:
summary: Retrieve a message
description: Retrieve a message by final message ID, pendingMessageID, or Matrix event ID. Chat ID may be a Beeper chat ID or local chat ID.
tags:
- Messages
operationId: getMessage
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Message ID.
example: '1343993'
required: true
description: Message ID.
name: messageID
in: path
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/Message'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
put:
summary: Edit a message
description: Edit the text content of an existing message. Messages with attachments cannot be edited.
tags:
- Messages
operationId: editMessage
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Message ID.
example: '1343993'
required: true
description: Message ID.
name: messageID
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
text:
type: string
minLength: 1
description: New text content for the message
required:
- text
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/EditMessageOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
delete:
summary: Delete a message
description: Delete a message by final message ID. Pending message IDs are not accepted because messages cannot be deleted while sending.
tags:
- Messages
operationId: deleteMessage
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Message ID.
example: '1343993'
required: true
description: Message ID.
name: messageID
in: path
- schema:
type: boolean
nullable: true
default: true
description: True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported.
required: false
description: True to request deletion for everyone when the network supports it; false to delete only for the authenticated user when supported.
name: forEveryone
in: query
responses:
'204':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
/v1/chats/{chatID}/messages/{messageID}/reactions:
post:
summary: Add a reaction
description: Add a reaction to an existing message.
tags:
- Messages
operationId: addReaction
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Message ID.
example: '1343993'
required: true
description: Message ID.
name: messageID
in: path
requestBody:
content:
application/json:
schema:
type: object
properties:
reactionKey:
type: string
minLength: 1
description: Reaction key to add (emoji, shortcode, or custom emoji key)
transactionID:
type: string
description: Optional transaction ID for deduplication and send tracking
required:
- reactionKey
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/AddReactionOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
/v1/chats/{chatID}/messages/{messageID}/reactions/{reactionKey}:
delete:
summary: Remove a reaction
description: Remove the reaction added by the authenticated user from an existing message.
tags:
- Messages
operationId: removeReaction
security:
- bearerAuth: []
parameters:
- schema:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
required: true
description: Chat ID or local chat ID.
name: chatID
in: path
- schema:
type: string
description: Message ID.
example: '1343993'
required: true
description: Message ID.
name: messageID
in: path
- schema:
type: string
minLength: 1
description: Reaction key to remove (emoji, shortcode, or custom emoji key)
required: true
description: Reaction key to remove (emoji, shortcode, or custom emoji key)
name: reactionKey
in: path
responses:
'200':
description: Request executed successfully
headers:
X-Beeper-Desktop-Version:
$ref: '#/components/headers/X-Beeper-Desktop-Version'
content:
application/json:
schema:
$ref: '#/components/schemas/RemoveReactionOutput'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/UnauthorizedError'
'403':
$ref: '#/components/responses/ForbiddenError'
'404':
$ref: '#/components/responses/NotFound'
'422':
$ref: '#/components/responses/UnprocessableEntity'
'429':
$ref: '#/components/responses/TooManyRequests'
'500':
$ref: '#/components/responses/InternalServerError'
components:
schemas:
Message:
type: object
properties:
id:
type: string
description: Message ID.
example: '1343993'
chatID:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
accountID:
type: string
description: Beeper account ID the message belongs to.
senderID:
type: string
description: Matrix-style fully-qualified sender user ID, usually including a bridge prefix and homeserver.
example: '@kishanbagaria:local-whatsapp.localhost'
senderName:
type: string
description: Resolved sender display name (impersonator/full name/username/participant name).
timestamp:
type: string
format: date-time
description: Message timestamp.
example: '2025-08-31T23:30:12.520Z'
sortKey:
type: string
description: A unique, sortable key used to sort messages.
example: '821744079'
type:
type: string
enum:
- TEXT
- NOTICE
- IMAGE
- VIDEO
- VOICE
- AUDIO
- FILE
- STICKER
- LOCATION
- REACTION
description: Message content type. Useful for distinguishing reactions, media messages, and state events from regular text messages.
text:
type: string
description: Matrix HTML body if present.
editedTimestamp:
type: string
format: date-time
description: Timestamp when the message was edited, if known.
example: '2025-08-31T23:30:12.520Z'
isSender:
type: boolean
description: True if the authenticated user sent the message.
sendStatus:
$ref: '#/components/schemas/SendStatus'
isHidden:
type: boolean
description: True if the message is hidden from normal display.
isDeleted:
type: boolean
description: True if the message has been deleted.
attachments:
type: array
items:
$ref: '#/components/schemas/Attachment'
description: Attachments included with this message, if any.
isUnread:
type: boolean
description: True if the message is unread for the authenticated user. May be omitted.
linkedMessageID:
type: string
description: ID of the message this is a reply to, if any.
example: '1343993'
mentions:
type: array
nullable: true
items:
type: string
description: Mentioned user IDs, @room, or null for legacy messages that require text scanning.
links:
type: array
items:
$ref: '#/components/schemas/LinkPreview'
description: Link previews included with this message, if any.
reactions:
type: array
items:
$ref: '#/components/schemas/Reaction'
description: Reactions to the message, if any.
seen:
$ref: '#/components/schemas/MessageSeen'
required:
- id
- chatID
- accountID
- senderID
- timestamp
- sortKey
example:
id: '241392'
sortKey: '455171049984'
chatID: '!discord_109876543210987654:beeper.com'
accountID: discordgo
senderID: '@discord_221590782384013314:beeper.com'
senderName: Kishan Bagaria
timestamp: '2026-05-05T20:20:12.497Z'
type: TEXT
text: The OAuth fix is deployed. Can you verify the desktop flow?
isSender: false
isDeleted: false
mentions:
- '@discord_337451892017545216:beeper.com'
isUnread: false
AddReactionOutput:
type: object
properties:
success:
type: boolean
enum:
- true
description: Always true. Indicates the reaction was queued; failures return an error response.
x-stainless-const: true
chatID:
type: string
description: Chat ID. Input routes also accept the local chat ID from this Beeper Desktop installation when available.
example: '!NCdzlIaMjZUmvmvyHU:beeper.com'
messageID:
type: string
description: Message ID.
example: '1343993'
reactionKey:
type: string
description: Reaction key that was added.
transactionID:
type: string
description: Transaction ID used for send tracking.
required:
- success
- chatID
- messageID
- reactionKey
- transactionID
example:
success: true
chatID: '!whatsapp_15550101002:ba_EvYDBBsZbRQAy3UOSWqG0LuTVkc.local-whatsapp.localhost'
messageID: '1343993'
reactionKey: ❤️
transactionID: txn_v3a8f4c9d2e1
User:
type: object
properties:
id:
type: string
description: Stable Beeper user ID. Use as the primary key when referencing a person.
username:
type: string
description: Human-readable handle if available (e.g., '@alice'). May be network-specific and not globally unique.
phoneNumber:
type: string
description: User's phone number in E.164 format (e.g., '+14155552671'). Omit if unknown.
email:
type: string
description: Email address if known. Not guaranteed verified.
fullName:
type: string
description: Display name as shown in clients (e.g., 'Alice Example'). May include emojis.
imgURL:
type: string
description: Avatar image URL if available. This may be a remote URL, Matrix media URL, data URL, or local filesystem URL depending on source and endpoint. May be temporary or local-only to this device; download promptly if durable access is needed.
cannotMessage:
type: boolean
description: True if Beeper cannot initiate messages to this user (e.g., blocked, network restriction, or no DM path). The user may still message you.
isSelf:
type: boolean
description: True if this user represents the authenticated account's own identity.
required:
- id
description: User the account belongs to.
LinkPreview:
type: object
properties:
url:
type: string
description: Resolved link URL.
originalURL:
type: string
description: Original URL when the displayed URL is shortened or redirected.
favicon:
type: string
description: Favicon URL if available. May be temporary or local-only to this device; download promptly if durable access is needed.
img:
type: string
description: Preview image URL if available. May be temporary or local-only to this device; download promptly if durable access is needed.
imgSize:
type: object
properties:
width:
type: number
height:
type: number
description: Preview image dimensions.
title:
type: string
description: Link preview title.
summary:
type: string
description: Link preview summary.
required:
- url
- title
description: Link preview included with a message.
AttachmentCapabilities:
type: object
properties:
mimeTypes:
type: object
additionalProperties:
$ref: '#/components/schemas/CapabilitySupportLevel'
description: Supported MIME types or MIME patterns for this file message type. Missing MIME types should be treated as rejected.
caption:
$ref: '#/components/schemas/CapabilitySupportLevel'
maxCaptionLength:
type: integer
description: Maximum caption length when captio
# --- truncated at 32 KB (65 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/beeper/refs/heads/main/openapi/beeper-messages-api-openapi.yml