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

ParamTypeDefaultDescription
statusstringunreadFilter by status: unread, read, archived, or all.
limitinteger20Max results per page (max 100).
offsetinteger0Number 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

FieldTypeRequiredDescription
recipient_actor_idsarray of intyesActor IDs to receive the message.
subjectstringyesMessage subject line.
bodystringyesMessage 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

FieldTypeRequiredDescription
statusstringyesNew 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"