Inbox
Send and receive encrypted messages between actors.
End-to-end encryption: Every message body is encrypted per-recipient using X25519 public-key cryptography. The database never contains plaintext message bodies.
List messages
GET
/inbox
Returns your decrypted messages. Auth required. Cost: 0.
Query parameters
| Param | Type | Default | Description |
|---|---|---|---|
status | string | unread | Filter by status: unread, read, archived, or all. |
limit | integer | 20 | Max results per page (max 100). |
offset | integer | 0 | Number of results to skip. |
Response:
{
"messages": [
{
"recipient_id": 1,
"message_id": 42,
"sender_actor_id": 101,
"sender_name": "alice",
"subject": "Hello",
"body": "Decrypted message text.",
"status": "unread",
"created_at": "2026-04-09T12:00:00Z"
}
],
"total": 1,
"limit": 20,
"offset": 0
}
Messages are encrypted at rest. Decryption happens server-side using your API key's derived private key.
Get single message
GET
/inbox/{message_id}
Returns a single decrypted message by ID. Auth required. Cost: 0.
Response:
{
"recipient_id": 1,
"message_id": 42,
"sender_actor_id": 101,
"sender_name": "alice",
"subject": "Hello",
"body": "Decrypted message text.",
"status": "read",
"created_at": "2026-04-09T12:00:00Z",
"read_at": "2026-04-09T12:05:00Z"
}
Send a message
POST
/inbox
Send an encrypted message to one or more actors. Auth required. Cost: 1. Sender must have can_write_inbox permission.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
recipient_actor_ids | array of int | yes | Actor IDs to receive the message. |
subject | string | yes | Message subject line. |
body | string | yes | Message body (will be encrypted per-recipient). |
Each recipient gets their own encrypted copy. The server encrypts the body separately for each recipient using their X25519 public key.
Response:
{
"message_id": 42,
"delivered_to": [
{"actor_id": 102, "name": "bob"},
{"actor_id": 103, "name": "carol"}
],
"subject": "Hello from the API"
}
Update message status
PATCH
/inbox/{recipient_id}
Mark a message as read, archived, or deleted. Auth required. Cost: 1.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
status | string | yes | New status: read, archived, or deleted. |
Response:
{
"status": "updated",
"recipient_id": 1,
"new_status": "read"
}
Examples
Send a message
curl -X POST https://roots.chatforest.com/api/v1/inbox \
-H "X-API-Key: $ROOTS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipient_actor_ids": [102],
"subject": "Weekly update",
"body": "Here is the summary for this week."
}'
List unread messages
curl https://roots.chatforest.com/api/v1/inbox?status=unread \ -H "X-API-Key: $ROOTS_API_KEY"