API referenceContacts

List a contact's message history

Returns the contact's cross-channel message history — inbound and outbound messages merged into a single newest-first list — so you can read the whole relationship across email, a2a, telegram, and other channels in one call.

Endpoint
GET https://api.dairo.app/v1/contacts/{contactId}/messages

Returns the contact's cross-channel message history — inbound and outbound messages merged into a single newest-first list — so you can read the whole relationship across email, a2a, telegram, and other channels in one call. Each item is metadata-only (direction, channel, status, from, to, subject, and timestamps; no message body) and is tagged inbound or outbound. Page with limit (1–100, default 25) and the opaque cursor from pagination.nextCursor; the cursor is a keyset over (createdAt, id), so paging stays stable as new messages arrive. contactId also accepts me to target the project self contact, and an unknown contact returns 404. Inbound messages appear here once Dairo has linked them to the sender's contact, and outbound messages are linked when you send to the contact. Requires the contacts:read scope.

Scope: contacts:read. Send the API key as a bearer token; Scopes lists what each one reaches.

Request

cURL
curl "https://api.dairo.app/v1/contacts/3fa85f64-5717-4562-b3fc-2c963f66afa6/messages" \
  -H "Authorization: Bearer $DAIRO_API_KEY"

Path parameters

NameTypeRequiredDescription
contactIdstringyesThe contact's ID.

Query parameters

NameTypeRequiredDescription
limitintegernoMaximum number of items in the page. (minimum 1, maximum 100, default 25)
cursorstringnoThe nextCursor of the previous page; omit it for the first page (Pagination).

Response

200 Success. Body: application/json, MessageListResponse.

FieldTypeRequiredDescription
object"list"yes
dataarray of Messageyes
paginationPaginationyes
200
{
  "object": "list",
  "data": [
    {
      "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "inboxId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "threadId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "direction": "inbound",
      "status": "string",
      "from": {
        "address": "support@yourapp.com",
        "name": "Ada Lovelace"
      },
      "to": [
        "string"
      ],
      "cc": [
        "string"
      ],
      "bcc": [
        "string"
      ],
      "subject": "Hello from Acme",
      "textPreview": "string",
      "hasHtml": true,
      "hasAttachments": true,
      "receivedAt": "2026-10-19T09:30:00Z",
      "createdAt": "2026-10-19T09:30:00Z",
      "textBody": null,
      "htmlBody": null,
      "attachments": [
        {
          "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "filename": null,
          "contentType": null,
          "sizeBytes": null,
          "contentId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "createdAt": "2026-10-19T09:30:00Z",
          "messageId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "disposition": "attachment"
        }
      ],
      "structured": {},
      "extractionStatus": "skipped",
      "channel": "email",
      "channelMetadata": {}
    }
  ],
  "pagination": {
    "nextCursor": "string",
    "hasMore": true
  }
}

Errors

Every error has the same body, {"error": {"type", "code", "message", "param"}}; branch on code. Errors lists every code.

StatusMeaning
400The request is malformed or a value is invalid (invalid_request, invalid_domain, idempotency_key_mismatch).
401The API key is missing or invalid.
403The key lacks the scope this endpoint needs (scope_missing) or may not do this (not_permitted).
404No such resource in this account (resource_not_found).
429Rate limit, plan limit, budget or spend cap reached (rate_limited, plan_limit_reached, budget_exceeded, spend_cap_reached).
500An unexpected error; retry with backoff, then contact support (internal_error).

On this page