KasarKasar Docs
API Reference

Inbox

Read interaction threads (email, LinkedIn, WhatsApp) and individual interactions from synced accounts.

The inbox endpoints let you read interaction threads from accounts synced to Kasar. Visibility mirrors the app exactly: each user only sees threads they own. Email/meeting threads are owned via the syncing email account; LinkedIn/WhatsApp/Telegram threads are owned via the thread's managing workspace user. The API never returns threads the caller does not own.

List Threads

GET /api/v1/inbox/threads

Returns a paginated list of interaction threads the authenticated user owns. Without a channel filter, the response combines owned email/meeting threads and owned non-email (LinkedIn/WhatsApp/Telegram) threads.

Query Parameters

ParameterTypeDefaultDescription
channelstringFilter by channel (e.g. email, meeting, linkedin, whatsapp, telegram)
sort_bystringlast_message_dateThread column to sort by
sort_dirstringdescSort direction: asc or desc
cursorstringPagination cursor from a previous response
limitinteger20Number of threads per page (max 100)

Interaction threads have no read-state column, so there is no is_read query parameter and threads do not carry a read flag.

Example Request

curl -X GET "https://kasar.app/api/v1/inbox/threads?channel=email&limit=25" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..."

Response

Each item is a raw interaction_threads row.

{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "subject": "Q2 Partnership Proposal",
      "channel": "email",
      "last_message_date": "2025-03-12T16:45:00Z",
      "message_count": 4,
      "summary": "Discussion about the revised Q2 proposal.",
      "content_visibility": "metadata_subject",
      "managed_by_workspace_user_id": null,
      "external_thread_id": "thread-xyz"
    }
  ],
  "total": 142,
  "nextCursor": "eyJvZmZzZXQiOjI1LCJsaW1pdCI6MjV9"
}

When nextCursor is absent, there are no further pages.

User isolation is enforced at the SQL level. The list only contains threads the caller owns — email/meeting threads owned via the syncing account, and non-email threads owned via managed_by_workspace_user_id.

Get Thread with Messages

GET /api/v1/inbox/threads/{id}

Returns a single thread along with its messages, paginated separately. The caller must own the thread; otherwise a RECORD_NOT_FOUND error is returned. Message bodies are decrypted (the owner sees them exactly as in the app).

Path Parameters

ParameterTypeDescription
idUUIDThe thread ID

Query Parameters

ParameterTypeDefaultDescription
message_cursorstringCursor for paginating messages within the thread
message_limitinteger50Number of messages to return (max 200)

Example Request

curl -X GET "https://kasar.app/api/v1/inbox/threads/a1b2c3d4-...?message_limit=20" \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..."

Response

thread is the raw interaction_threads row; each item in messages is a raw interactions row with decrypted body fields.

{
  "thread": {
    "id": "a1b2c3d4-...",
    "subject": "Q2 Partnership Proposal",
    "channel": "email",
    "last_message_date": "2025-03-12T16:45:00Z",
    "message_count": 4,
    "content_visibility": "metadata_subject"
  },
  "messages": [
    {
      "id": "e5f6a7b8-...",
      "subject": "Q2 Partnership Proposal",
      "direction": "outbound",
      "date": "2025-03-12T16:45:00Z",
      "content": "Hi Bob, here is the revised proposal...",
      "content_html": "<p>Hi Bob, here is the revised proposal...</p>",
      "content_text": "Hi Bob, here is the revised proposal...",
      "participants": ["alice@example.com", "bob@acme.com"],
      "interaction_thread_id": "a1b2c3d4-..."
    }
  ],
  "total_messages": 4,
  "next_message_cursor": null
}

When next_message_cursor is null, all messages in the thread have been returned.

Error Responses

StatusCodeDescription
400MISSING_REQUIRED_FIELDthread_id is missing
400RECORD_NOT_FOUNDNo thread with the given ID, or the caller does not own it

Mark Thread Read / Unread

PUT /api/v1/inbox/threads/{id}

This endpoint exists but is not functional. Interaction threads have no read-state column, so the request returns a NOT_SUPPORTED error rather than updating any state. Read/unread status is not backed by the schema.

Path Parameters

ParameterTypeDescription
idUUIDThe thread ID

Request Body

A boolean is_read is accepted but ignored. false maps to a mark_unread action; anything else maps to mark_read. Both return the same error.

{
  "is_read": true
}

Example Request

curl -X PUT "https://kasar.app/api/v1/inbox/threads/a1b2c3d4-..." \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{"is_read": true}'

Error Responses

StatusCodeDescription
400NOT_SUPPORTEDMarking threads read/unread is not supported — interaction threads have no read-state column

Get Single Interaction

GET /api/v1/interactions/{id}

Returns a single interaction (email, meeting, LinkedIn message, etc.) by ID. The metadata and raw_metadata fields are stripped from the response. Body fields are decrypted before being returned.

Visibility mirrors the app:

  • The owner of the interaction's thread always sees the full subject and body.
  • A non-owner is gated by the thread's content_visibility:
    • full — subject and content shown
    • metadata_subject (default when unset) — subject shown, content masked
    • none — subject and content both masked
  • For non-email channels (LinkedIn/WhatsApp/Telegram), a non-owner cannot see the interaction at all (RECORD_NOT_FOUND).

When content is masked, the body fields (content, content_html, content_text, content_blocks, summary) are replaced with a placeholder string.

Path Parameters

ParameterTypeDescription
idUUIDThe interaction ID

Example Request

curl -X GET "https://kasar.app/api/v1/interactions/e5f6a7b8-..." \
  -H "Authorization: Bearer ksr_a1b2c3d4e5f6..."

Response

record is the raw interactions row (minus metadata/raw_metadata), with body fields decrypted.

{
  "data": {
    "record": {
      "id": "e5f6a7b8-...",
      "direction": "outbound",
      "subject": "Q2 Partnership Proposal",
      "content": "Hi Bob, here is the revised proposal...",
      "content_html": "<p>Hi Bob, here is the revised proposal...</p>",
      "content_text": "Hi Bob, here is the revised proposal...",
      "participants": ["alice@example.com", "bob@acme.com"],
      "date": "2025-03-12T16:45:00Z",
      "interaction_thread_id": "a1b2c3d4-..."
    }
  }
}

Error Responses

StatusCodeDescription
400MISSING_REQUIRED_FIELDinteraction_id is missing
400RECORD_NOT_FOUNDNo interaction found with the given ID, or it is not visible to the caller

On this page