Send & Receive Messages
Send and receive end-to-end encrypted messages between the operator and the customer.
Message Directions
- Company → Contact: sent through the API, displayed in the customer's chat.
- Contact → Company: sent from the customer's chat, delivered via webhook.
All message content is end-to-end encrypted. The backend only stores and relays ciphertext — it never sees plaintext.
Send a Message (Company)
Send text messages with application/json or media messages with multipart/form-data. For media messages, the content field becomes the encrypted caption.
curl -X POST https://api.ixblix.app/api/messages/company \
-H "X-API-Key: smci_xxxx" \
-H "Content-Type: application/json" \
-d '{
"conversationId": "conv_xxxx",
"content": "<base64 AES-GCM ciphertext>",
"iv": "<base64>",
"authTag": "<base64>",
"encryptedKey": "<base64 RSA-OAEP wrapped AES key>",
"selfEncryptedKey": "<base64 RSA-OAEP wrapped AES key>",
"keyId": "<operator key id>"
}' curl -X POST https://api.ixblix.app/api/messages/company \
-H "X-API-Key: smci_xxxx" \
-F "conversationId=conv_xxxx" \
-F "content=<base64 AES-GCM caption>" \
-F "file=@encrypted_file.bin" \
-F "iv=<base64>" \
-F "authTag=<base64>" \
-F "encryptedKey=<base64>" \
-F "selfEncryptedKey=<base64>" \
-F "keyId=<operator key id>" Request Fields
| Field | Required | Description |
|---|---|---|
conversationId | Yes | ID of the conversation. |
content | Yes | Base64 AES-256-GCM ciphertext. |
iv | Yes | AES-GCM initialization vector (base64). |
authTag | Yes | AES-GCM authentication tag (base64). |
encryptedKey | Yes | AES key wrapped to customer's RSA public key. |
selfEncryptedKey | Yes | AES key wrapped to operator's own RSA public key. |
keyId | Yes | Identifier of the operator's public key. |
operatorUuid | Yes | UUID of the operator sending this message. Must be a valid UUID. |
replyToId | No | ID of the message this replies to. |
attachments | No | Encrypted JSON string with rich message attachments (buttons, vcard, location). The operator identity (name, image, gravatarHash) should be embedded in this JSON by the sender before encryption so the customer client can render the correct avatar per message. |
metadata | No | Opaque JSON object stored with the message. Use encryptedPushPayload to include an encrypted push notification preview (see below). The backend never inspects the contents. |
Send a Message (Contact)
curl -X POST https://api.ixblix.app/api/messages/contact \
-H "Content-Type: application/json" \
-d '{
"token": "abc123def456",
"content": "<base64 AES-GCM ciphertext>",
"iv": "<base64>",
"authTag": "<base64>",
"encryptedKey": "<base64>",
"selfEncryptedKey": "<base64>",
"keyId": "<customer key id>"
}' List Messages
curl https://api.ixblix.app/api/messages/{conversationId} \
-H "X-API-Key: smci_xxxx" Prefer webhooks over polling. SMCI pushes a MESSAGE_RECEIVED webhook whenever a contact sends a message.
Delivery and Read Receipts
Every message moves through three acknowledgement states: sent, delivered and read. read implies delivered — marking a message as read also records its delivery when it had not been delivered yet. Both timestamps are exposed on the message as deliveredAt and readAt.
Mark a customer message as delivered (operator side) as soon as your client receives it:
curl -X POST https://api.ixblix.app/api/messages/company/delivered \
-H "X-API-Key: smci_xxxx" \
-H "Content-Type: application/json" \
-d '{ "conversationId": "conv_xxxx", "messageId": "msg_xxxx" }' Mark a customer message as read (operator side) once the operator has actually seen it:
curl -X POST https://api.ixblix.app/api/messages/company/read \
-H "X-API-Key: smci_xxxx" \
-H "Content-Type: application/json" \
-d '{ "conversationId": "conv_xxxx", "messageId": "msg_xxxx" }' Only report a read when the chat window is focused and the message is visible in the viewport. Report delivery instead when the message is off-screen or the window is in the background — otherwise the customer sees a false read receipt.
On the customer side, ixblix pushes a MESSAGE_DELIVERED webhook when the customer's device receives your message and a MESSAGE_READ webhook when the customer actually sees it.
Reactions
Reactions are encrypted messages with contentType set to react and replyToId pointing to the target message. Send an empty content to clear a reaction.
Push Notification Previews
When the customer has push notifications enabled, the customer's device shows a notification for each new company message. By default the notification shows a generic "New message" text. To show the actual message content, include an encryptedPushPayload in the message metadata.
The preview is a small JSON object encrypted with the customer's RSA public key (RSA-OAEP/SHA-256):
{
"text": "Hello, how can I help?",
"senderName": "Support Agent",
"thumbnailBase64": "/9j/4AAQ..." // optional, for media messages
} Encrypt the preview and include it in the message metadata:
{
"conversationId": "conv_xxxx",
"content": "<base64 AES-GCM ciphertext>",
"iv": "<base64>",
"authTag": "<base64>",
"encryptedKey": "<base64>",
"selfEncryptedKey": "<base64>",
"keyId": "<operator key id>",
"metadata": {
"encryptedPushPayload": "<base64 RSA-OAEP ciphertext of the preview JSON>"
}
} The backend never sees the push preview plaintext. It only relays the opaque ciphertext to the customer's device, which decrypts it with its private key.
SDK Helper
The SDK provides encryptPushPreview() to encrypt the preview JSON, and sendEncryptedMessage() accepts a pushPreview option that automatically generates and includes the encrypted payload:
await client.sendEncryptedMessage(conversationId, {
content: "Hello, how can I help?",
operatorIdentity: { uuid: "op-1", name: "Support Agent" },
pushPreview: {
text: "Hello, how can I help?",
senderName: "Support Agent",
},
});