Skip to content
AISARAISAR

Data types: messaging

Data-type reference for the messaging domain: channels, conversations, threads, contacts, attachments and conversation events.

A reference of the JSON shapes the API returns for messaging entities. Field sets are representative; nested references such as { "...Contact" } or [{ "...Thread" }] point to other types in this reference. Placeholder values "..." denote free-form strings, and {} denotes free-form objects.

Channels

Channel

json
{
  "id": 1,
  "company_id": 1,
  "channel_type_id": 1,
  "channel_type_provider_id": 1,
  "provider_key": "whatsapp",
  "provider_version": "1.0",
  "name": "...",
  "description": "...",
  "account_name": "...",
  "timezone": "UTC",
  "notes": "...",
  "status": "connected",
  "setup_state": "draft|pairing|ready|failed",
  "status_message": "...",
  "health": {},
  "external_ids": {},
  "config": {},
  "allow_broadcasts": true,
  "allow_automations": true,
  "allow_inbound_handling": true,
  "rate_limits": {},
  "quota_limits": {},
  "status_changed_at": "2024-01-01T00:00:00Z",
  "connected_at": "2024-01-01T00:00:00Z",
  "disconnected_at": null,
  "last_seen_at": "2024-01-01T00:00:00Z",
  "last_inbound_at": null,
  "last_outbound_at": null,
  "last_error_at": null,
  "last_error_code": null,
  "reconnect_attempts": 0,
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z",
  "capabilities": {},
  "limits": {},
  "channel_type": {
    "id": 1,
    "key": "whatsapp",
    "name": "WhatsApp"
  }
}

capabilities and limits are the resolved values: the base values from ChannelType plus the overrides from ChannelTypeProvider.

provider_key is the provider's public identifier; internal runtime-library names are never exposed. QR channels map to neutral values: WhatsApp (QR) → whatsapp, Telegram (personal) → telegram. Other providers are returned as-is: meta, meta_instagram, meta_threads, meta_messenger, telegram_bot, telegram_business, sip_telephony, live_chat_widget. To distinguish the channel type, use channel_type.key.

ChannelType

json
{
  "id": 1,
  "key": "whatsapp",
  "name": "WhatsApp",
  "description": "...",
  "category": "messaging",
  "order_id": 1,
  "badge_label": "Popular",
  "badge_variant": "primary",
  "is_published": true,
  "capabilities": {},
  "limits": {},
  "provider_config": {},
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z"
}

ChannelTypeProvider

json
{
  "id": 1,
  "channel_type_id": 1,
  "provider_key": "meta",
  "provider_version": "1",
  "capabilities_override": {},
  "limits_override": {},
  "config": {},
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z"
}

ChannelProviderConfig

json
{
  "flag_key": {
    "value": true,
    "label": "...",
    "description": "..."
  }
}

ChannelAccess

json
{
  "id": 1,
  "model_type": "team",
  "model_id": 10,
  "rule": "allow",
  "created_at": "2024-01-01T00:00:00Z"
}

ChannelLog

json
{
  "id": "123",
  "level": "info",
  "code": "...",
  "message": "...",
  "context": {},
  "created_at": "2024-01-01T00:00:00Z"
}

Conversations & messages

Conversation

json
{
  "id": 1,
  "company_id": 1,
  "contact_id": 10,
  "subject": "Support request",
  "lifecycle_status": "active",
  "is_closed": false,
  "is_archived": false,
  "last_message_id": 1001,
  "last_message_at": "2026-02-09T18:00:00Z",
  "last_message": { "...Message" },
  "unread_count_for_current_user": 5,
  "closed_at": null,
  "archived_at": null,
  "reopened_at": null,
  "created_at": "2026-02-09T17:00:00Z",
  "updated_at": "2026-02-09T18:00:00Z",
  "contact": { "...Contact" },
  "threads": [{ "...Thread" }]
}

lifecycle_status: active|closed.

Thread

json
{
  "id": 1,
  "conversation_id": 1,
  "company_id": 1,
  "contact_id": 10,
  "channel_id": 3,
  "contact_account_id": 44,
  "funnel_id": 5,
  "funnel_stage_id": 8,
  "lifecycle_status": "active",
  "is_closed": false,
  "is_archived": false,
  "is_group": false,
  "external_thread_id": "1203630...@g.us",
  "last_message_id": 1001,
  "last_message_at": "2026-02-09T18:00:00Z",
  "conversation_last_message_id": 1001,
  "conversation_last_message_at": "2026-02-09T18:00:00Z",
  "closed_at": null,
  "archived_at": null,
  "reopened_at": null,
  "created_at": "2026-02-09T17:00:00Z",
  "updated_at": "2026-02-09T18:00:00Z",
  "contact_account": { "...ContactAccount" },
  "funnel_stage": { "...FunnelStage" },
  "events": [{ "...ConversationEvent" }],
  "conversation": { "...Conversation" }
}

