> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nekt.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Chatwoot as a data source

> Bring data from Chatwoot to your Lakehouse.

Chatwoot is an open-source customer engagement platform that centralizes conversations from a website widget, WhatsApp, Instagram, Facebook, Telegram, email and a generic API channel into shared inboxes. The connector extracts those conversations and their full message history, the contacts behind them, and the account configuration — inboxes, agents, teams, labels and custom attributes — so you can analyse your customer conversations in your Lakehouse.

The connector works with **Chatwoot Cloud** and with **self-hosted** installations; the only difference is the address you inform in the Chatwoot URL setting.

## Configuring Chatwoot as a Source

In the [Sources](https://app.nekt.ai/sources) tab, click on the "Add source" button located on the top right of your screen. Then, select the Chatwoot option from the list of connectors.

Click **Next** and you'll be prompted to add your access.

### 1. Add account access

Chatwoot authenticates with a static **user access token**, sent in the `api_access_token` header. In Chatwoot, open your avatar in the bottom left corner, go to **Profile Settings**, scroll to **Access Token** and copy the value.

<Warning>The token inherits the permissions of the user who owns it. An **administrator** token reaches every inbox, conversation and contact of the account; an **agent** token only reaches the inboxes that agent is assigned to, and Chatwoot denies access to the Agent Bots, Automation Rules and Inbox Members streams. Generate the token with an account administrator to sync the whole account.</Warning>

The following configurations are available:

* **Access token**: the user access token copied from **Profile Settings > Access Token**. Required.

* **Account ID**: the numeric identifier of the account you want to sync. It is the number that appears in the application URL — in `app.chatwoot.com/app/accounts/1/dashboard`, the account ID is `1`. Required.

* **Chatwoot URL**: the address of your Chatwoot installation. Keep the default `https://app.chatwoot.com` for Chatwoot Cloud, or inform your own address when self-hosting, for example `https://chat.yourcompany.com`.

* **Initial sync date**: the earliest date from which records will be synced. It applies to the streams replicated incrementally — Conversations (by last activity) and CSAT Survey Responses (by creation date).

Once you're done, click **Next**.

### 2. Select streams

Choose which data streams you want to sync. For faster extractions, select only the streams that are relevant to your analysis. You can select entire groups of streams or pick specific ones.

> Tip: The stream can be found more easily by typing its name.

<Note>The **Messages** stream is a child of **Conversations**: it fetches the message history of each conversation the run touched. Selecting it on an account with a long history makes the first extraction considerably longer, since every conversation is read from its first message.</Note>

<Info>If you don't see a stream you were expecting to find, please check if your access token has access to it. Chatwoot's Reporting Events and Audit Logs endpoints, for instance, exist only in the enterprise edition and are not covered by this connector.</Info>

Select the streams and click **Next**.

### 3. Configure data streams

Customize how you want your data to appear in your catalog. Select the desired layer where the data will be placed, a folder to organize it inside the layer, a name for each table (which will effectively contain the fetched data) and the type of sync.

* **Layer**: choose between the existing layers on your catalog. This is where you will find your new extracted tables as the extraction runs successfully.
* **Folder**: a folder can be created inside the selected layer to group all tables being created from this new data source.
* **Table name**: we suggest a name, but feel free to customize it. You have the option to add a **prefix** to all tables at once and make this process faster!
* **Sync Type**: Conversations and CSAT Survey Responses support INCREMENTAL; the remaining streams are full table. Read more about Sync Types [here](https://docs.nekt.com/get-started/core-concepts/types-of-sync).

Once you are done configuring, click **Next**.

### 4. Configure data source

Describe your data source for easy identification within your organization, not exceeding 140 characters.

To define your [Trigger](https://docs.nekt.com/get-started/core-concepts/triggers), consider how often you want data to be extracted from this source. This decision usually depends on how frequently you need the new table data updated (every day, once a week, or only at specific times).

Optionally, you can define some additional settings:

* Configure Delta Log Retention and determine for how long we should store old states of this table as it gets updated. Read more about this resource [here](https://docs.nekt.com/get-started/core-concepts/resource-control).
* Determine when to execute an **Additional [Full Sync](https://docs.nekt.com/get-started/core-concepts/types-of-sync#additional-full-sync)**. This will complement the incremental data extractions, ensuring that your data is completely synchronized with your source every once in a while.

Once you are ready, click **Next** to finalize the setup.

### 5. Check your new source

You can view your new source on the [Sources](https://app.nekt.ai/sources) page. If needed, manually trigger the source extraction by clicking on the arrow button. Once executed, your data will appear in your Catalog.

<Warning>For you to be able to see it on your [Catalog](https://app.nekt.ai/catalog), you need at least one successful source run.</Warning>

# Streams and Fields

Below you'll find all available data streams from Chatwoot and their corresponding fields. API reference: [developers.chatwoot.com](https://developers.chatwoot.com/api-reference/introduction).

<AccordionGroup>
  <Accordion title="Account">
    The Chatwoot account itself (`GET /api/v1/accounts/{account_id}`). A single row carrying the account's locale, status, plan and feature flags.

    Primary key: `id`

    | Field                     | Type     | Description                                                                                                                                       |
    | :------------------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                      | Integer  | Unique identifier of the account, used as the primary key.                                                                                        |
    | `name`                    | String   | Display name of the account.                                                                                                                      |
    | `locale`                  | String   | Default language of the account, for example 'en' or 'pt\_BR'.                                                                                    |
    | `domain`                  | String   | Custom domain configured for the account's help center.                                                                                           |
    | `support_email`           | String   | Email address used as the sender for the account's support emails.                                                                                |
    | `status`                  | String   | Lifecycle status of the account, for example 'active' or 'suspended'.                                                                             |
    | `created_at`              | Datetime | Timestamp when the account was created (UTC).                                                                                                     |
    | `latest_chatwoot_version` | String   | Latest Chatwoot version available upstream, reported by self-hosted installations.                                                                |
    | `features`                | String   | Feature flags enabled for the account, as a JSON object mapping each feature name to a boolean.                                                   |
    | `settings`                | String   | Account-level settings, as a JSON object — includes the auto-resolve delay and the message sent when a conversation is auto-resolved.             |
    | `custom_attributes`       | String   | Account metadata Chatwoot keeps outside the main columns, as a JSON object — plan name, subscription status, industry, company size and timezone. |
    | `subscribed_features`     | Array    | Enterprise features included in the account's subscription.                                                                                       |
  </Accordion>

  <Accordion title="Agents">
    Users that belong to the account (`GET /api/v1/accounts/{account_id}/agents`), with their role and current presence.

    Primary key: `id`

    | Field                 | Type    | Description                                                                                  |
    | :-------------------- | :------ | :------------------------------------------------------------------------------------------- |
    | `id`                  | Integer | Unique identifier of the agent.                                                              |
    | `account_id`          | Integer | Identifier of the Chatwoot account the record belongs to.                                    |
    | `name`                | String  | Full name of the agent.                                                                      |
    | `available_name`      | String  | Name shown to contacts in the conversation, which can differ from the agent's internal name. |
    | `email`               | String  | Email address the agent signs in with.                                                       |
    | `role`                | String  | Role of the agent in the account: 'administrator' or 'agent'.                                |
    | `confirmed`           | Boolean | Whether the agent has confirmed their email invitation.                                      |
    | `availability_status` | String  | Current presence of the agent: 'online', 'busy' or 'offline'.                                |
    | `auto_offline`        | Boolean | Whether Chatwoot automatically marks the agent offline after a period of inactivity.         |
    | `provider`            | String  | Authentication provider of the agent account, for example 'email'.                           |
    | `thumbnail`           | String  | URL of the agent's avatar image.                                                             |
    | `custom_attributes`   | String  | Custom attributes stored on the agent, as a JSON object.                                     |
  </Accordion>

  <Accordion title="Teams">
    Teams used to group agents and route conversations (`GET /api/v1/accounts/{account_id}/teams`).

    Primary key: `id`

    | Field               | Type    | Description                                                                                     |
    | :------------------ | :------ | :---------------------------------------------------------------------------------------------- |
    | `id`                | Integer | Unique identifier of the team, used as the primary key.                                         |
    | `account_id`        | Integer | Identifier of the Chatwoot account the record belongs to.                                       |
    | `name`              | String  | Name of the team.                                                                               |
    | `description`       | String  | Free-text description of what the team handles.                                                 |
    | `allow_auto_assign` | Boolean | Whether assigning a conversation to this team also auto-assigns it to one of the team's agents. |
    | `icon`              | String  | Emoji shown as the team's icon.                                                                 |
    | `icon_color`        | String  | Hex color of the team's icon.                                                                   |
  </Accordion>

  <Accordion title="Team Members">
    Membership rows linking each team to its agents (`GET /api/v1/accounts/{account_id}/teams/{team_id}/team_members`). **Child stream of Teams.**

    Primary key: `team_id`, `id`

    | Field                 | Type    | Description                                                                                  |
    | :-------------------- | :------ | :------------------------------------------------------------------------------------------- |
    | `team_id`             | Integer | Identifier of the team the agent belongs to.                                                 |
    | `id`                  | Integer | Unique identifier of the agent.                                                              |
    | `account_id`          | Integer | Identifier of the Chatwoot account the record belongs to.                                    |
    | `name`                | String  | Full name of the agent.                                                                      |
    | `available_name`      | String  | Name shown to contacts in the conversation, which can differ from the agent's internal name. |
    | `email`               | String  | Email address the agent signs in with.                                                       |
    | `role`                | String  | Role of the agent in the account: 'administrator' or 'agent'.                                |
    | `confirmed`           | Boolean | Whether the agent has confirmed their email invitation.                                      |
    | `availability_status` | String  | Current presence of the agent: 'online', 'busy' or 'offline'.                                |
    | `auto_offline`        | Boolean | Whether Chatwoot automatically marks the agent offline after a period of inactivity.         |
    | `provider`            | String  | Authentication provider of the agent account, for example 'email'.                           |
    | `thumbnail`           | String  | URL of the agent's avatar image.                                                             |
    | `custom_attributes`   | String  | Custom attributes stored on the agent, as a JSON object.                                     |
  </Accordion>

  <Accordion title="Inboxes">
    The channels of the account — website widget, WhatsApp, Instagram, email, API and others (`GET /api/v1/accounts/{account_id}/inboxes`). Channel credentials that Chatwoot returns to administrators (IMAP/SMTP passwords, HMAC tokens, Twilio auth tokens) are deliberately **not** extracted.

    Primary key: `id`

    | Field                           | Type    | Description                                                                                                                      |
    | :------------------------------ | :------ | :------------------------------------------------------------------------------------------------------------------------------- |
    | `id`                            | Integer | Unique identifier of the inbox, used as the primary key.                                                                         |
    | `account_id`                    | Integer | Identifier of the Chatwoot account the record belongs to.                                                                        |
    | `name`                          | String  | Display name of the inbox.                                                                                                       |
    | `channel_type`                  | String  | Channel class backing the inbox, for example 'Channel::WebWidget', 'Channel::Whatsapp', 'Channel::Email' or 'Channel::Api'.      |
    | `channel_id`                    | Integer | Identifier of the channel record backing the inbox.                                                                              |
    | `provider`                      | String  | Provider used by the channel when it supports more than one, for example 'whatsapp\_cloud' or 'microsoft' for email.             |
    | `avatar_url`                    | String  | URL of the inbox avatar shown to contacts.                                                                                       |
    | `greeting_enabled`              | Boolean | Whether a greeting message is sent when a conversation starts.                                                                   |
    | `greeting_message`              | String  | Greeting message sent when a conversation starts.                                                                                |
    | `working_hours_enabled`         | Boolean | Whether business hours are configured for this inbox.                                                                            |
    | `working_hours`                 | String  | Weekly business-hours schedule, as a JSON array of objects with the day of week, open and close times.                           |
    | `timezone`                      | String  | Timezone the inbox's business hours are expressed in.                                                                            |
    | `out_of_office_message`         | String  | Message sent to contacts who write outside business hours.                                                                       |
    | `enable_email_collect`          | Boolean | Whether Chatwoot asks the contact for an email address.                                                                          |
    | `csat_survey_enabled`           | Boolean | Whether a satisfaction survey is sent when a conversation is resolved.                                                           |
    | `csat_config`                   | String  | Satisfaction survey configuration, as a JSON object.                                                                             |
    | `enable_auto_assignment`        | Boolean | Whether new conversations are auto-assigned to available agents.                                                                 |
    | `auto_assignment_config`        | String  | Auto-assignment configuration, as a JSON object — includes the maximum number of conversations an agent can be assigned at once. |
    | `allow_messages_after_resolved` | Boolean | Whether contacts can keep writing to a conversation after it is resolved.                                                        |
    | `lock_to_single_conversation`   | Boolean | Whether every message from a contact is appended to a single ongoing conversation instead of opening a new one.                  |
    | `sender_name_type`              | String  | Which name outgoing messages are signed with: 'friendly' (agent name) or 'professional' (business name).                         |
    | `business_name`                 | String  | Business name used when messages are signed professionally.                                                                      |
    | `callback_webhook_url`          | String  | Webhook URL the channel provider calls back on.                                                                                  |
    | `website_url`                   | String  | Website the widget is installed on (website widget inboxes).                                                                     |
    | `widget_color`                  | String  | Hex color of the website widget.                                                                                                 |
    | `welcome_title`                 | String  | Title shown at the top of the website widget.                                                                                    |
    | `welcome_tagline`               | String  | Tagline shown under the title of the website widget.                                                                             |
    | `reply_time`                    | String  | Expected reply time advertised in the website widget: 'in\_a\_few\_minutes', 'in\_a\_few\_hours' or 'in\_a\_day'.                |
    | `allowed_domains`               | String  | Domains allowed to embed the website widget.                                                                                     |
    | `pre_chat_form_enabled`         | Boolean | Whether the widget asks the contact for details before chatting.                                                                 |
    | `pre_chat_form_options`         | String  | Pre-chat form configuration, as a JSON object.                                                                                   |
    | `continuity_via_email`          | Boolean | Whether website widget conversations continue by email once the contact leaves the page.                                         |
    | `email`                         | String  | Address the inbox receives mail on (email inboxes).                                                                              |
    | `forward_to_email`              | String  | Address incoming mail should be forwarded to (email inboxes).                                                                    |
    | `phone_number`                  | String  | Phone number of the inbox (WhatsApp, SMS and voice inboxes).                                                                     |
    | `medium`                        | String  | Twilio medium of the inbox: 'sms' or 'whatsapp'.                                                                                 |
    | `bot_name`                      | String  | Name of the Telegram bot backing the inbox.                                                                                      |
    | `page_id`                       | String  | Facebook page identifier backing the inbox.                                                                                      |
    | `instagram_id`                  | String  | Instagram account identifier backing the inbox.                                                                                  |
    | `inbox_identifier`              | String  | Public identifier of an API inbox, used by the client APIs to create contacts and conversations.                                 |
    | `webhook_url`                   | String  | URL Chatwoot posts outgoing messages to (API inboxes).                                                                           |
    | `additional_attributes`         | String  | Channel-specific extra settings, as a JSON object.                                                                               |
    | `reauthorization_required`      | Boolean | Whether the channel's authorization has expired and an administrator must reconnect it.                                          |
    | `help_center`                   | String  | Help center portal linked to the inbox, as a JSON object with its name and slug.                                                 |
  </Accordion>

  <Accordion title="Inbox Members">
    Membership rows linking each inbox to the agents assigned to it (`GET /api/v1/accounts/{account_id}/inbox_members/{inbox_id}`). **Child stream of Inboxes.**

    Primary key: `inbox_id`, `id`

    | Field                 | Type    | Description                                                                                  |
    | :-------------------- | :------ | :------------------------------------------------------------------------------------------- |
    | `inbox_id`            | Integer | Identifier of the inbox the agent is assigned to.                                            |
    | `id`                  | Integer | Unique identifier of the agent.                                                              |
    | `account_id`          | Integer | Identifier of the Chatwoot account the record belongs to.                                    |
    | `name`                | String  | Full name of the agent.                                                                      |
    | `available_name`      | String  | Name shown to contacts in the conversation, which can differ from the agent's internal name. |
    | `email`               | String  | Email address the agent signs in with.                                                       |
    | `role`                | String  | Role of the agent in the account: 'administrator' or 'agent'.                                |
    | `confirmed`           | Boolean | Whether the agent has confirmed their email invitation.                                      |
    | `availability_status` | String  | Current presence of the agent: 'online', 'busy' or 'offline'.                                |
    | `auto_offline`        | Boolean | Whether Chatwoot automatically marks the agent offline after a period of inactivity.         |
    | `provider`            | String  | Authentication provider of the agent account, for example 'email'.                           |
    | `thumbnail`           | String  | URL of the agent's avatar image.                                                             |
    | `custom_attributes`   | String  | Custom attributes stored on the agent, as a JSON object.                                     |
  </Accordion>

  <Accordion title="Labels">
    Labels available to tag conversations and contacts (`GET /api/v1/accounts/{account_id}/labels`). The `title` is what appears in the `labels` array of a conversation.

    Primary key: `id`

    | Field             | Type    | Description                                                                                  |
    | :---------------- | :------ | :------------------------------------------------------------------------------------------- |
    | `id`              | Integer | Unique identifier of the label, used as the primary key.                                     |
    | `account_id`      | Integer | Identifier of the Chatwoot account the record belongs to.                                    |
    | `title`           | String  | Title of the label — this is the value that appears in the 'labels' array of a conversation. |
    | `description`     | String  | Free-text description of what the label means.                                               |
    | `color`           | String  | Hex color the label is displayed with.                                                       |
    | `show_on_sidebar` | Boolean | Whether the label is pinned to the conversation sidebar.                                     |
  </Accordion>

  <Accordion title="Canned Responses">
    Saved replies agents insert with a short code (`GET /api/v1/accounts/{account_id}/canned_responses`).

    Primary key: `id`

    | Field        | Type     | Description                                                        |
    | :----------- | :------- | :----------------------------------------------------------------- |
    | `id`         | Integer  | Unique identifier of the canned response, used as the primary key. |
    | `account_id` | Integer  | Identifier of the Chatwoot account the record belongs to.          |
    | `short_code` | String   | Short code an agent types to insert the response.                  |
    | `content`    | String   | Message body inserted when the short code is used.                 |
    | `created_at` | Datetime | Timestamp when the canned response was created (UTC).              |
    | `updated_at` | Datetime | Timestamp when the canned response was last updated (UTC).         |
  </Accordion>

  <Accordion title="Custom Attribute Definitions">
    Definitions of the custom attributes available on contacts and conversations (`GET /api/v1/accounts/{account_id}/custom_attribute_definitions`). Both models are extracted; `attribute_key` is the key that appears inside the `custom_attributes` JSON of contacts and conversations.

    Primary key: `id`

    | Field                    | Type     | Description                                                                                                             |
    | :----------------------- | :------- | :---------------------------------------------------------------------------------------------------------------------- |
    | `id`                     | Integer  | Unique identifier of the definition, used as the primary key.                                                           |
    | `account_id`             | Integer  | Identifier of the Chatwoot account the record belongs to.                                                               |
    | `attribute_model`        | String   | Which record the attribute is attached to: 'contact\_attribute' or 'conversation\_attribute'.                           |
    | `attribute_key`          | String   | Machine key of the attribute — the key that appears inside the 'custom\_attributes' JSON of contacts and conversations. |
    | `attribute_display_name` | String   | Label shown for the attribute in the Chatwoot interface.                                                                |
    | `attribute_display_type` | String   | Input type of the attribute: text, number, currency, percent, link, date, list or checkbox.                             |
    | `attribute_description`  | String   | Help text explaining what the attribute records.                                                                        |
    | `attribute_values`       | String   | Allowed values for a list attribute, as a JSON array of strings.                                                        |
    | `default_value`          | String   | Value the attribute takes when none is set.                                                                             |
    | `regex_pattern`          | String   | Regular expression the value must match, when one is configured.                                                        |
    | `regex_cue`              | String   | Hint shown to the agent when the value fails the regex.                                                                 |
    | `created_at`             | Datetime | Timestamp when the definition was created (UTC).                                                                        |
    | `updated_at`             | Datetime | Timestamp when the definition was last updated (UTC).                                                                   |
  </Accordion>

  <Accordion title="Automation Rules">
    Rules that react to conversation and message events (`GET /api/v1/accounts/{account_id}/automation_rules`). Requires an administrator token — the stream is skipped with a warning otherwise.

    Primary key: `id`

    | Field         | Type     | Description                                                                                                                              |
    | :------------ | :------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
    | `id`          | Integer  | Unique identifier of the automation rule, used as the primary key.                                                                       |
    | `account_id`  | Integer  | Identifier of the Chatwoot account the record belongs to.                                                                                |
    | `name`        | String   | Name of the automation rule.                                                                                                             |
    | `description` | String   | Free-text description of what the rule does.                                                                                             |
    | `event_name`  | String   | Event that triggers the rule: 'conversation\_created', 'conversation\_updated' or 'message\_created'.                                    |
    | `conditions`  | String   | Conditions evaluated when the event fires, as a JSON array of objects with attribute\_key, filter\_operator, values and query\_operator. |
    | `actions`     | String   | Actions performed when the conditions match, as a JSON array of objects with action\_name and action\_params.                            |
    | `active`      | Boolean  | Whether the rule is currently enabled.                                                                                                   |
    | `created_on`  | Datetime | Timestamp when the rule was created (UTC).                                                                                               |
  </Accordion>

  <Accordion title="Agent Bots">
    Agent bots registered on the account (`GET /api/v1/accounts/{account_id}/agent_bots`). Requires an administrator token — the stream is skipped with a warning otherwise. The bot access token and signing secret are deliberately **not** extracted.

    Primary key: `id`

    | Field          | Type    | Description                                                             |
    | :------------- | :------ | :---------------------------------------------------------------------- |
    | `id`           | Integer | Unique identifier of the agent bot, used as the primary key.            |
    | `account_id`   | Integer | Identifier of the Chatwoot account the record belongs to.               |
    | `name`         | String  | Name of the agent bot.                                                  |
    | `description`  | String  | Free-text description of what the bot does.                             |
    | `bot_type`     | String  | Type of the bot: 'webhook' or 'csml'.                                   |
    | `bot_config`   | String  | Bot-type-specific configuration, as a JSON object.                      |
    | `outgoing_url` | String  | URL Chatwoot posts conversation events to for webhook bots.             |
    | `thumbnail`    | String  | URL of the bot's avatar image.                                          |
    | `system_bot`   | Boolean | Whether the bot ships with Chatwoot rather than being customer-created. |
  </Accordion>

  <Accordion title="Contacts">
    The people behind the conversations (`GET /api/v1/accounts/{account_id}/contacts`). Chatwoot exposes no modification date on contacts, so this stream is replicated in full on every run.

    Primary key: `id`

    | Field                   | Type     | Description                                                                                                                                 |
    | :---------------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------ |
    | `id`                    | Integer  | Unique identifier of the contact, used as the primary key.                                                                                  |
    | `account_id`            | Integer  | Identifier of the Chatwoot account the record belongs to.                                                                                   |
    | `name`                  | String   | Display name of the contact.                                                                                                                |
    | `email`                 | String   | Email address of the contact.                                                                                                               |
    | `phone_number`          | String   | Phone number of the contact, in E.164 format.                                                                                               |
    | `identifier`            | String   | External identifier set by the system that created the contact, used to reconcile it with the customer's own database.                      |
    | `blocked`               | Boolean  | Whether the contact has been blocked from writing to the account.                                                                           |
    | `availability_status`   | String   | Whether the contact is currently 'online' or 'offline'.                                                                                     |
    | `thumbnail`             | String   | URL of the contact's avatar image.                                                                                                          |
    | `created_at`            | Datetime | Timestamp when the contact was created (UTC).                                                                                               |
    | `last_activity_at`      | Datetime | Timestamp of the contact's most recent activity (UTC).                                                                                      |
    | `additional_attributes` | String   | Attributes Chatwoot collects automatically, as a JSON object — browser and device details, referrer, city, country and company name.        |
    | `custom_attributes`     | String   | Custom attributes set on the contact, as a JSON object keyed by the attribute keys listed in the custom\_attribute\_definitions stream.     |
    | `contact_inboxes`       | String   | Inboxes the contact can be reached through, as a JSON array of objects with the inbox and the source\_id that identifies the contact in it. |
  </Accordion>

  <Accordion title="Conversations">
    Conversations held with contacts across every inbox (`GET /api/v1/accounts/{account_id}/conversations`), in every status and for every assignee. Replicated incrementally on `last_activity_at`, which Chatwoot bumps on any change to the conversation — a new message, a status or assignee change, a label.

    Primary key: `id` · Replication key: `last_activity_at`

    | Field                     | Type     | Description                                                                                                                                        |
    | :------------------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `id`                      | Integer  | Identifier of the conversation within the account — the number shown in the Chatwoot interface and used in the API paths. Used as the primary key. |
    | `account_id`              | Integer  | Identifier of the Chatwoot account the record belongs to.                                                                                          |
    | `uuid`                    | String   | Globally unique identifier of the conversation.                                                                                                    |
    | `inbox_id`                | Integer  | Identifier of the inbox the conversation arrived in.                                                                                               |
    | `channel`                 | String   | Channel class of the inbox the conversation arrived in, for example 'Channel::WebWidget' or 'Channel::Whatsapp'.                                   |
    | `status`                  | String   | Current status of the conversation: 'open', 'resolved', 'pending' or 'snoozed'.                                                                    |
    | `priority`                | String   | Priority assigned to the conversation: 'low', 'medium', 'high' or 'urgent'. Empty when no priority is set.                                         |
    | `labels`                  | Array    | Titles of the labels applied to the conversation.                                                                                                  |
    | `contact_id`              | Integer  | Identifier of the contact the conversation is held with.                                                                                           |
    | `contact_name`            | String   | Display name of the contact the conversation is held with.                                                                                         |
    | `contact_email`           | String   | Email address of the contact the conversation is held with.                                                                                        |
    | `contact_phone_number`    | String   | Phone number of the contact the conversation is held with.                                                                                         |
    | `contact_identifier`      | String   | External identifier of the contact, when the account sets one.                                                                                     |
    | `assignee_id`             | Integer  | Identifier of the agent or agent bot the conversation is assigned to. Empty while the conversation is unassigned.                                  |
    | `assignee_name`           | String   | Name of the agent or agent bot the conversation is assigned to.                                                                                    |
    | `assignee_email`          | String   | Email address of the agent the conversation is assigned to.                                                                                        |
    | `assignee_type`           | String   | Whether the assignee is a human agent ('User') or an automation ('AgentBot').                                                                      |
    | `team_id`                 | Integer  | Identifier of the team the conversation is routed to.                                                                                              |
    | `team_name`               | String   | Name of the team the conversation is routed to.                                                                                                    |
    | `created_at`              | Datetime | Timestamp when the conversation was opened (UTC).                                                                                                  |
    | `updated_at`              | Datetime | Timestamp when the conversation record was last written (UTC).                                                                                     |
    | `last_activity_at`        | Datetime | Timestamp of the last activity in the conversation (UTC) — a message, a status change or an assignment. Used as the incremental replication key.   |
    | `first_reply_created_at`  | Datetime | Timestamp of the first agent reply (UTC), the basis of the first response time metric. Empty when no agent has replied yet.                        |
    | `waiting_since`           | Datetime | Timestamp since when the conversation has been waiting for an agent reply (UTC). Empty when nothing is pending.                                    |
    | `snoozed_until`           | Datetime | Timestamp until which the conversation stays snoozed (UTC).                                                                                        |
    | `agent_last_seen_at`      | Datetime | Timestamp when any agent last opened the conversation (UTC).                                                                                       |
    | `assignee_last_seen_at`   | Datetime | Timestamp when the assigned agent last opened the conversation (UTC).                                                                              |
    | `contact_last_seen_at`    | Datetime | Timestamp when the contact last read the conversation (UTC).                                                                                       |
    | `unread_count`            | Integer  | Number of incoming messages no agent has read yet.                                                                                                 |
    | `muted`                   | Boolean  | Whether notifications for this conversation are muted.                                                                                             |
    | `can_reply`               | Boolean  | Whether an agent can still reply — some channels close the reply window a fixed time after the contact's last message.                             |
    | `hmac_verified`           | Boolean  | Whether the contact's identity was verified with the inbox's HMAC signature.                                                                       |
    | `sla_policy_id`           | Integer  | Identifier of the SLA policy applied to the conversation.                                                                                          |
    | `last_message_id`         | Integer  | Identifier of the latest message that is not a system activity — the full history lives in the messages stream.                                    |
    | `last_message_content`    | String   | Body of the latest non-activity message in the conversation.                                                                                       |
    | `last_message_type`       | String   | Direction of the latest non-activity message: 'incoming' (from the contact), 'outgoing' (from an agent) or 'template'.                             |
    | `last_message_created_at` | Datetime | Timestamp of the latest non-activity message (UTC).                                                                                                |
    | `additional_attributes`   | String   | Context Chatwoot captured when the conversation started, as a JSON object — browser, referrer and initiated-at details.                            |
    | `custom_attributes`       | String   | Custom attributes set on the conversation, as a JSON object keyed by the attribute keys listed in the custom\_attribute\_definitions stream.       |
  </Accordion>

  <Accordion title="Messages">
    The full message history of a conversation, including the system activity notes (`GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages`). **Child stream of Conversations**: an incremental run only re-reads the conversations that saw activity since the last sync.

    Primary key: `id`

    | Field                | Type     | Description                                                                                                                                                                 |
    | :------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `id`                 | Integer  | Unique identifier of the message, used as the primary key.                                                                                                                  |
    | `account_id`         | Integer  | Identifier of the Chatwoot account the record belongs to.                                                                                                                   |
    | `conversation_id`    | Integer  | Identifier of the conversation the message belongs to.                                                                                                                      |
    | `inbox_id`           | Integer  | Identifier of the inbox the message was exchanged in.                                                                                                                       |
    | `content`            | String   | Text body of the message.                                                                                                                                                   |
    | `message_type`       | String   | Direction of the message: 'incoming' (from the contact), 'outgoing' (from an agent or bot), 'activity' (a system note such as a status change) or 'template'.               |
    | `content_type`       | String   | How the message body should be rendered: 'text', 'input\_select', 'cards', 'form', 'article', 'incoming\_email', 'input\_csat' and others.                                  |
    | `status`             | String   | Delivery status of the message: 'sent', 'delivered', 'read' or 'failed'.                                                                                                    |
    | `private`            | Boolean  | Whether the message is a private note visible only to agents rather than a reply to the contact.                                                                            |
    | `created_at`         | Datetime | Timestamp when the message was created (UTC).                                                                                                                               |
    | `sender_id`          | Integer  | Identifier of the contact, agent or agent bot that sent the message.                                                                                                        |
    | `sender_type`        | String   | What kind of sender wrote the message: 'contact', 'user' (agent) or 'agent\_bot'. Empty for system activity messages.                                                       |
    | `sender_name`        | String   | Display name of the sender.                                                                                                                                                 |
    | `sender`             | String   | Full sender payload, as a JSON object — the shape depends on whether the sender is a contact, an agent or an agent bot.                                                     |
    | `source_id`          | String   | Identifier of the message in the origin channel, for example the provider's message id on WhatsApp or the Message-ID of an email.                                           |
    | `content_attributes` | String   | Structured payload attached to the message, as a JSON object — holds email headers, CSAT answers, the items of an interactive message and the details of system activities. |
    | `attachments`        | String   | Files sent with the message, as a JSON array of objects with the file type, size, extension and download URL.                                                               |
  </Accordion>

  <Accordion title="CSAT Survey Responses">
    Answers contacts gave to the satisfaction survey sent when a conversation is resolved (`GET /api/v1/accounts/{account_id}/csat_survey_responses`). Only inboxes with `csat_survey_enabled` produce rows.

    Primary key: `id` · Replication key: `created_at`

    | Field                          | Type     | Description                                                                                     |
    | :----------------------------- | :------- | :---------------------------------------------------------------------------------------------- |
    | `id`                           | Integer  | Unique identifier of the survey response, used as the primary key.                              |
    | `account_id`                   | Integer  | Identifier of the Chatwoot account the record belongs to.                                       |
    | `conversation_id`              | Integer  | Identifier of the conversation the survey was sent for.                                         |
    | `message_id`                   | Integer  | Identifier of the message that carried the survey.                                              |
    | `rating`                       | Integer  | Score the contact gave, from 1 (very poor) to 5 (excellent).                                    |
    | `feedback_message`             | String   | Free-text comment the contact left with the rating.                                             |
    | `created_at`                   | Datetime | Timestamp when the survey response was recorded (UTC), used as the incremental replication key. |
    | `contact_id`                   | Integer  | Identifier of the contact who answered the survey.                                              |
    | `contact_name`                 | String   | Display name of the contact who answered the survey.                                            |
    | `contact_email`                | String   | Email address of the contact who answered the survey.                                           |
    | `assigned_agent_id`            | Integer  | Identifier of the agent assigned to the rated conversation.                                     |
    | `assigned_agent_name`          | String   | Name of the agent assigned to the rated conversation.                                           |
    | `assigned_agent_email`         | String   | Email address of the agent assigned to the rated conversation.                                  |
    | `csat_review_notes`            | String   | Internal notes an agent added when reviewing the response.                                      |
    | `review_notes_updated_at`      | Datetime | Timestamp when the review notes were last edited (UTC).                                         |
    | `review_notes_updated_by_id`   | Integer  | Identifier of the agent who last edited the review notes.                                       |
    | `review_notes_updated_by_name` | String   | Name of the agent who last edited the review notes.                                             |
  </Accordion>
</AccordionGroup>

# Data Model

**Conversations** is the core entity: every conversation belongs to a contact and to an inbox, and carries the messages exchanged in it. Agents, teams and labels describe who handled the conversation and how it was classified.

```mermaid theme={null}
graph TD;
    subgraph "Conversations"
        Conversations("Conversations");
        Messages("Messages");
        Csat("CSAT Survey Responses");
    end

    subgraph "People"
        Contacts("Contacts");
        Agents("Agents");
        Teams("Teams");
        TeamMembers("Team Members");
    end

    subgraph "Configuration"
        Account("Account");
        Inboxes("Inboxes");
        InboxMembers("Inbox Members");
        Labels("Labels");
        CustomAttributes("Custom Attribute Definitions");
        CannedResponses("Canned Responses");
        AutomationRules("Automation Rules");
        AgentBots("Agent Bots");
    end

    Messages -- "conversation_id" --> Conversations;
    Csat -- "conversation_id" --> Conversations;
    Conversations -- "contact_id" --> Contacts;
    Conversations -- "inbox_id" --> Inboxes;
    Conversations -- "assignee_id" --> Agents;
    Conversations -- "team_id" --> Teams;
    Conversations -- "labels" --> Labels;
    Messages -- "sender_id" --> Contacts;
    TeamMembers -- "team_id" --> Teams;
    InboxMembers -- "inbox_id" --> Inboxes;
```

# Implementation Notes

### Incremental replication of conversations

Chatwoot offers no "modified since" filter on the conversations list, but it does return conversations sorted by last activity, newest first. An incremental extraction therefore reads from the most recent conversation and stops as soon as it walks past the point reached in the previous run. Because Chatwoot bumps `last_activity_at` on every change to a conversation — a new message, a status or assignee change, a label — no update is missed.

The **Messages** stream follows along: only the conversations that saw activity since the last run have their history re-read, and messages are matched on their identifier, so re-reading a conversation never duplicates rows.

### Timestamps and nested fields

* Chatwoot returns timestamps as Unix epochs and represents an absent timestamp as `0`. The connector converts them to proper datetimes in UTC and turns those zeros into empty values, so a conversation that was never opened by an agent shows an empty `agent_last_seen_at` rather than a date in 1970.
* Fields that hold a nested structure — `custom_attributes`, `additional_attributes`, `content_attributes`, `attachments`, `sender`, `working_hours` and others — are stored as **JSON strings**. Use your warehouse's JSON functions to read inside them. The `labels` field of a conversation is the exception: it is a plain array of label titles.
* `message_type` is translated from Chatwoot's internal number to its name: `incoming`, `outgoing`, `activity` or `template`.

### Credentials are never extracted

Chatwoot returns channel credentials to administrator tokens — IMAP and SMTP passwords, HMAC tokens, Twilio auth tokens and agent bot access tokens. None of them are part of the extracted schemas, so they never reach your Lakehouse.

### Rate limits

Chatwoot throttles requests per IP address (3000 requests per minute by default, configurable on self-hosted installations). The connector respects the limit, waits the interval Chatwoot asks for when it is reached, and retries automatically.