Contact

json
{
  "id": 10,
  "company_id": 1,
  "created_user_id": 7,
  "salutation": "Mr",
  "firstName": "John",
  "lastName": "Doe",
  "secondName": null,
  "displayName": "John Doe",
  "dob": null,
  "title": null,
  "photo": "https://api.aisar.app/v1/contacts/10/photo?signature={signature}",
  "comments": null,
  "company": null,
  "status": "lead",
  "merged_into_contact_id": null,
  "merged_at": null,
  "merged_by_user_id": null,
  "blocked_at": null,
  "blocked_reason": null,
  "blocked_by_user_id": null,
  "blocked_by_name": null,
  "last_activity_at": "2026-09-07T18:42:11.000000Z",
  "hidden_from_inbox_at": null,
  "hidden_from_inbox_by_user_id": null,
  "auto_lead_excluded_at": null,
  "auto_lead_excluded_via": null,
  "auto_lead_excluded_by_user_id": null,
  "phones": [{ "phone": "+12025550169", "type": "mobile" }],
  "emailes": [{ "email": "john@example.com", "type": "work" }],
  "contactAccounts": [{ "...ContactAccount" }]
}

The array of email addresses uses the historical key name emailes (not emails). The photo field is a temporary signed URL: the signature parameter in the example is a placeholder.

Blocking a contact (since 2026-09-04) is described by four fields: blocked_at — when it was blocked (ISO-8601) and the single source of truth (status: "blocked" may be a leftover of the earlier, nominal blocking and is not enforced anywhere); blocked_reason — free-text reason or null; blocked_by_user_id — who blocked it, where null means "the AI agent did" (it has no user row); blocked_by_name — that same user's name, so it need not be fetched separately (null both when the agent blocked and when the user has been deleted).

last_activity_at (the last message or call in any of the contact's conversations), the hidden_from_inbox_at / hidden_from_inbox_by_user_id pair (hidden from the shared working inbox) and, since 2026-09-29, the auto_lead_excluded_at / auto_lead_excluded_via (manual or decline) / auto_lead_excluded_by_user_id trio (the contact is excluded from auto-leads, see the Contacts group) are always present. Two further fields — open_deals_count and responsible_user ({id, name} or null) — are emitted only by the Contacts group endpoints; the contact nested inside Conversation and Thread does not carry them at all, and a missing key means "not requested", not zero or null.

MessageAttachment

json
{
  "id": 501,
  "type": "image",
  "url": "https://api.aisar.app/v1/messages/1001/attachments/501/media?company=3&signature={signature}",
  "thumbnail_url": "https://api.aisar.app/v1/messages/1001/attachments/501/media?company=3&w=640&signature={signature}",
  "playback_url": null,
  "filename": "12.jpg",
  "mime_type": "image/jpeg",
  "size": 23927,
  "width": 1280,
  "height": 960,
  "duration": null,
  "metadata": {}
}

width / height are the original image or video size in pixels (integer or null); they are filled when the provider reports it (WhatsApp almost always, Instagram and Telegram often null). The same fields are present in realtime message events. url is a signed download link; the signature parameter in the example is a placeholder. Since 2026-09-22 the signed parameter set includes company, the id of the company that owns the attachment; it is checked against the attachment when the file is served, so the link cannot be pointed at another company without breaking the signature. Links without company issued earlier keep working for business companies. The signature lifetime depends on the endpoint: in messages (GET /messages, GET /messages/{message}/attachments and so on) url, thumbnail_url and playback_url are signed without expiry, in the conversation and contact file galleries for 20 minutes. thumbnail_url (since 2026-08-24), for locally-stored image attachments (except image/svg+xml), is the same route with w=640, returning a webp preview; it stays null for other attachment types or before the file is stored locally. playback_url (since 2026-08-26) is a signed link to the m4a/AAC version of the attachment, lazily transcoded from the original OGG/Opus; it is populated only for voice attachments and audio/ogg attachments already stored locally, null otherwise. In the webhook payload the same field is signed for 7 days (see the webhook events reference, message.created).

type is the full message_attachments.type CHECK-constraint value set: image, video, audio, voice, document, file, contact, location, sticker, ig_reel, ig_post, ig_story, share, ig_story_reply, story_mention, ephemeral, unsupported_type, template.

metadata is a free-form object whose keys depend on the channel and attachment type: download_status (pending|completed|expired|video_skipped — lazy-fetch state; absent until a fetch has been attempted) — pending is set by the webhook handler right away for lazy Instagram attachments (story_mention/ig_story/ig_reel/ig_post/share), expired/video_skipped are outcomes of an Instagram CDN fetch attempt (an expired story, a video deliberately not mirrored); media_id — the provider-side media id (Instagram: ig_post_media_id/reel_video_id/story_media_id, used for fetching); external_media_id — the media id on Meta channels (WhatsApp Cloud/Instagram Graph, used for fetching via the Graph API); title — the card caption (ig_post, ig_reel, share, story_mention); display_name, phones[], organization, vcard, contacts_count — fields of a contact attachment (type: contact; the set depends on the channel — WhatsApp carries vcard, Telegram a simplified phones[] with no vcard); file_id — the file id in the Telegram Bot API; kind — a domain label for the attachment, unrelated to the channel type (e.g. call_recording — a call recording attached as type: audio); template.elements[] (since 2026-08-26) — the contents of an IG generic-template card (type: template) when Meta actually sent one (in most cases generic.elements is empty and metadata is then null): an array of elements shaped like { "title": "...", "buttons": [{ "type": "open_url" | "postback", "title": "...", "url"?: "...", "payload"?: "..." }] }, url is present for open_url, payload for postback.

ConversationEvent

json
{
  "id": 1,
  "company_id": 1,
  "conversation_id": 1,
  "thread_id": 1,
  "type": "comment",
  "author_user_id": 7,
  "comment": "Conversation closed by operator.",
  "from_lifecycle_status": "active",
  "to_lifecycle_status": "closed",
  "payload": {},
  "created_at": "2026-02-09T18:10:00Z",
  "updated_at": "2026-02-09T18:10:00Z",
  "author": { "id": 7, "name": "Jane", "lastname": "Doe", "email": "...", "photo": null }
}

type: created|comment|status_changed|archived|unarchived|assigned|unassigned.

ConversationParticipant

json
{
  "id": 1,
  "company_id": 1,
  "conversation_id": 1,
  "member_type": "user",
  "member_id": 7,
  "role": "assignee",
  "is_primary": true,
  "joined_at": "2026-02-09T18:00:00Z",
  "left_at": null,
  "added_by_user_id": 1,
  "removed_by_user_id": null,
  "created_at": "2026-02-09T18:00:00Z",
  "updated_at": "2026-02-09T18:00:00Z",
  "added_by": { "id": 1, "name": "Jane", "lastname": "Doe", "email": "..." },
  "removed_by": null
}

member_type: user|team|bot. role: the meaningful role is assignee (the responsible operator); the default is participant.

ConversationTag

json
{
  "id": 1,
  "company_id": 1,
  "conversation_id": 1,
  "name": "vip",
  "color": "#22c55e",
  "source": "manual",
  "created_by_user_id": 7,
  "created_at": "2026-02-09T18:00:00Z",
  "updated_at": "2026-02-09T18:00:00Z",
  "created_by": { "id": 7, "name": "Jane", "lastname": "Doe", "email": "..." }
}

source: manual|automation|integration.

ConversationNote

json
{
  "id": 1,
  "company_id": 1,
  "conversation_id": 1,
  "thread_id": 2,
  "author_user_id": 7,
  "body": "Closed after successful resolution.",
  "is_private": true,
  "pinned_at": null,
  "edited_at": null,
  "metadata": {},
  "created_at": "2026-02-09T18:00:00Z",
  "updated_at": "2026-02-09T18:00:00Z",
  "author": { "id": 7, "name": "Jane", "lastname": "Doe", "email": "..." }
}

ConversationRead

json
{
  "id": 501,
  "company_id": 1,
  "conversation_id": 1,
  "thread_id": 2,
  "user_id": 7,
  "last_read_message_id": 1001,
  "first_read_at": "2026-02-09T18:05:00Z",
  "last_read_at": "2026-02-09T18:10:00Z",
  "created_at": "2026-02-09T18:10:00Z",
  "updated_at": "2026-02-09T18:10:00Z",
  "user": { "id": 7, "name": "Jane", "lastname": "Doe", "email": "..." }
}