{
  "schemaVersion": "1.0",
  "title": "Chatwoot conversations and messages",
  "description": "Use these 28 provider-catalogue capabilities to find conversations, change their state, manage routing metadata, and work with messages. Start by choosing the exact capability ID; three similar connector composites use different punctuation",
  "canonical": "https://getaip.org/docs/connectors/chatwoot/capabilities/conversations-and-messages",
  "route": "/docs/connectors/chatwoot/capabilities/conversations-and-messages",
  "source": "docs/connectors/chatwoot/capabilities/conversations-and-messages.md",
  "protocol": "Agent Interoperability Protocol",
  "protocolVersion": "1.0",
  "section": "Connectors",
  "documentType": "Connector",
  "language": "en",
  "downloads": {
    "md": "/docs/download/connectors/chatwoot/capabilities/conversations-and-messages.md",
    "txt": "/docs/download/connectors/chatwoot/capabilities/conversations-and-messages.txt",
    "json": "/docs/download/connectors/chatwoot/capabilities/conversations-and-messages.json",
    "pdf": "/docs/download/connectors/chatwoot/capabilities/conversations-and-messages.pdf"
  },
  "content": {
    "format": "text/markdown",
    "markdown": "---\ntitle: Chatwoot conversations and messages\ndescription: >-\n  Use 28 exact conversation and message capabilities with governed state\n  changes, bounded attachments, and unambiguous capability IDs\nkind: capability-reference\naudience: application-developer\nappliesTo: \"1.x\"\nwritingStandard: \"aip-docs/1.0\"\nlastReviewedRevision: \"97be86e9efedf07ecf1783b03800f683f107fb04\"\nconnector: chatwoot\ncapabilityIds:\n  - cap:chatwoot:conversation.list\n  - cap:chatwoot:conversation.create\n  - cap:chatwoot:conversation.get\n  - cap:chatwoot:conversation.update\n  - cap:chatwoot:conversation.delete\n  - cap:chatwoot:conversation.meta\n  - cap:chatwoot:conversation.search\n  - cap:chatwoot:conversation.unread_counts\n  - cap:chatwoot:conversation.filter\n  - cap:chatwoot:conversation.mute\n  - cap:chatwoot:conversation.unmute\n  - cap:chatwoot:conversation.transcript\n  - cap:chatwoot:conversation.priority\n  - cap:chatwoot:conversation.unread\n  - cap:chatwoot:conversation.custom_attributes\n  - cap:chatwoot:conversation.attachment.list\n  - cap:chatwoot:message.list\n  - cap:chatwoot:message.update\n  - cap:chatwoot:message.delete\n  - cap:chatwoot:message.translate\n  - cap:chatwoot:message.retry\n  - cap:chatwoot:conversation.assignment\n  - cap:chatwoot:conversation.label.list\n  - cap:chatwoot:conversation.label.update\n  - cap:chatwoot:conversation.toggle_status\n  - cap:chatwoot:conversation.toggle_typing\n  - cap:chatwoot:conversation.reporting_event.list\n  - cap:chatwoot:message.create\naliases:\n  - Chatwoot conversation capabilities\n  - Chatwoot message capabilities\n---\n\n# Chatwoot conversations and messages\n\nUse these 28 provider-catalogue capabilities to find conversations, change\ntheir state, manage routing metadata, and work with messages. Start by choosing\nthe exact capability ID; three similar connector composites use different\npunctuation and different contracts.\n\nThe connector inserts its configured Chatwoot account. Applications supply\nonly conversation, message, query, and provider-body values allowed by the\nselected operation.\n\n## Family at a glance\n\n| Group | Operations | Reads | Mutations | High risk |\n|---|---:|---:|---:|---:|\n| Core conversation records | 9 | 5 | 4 | 1 |\n| State, routing, and metadata | 13 | 3 | 10 | 0 |\n| Messages | 6 | 1 | 5 | 1 |\n| **Total** | **28** | **9** | **19** | **2** |\n\nThe method split is nine `GET`, 15 `POST`, two `PATCH`, and two `DELETE`\noperations. The nine reads are low risk, 17 mutations are medium risk, and the\ntwo deletes are high risk.\n\nTwenty-seven capabilities are Tools. `conversation.transcript` is a Workflow,\nbut its execution contract is still synchronous and has no async, streaming,\nor cancellation support.\n\n## Distinguish catalogue operations from composites\n\n| Provider-catalogue capability on this page | Similar connector composite | Important difference |\n|---|---|---|\n| `cap:chatwoot:message.create` | `cap:chatwoot:message:create` | Dot ID uses generic provider input and result; colon ID has strict connector-owned message fields |\n| `cap:chatwoot:conversation.toggle_status` | `cap:chatwoot:conversation:status` | Dot ID passes a generic provider body; colon ID accepts a strict status enum |\n| `cap:chatwoot:conversation.assignment` | `cap:chatwoot:conversation:handoff` | Dot ID calls the assignment route; colon ID can assign and add a private note |\n\nDo not normalize dots and colons. They are distinct capability IDs, and an\napproval or idempotency record for one does not authorize another.\n\n## Core conversation operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n|---|---|---|---|---|\n| `cap:chatwoot:conversation.list` | `GET /api/v1/accounts/{account_id}/conversations` | List conversations | Low | No |\n| `cap:chatwoot:conversation.create` | `POST /api/v1/accounts/{account_id}/conversations` | Create a conversation | Medium | Required |\n| `cap:chatwoot:conversation.get` | `GET /api/v1/accounts/{account_id}/conversations/{conversation_id}` | Read one conversation | Low | No |\n| `cap:chatwoot:conversation.update` | `PATCH /api/v1/accounts/{account_id}/conversations/{conversation_id}` | Update one conversation | Medium | Required |\n| `cap:chatwoot:conversation.delete` | `DELETE /api/v1/accounts/{account_id}/conversations/{conversation_id}` | Delete one conversation | High | Required |\n| `cap:chatwoot:conversation.meta` | `GET /api/v1/accounts/{account_id}/conversations/meta` | Read counters and metadata | Low | No |\n| `cap:chatwoot:conversation.search` | `GET /api/v1/accounts/{account_id}/conversations/search` | Search conversations | Low | No |\n| `cap:chatwoot:conversation.unread_counts` | `GET /api/v1/accounts/{account_id}/conversations/unread_counts` | Read unread counts | Low | No |\n| `cap:chatwoot:conversation.filter` | `POST /api/v1/accounts/{account_id}/conversations/filter` | Filter conversations | Medium | Required |\n\n`conversation.filter` has a read-like purpose but uses `POST`. The frozen\ncatalogue classifies every non-`GET` operation as a mutation. It therefore\nrequires approval and an idempotency key and does not advertise retry support.\n\n## State, routing, and metadata operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n|---|---|---|---|---|\n| `cap:chatwoot:conversation.mute` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/mute` | Mute a conversation | Medium | Required |\n| `cap:chatwoot:conversation.unmute` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/unmute` | Unmute a conversation | Medium | Required |\n| `cap:chatwoot:conversation.transcript` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/transcript` | Request a transcript | Medium | Required |\n| `cap:chatwoot:conversation.priority` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/toggle_priority` | Update priority | Medium | Required |\n| `cap:chatwoot:conversation.unread` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/unread` | Mark unread | Medium | Required |\n| `cap:chatwoot:conversation.custom_attributes` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/custom_attributes` | Update custom attributes | Medium | Required |\n| `cap:chatwoot:conversation.attachment.list` | `GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/attachments` | List attachments | Low | No |\n| `cap:chatwoot:conversation.assignment` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/assignments` | Assign an agent or team | Medium | Required |\n| `cap:chatwoot:conversation.label.list` | `GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/labels` | List applied labels | Low | No |\n| `cap:chatwoot:conversation.label.update` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/labels` | Replace applied labels | Medium | Required |\n| `cap:chatwoot:conversation.toggle_status` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/toggle_status` | Toggle provider status | Medium | Required |\n| `cap:chatwoot:conversation.toggle_typing` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/toggle_typing_status` | Publish typing state | Medium | Required |\n| `cap:chatwoot:conversation.reporting_event.list` | `GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/reporting_events` | List enterprise reporting events | Low | No |\n\nThe word `list` in `conversation.reporting_event.list` matches its `GET`\ncontract. The word `transcript` does not imply a background AIP run; this\nWorkflow completes through the same synchronous catalogue path.\n\nTyping state, labels, priority, assignment, and custom attributes can affect\ncustomer-service workflows. The generic contract marks only `write` and\n`external_network`, so policy must also inspect the exact capability and body.\n\n## Message operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n|---|---|---|---|---|\n| `cap:chatwoot:message.list` | `GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages` | List messages | Low | No |\n| `cap:chatwoot:message.update` | `PATCH /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages/{message_id}` | Update one message | Medium | Required |\n| `cap:chatwoot:message.delete` | `DELETE /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages/{message_id}` | Delete one message | High | Required |\n| `cap:chatwoot:message.translate` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages/{message_id}/translate` | Translate one message | Medium | Required |\n| `cap:chatwoot:message.retry` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages/{message_id}/retry` | Ask Chatwoot to retry a failed outgoing message | Medium | Required |\n| `cap:chatwoot:message.create` | `POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages` | Create a message with optional attachments | Medium | Required |\n\n`message.retry` is a provider operation, not permission for AIP to repeat the\nAction. Its own capability contract declares retry unsafe. Repeating it after\nan uncertain result can ask Chatwoot to process the failed message again.\n\n## Account and path inputs\n\nThe host inserts `account_id`. It is not a caller input.\n\n`conversation_id` is required by 22 operations. It is omitted only for:\n\n- `conversation.list`;\n- `conversation.create`;\n- `conversation.meta`;\n- `conversation.search`;\n- `conversation.unread_counts`;\n- `conversation.filter`.\n\n`message_id` is additionally required by `message.update`, `message.delete`,\n`message.translate`, and `message.retry`.\n\nEvery path input is a non-blank string of at most 512 bytes without control\ncharacters. Each value becomes one encoded URL segment.\n\n## Generic input envelope\n\nThe catalogue adds optional `query`, `body`, and `multipart` properties around\nthe required path IDs:\n\n| Property | Connector boundary |\n|---|---|\n| `query` | Object with at most 128 keys; scalar values or arrays of at most 256 scalars |\n| `body` | Object with at most 512 properties and a 16 MiB encoded limit |\n| `multipart.fields` | Object with at most 512 fields |\n| `multipart.files` | Array with at most 20 file objects |\n\n`body` and `multipart` are mutually exclusive. Provider-specific message,\nconversation, filter, assignment, label, status, and translation fields are\nnot frozen by this generic schema.\n\nAn input can satisfy the AIP schema and still be rejected by Chatwoot. Use the\npayload contract for the exact pinned provider route, then retain its canonical\nform with approval evidence.\n\n## Read one conversation\n\nUse a conversation ID obtained from the same account route:\n\n```sh\naipctl action call \\\n  \"$AIP_URL\" \\\n  cap:chatwoot:conversation.get \\\n  --action-id act_chatwoot_conversation_get_001 \\\n  --input '{\"conversation_id\":\"314\"}'\n```\n\nThe connector sends:\n\n```text\nGET /api/v1/accounts/{configured_account_id}/conversations/314\n```\n\nThis read needs no capability-level approval and advertises safe retry. Its\nresult can contain customer and message metadata, so the restricted-data and\nredaction contract still applies.\n\n## Create a message with an attachment\n\nThe pinned connector fixture exercises `cap:chatwoot:message.create` with this\nexact input shape:\n\n```json\n{\n  \"conversation_id\": \"conversation-1\",\n  \"multipart\": {\n    \"fields\": {\n      \"content\": \"Evidence attached\",\n      \"private\": false\n    },\n    \"files\": [\n      {\n        \"field_name\": \"attachments[]\",\n        \"filename\": \"evidence.txt\",\n        \"content_type\": \"text/plain\",\n        \"content_base64\": \"aGVsbG8=\"\n      }\n    ]\n  }\n}\n```\n\nThe fixture proves connector-side multipart encoding and allowlist\nenforcement. It does not prove that an unidentified Chatwoot version accepts\nthe same payload.\n\n### Multipart bounds\n\n| Value | Hard connector bound |\n|---|---:|\n| Files per request | 20 |\n| Decoded bytes per file | 25 MiB |\n| Combined field-value and decoded-file bytes | 64 MiB |\n| Serialized bytes per field value | 1 MiB |\n| Field name | 1–128 bytes; no control characters |\n| Filename | 1–255 bytes; basename only |\n| Content type | 1–255 bytes |\n\nEach file object must contain exactly `field_name`, `filename`,\n`content_type`, and standard-base64 `content_base64`. An empty multipart\nobject is rejected.\n\nSubmit the message mutation with a unique Action ID, exact approval, and one\nexternal-account-scoped idempotency key. The connector forwards\n`X-AIP-Action-ID` and `Idempotency-Key` to the provider.\n\n## Shared mutation contract\n\nAll 19 non-`GET` operations declare:\n\n| Contract field | Value |\n|---|---|\n| Approval | Required; tenant-policy selector |\n| Approval validity | 900,000 ms |\n| Approval evidence | Reason, input snapshot, policy decision |\n| Idempotency | Required; external-account scope; 86,400,000 ms published TTL |\n| Connector retry | Not supported; unsafe |\n| Side effects | `write`, `external_network` |\n| Data | Restricted; contains PII; redaction required |\n| Execution | Synchronous; no async, streaming, or cancellation support |\n| Compensation | Rollback not supported |\n\nThe connector forwards an idempotency key but does not prove provider\ndeduplication. Preserve one key only for the same capability, account, Action,\npath IDs, and canonical input.\n\n## Result contract\n\nA successful catalogue operation returns:\n\n```json\n{\n  \"http_status\": 200,\n  \"body\": {},\n  \"provider_request_id\": null\n}\n```\n\n`body` contains parsed JSON, `null` for an empty provider body, or a `text`\nwrapper for non-JSON bytes. `provider_request_id` reads `x-request-id` first\nand `x-runtime` second.\n\nThis generic result differs from the strict outputs of the three colon-named\ncomposites. Do not deserialize one as the other.\n\n## Failures and recovery\n\n| Failure code | Typical cause | Safe response |\n|---|---|---|\n| `connector.chatwoot.invalid_action` | Unknown or unadmitted ID, missing path input, conflicting body formats, or malformed multipart | Correct input or refresh discovery before dispatch |\n| `connector.chatwoot.missing_idempotency_key` | Non-`GET` Action has no valid key | Restore the key for the original intent |\n| `connector.chatwoot.authentication` | Provider returned `401` or `403` | Verify account binding and credential revision |\n| `connector.chatwoot.remote_rejected` | Chatwoot rejected input or state | Correct authoritative state before another Action |\n| `connector.chatwoot.remote_temporary` | Provider returned `429` or a server error | Retry a read within policy; reconcile a mutation |\n| `connector.chatwoot.transport` | Provider exchange failed | Retry a read within policy; treat a mutation as uncertain |\n| `connector.chatwoot.response_too_large` | Response exceeded the active bound | Preserve evidence and reconcile a mutation |\n\nConnector failures set `retryable: false`. Only the nine read contracts\nadvertise retry support.\n\nFor an uncertain create or update, search or read the target before submitting\na correction. For an uncertain delete, compare authoritative state and audit\nevidence. For an uncertain `message.retry` or `message.create`, inspect the\nconversation before risking duplicate customer-visible delivery.\n\nApproval and idempotency do not provide rollback. Corrective writes require a\nnew decision based on current Chatwoot state.\n\n## Verify an integration\n\nRequire all of the following:\n\n- discovery returns the exact dot-named catalogue capability;\n- the Action does not contain a caller-selected account ID;\n- conversation and message IDs belong to the configured account;\n- provider body fields match the pinned route;\n- every non-`GET` operation has exact approval and one retained key;\n- multipart content stays within every decoded and aggregate bound;\n- the completed result belongs to the original Action and preserves provider\n  status and request identity;\n- consequential mutations are confirmed through authoritative conversation\n  state;\n- restricted conversation, message, transcript, and attachment data is\n  redacted and retained under tenant policy;\n- uncertain mutations are reconciled instead of repeated.\n\nThese checks validate application behavior. They do not establish live\nChatwoot qualification or customer-delivery correctness.\n\n## Related documentation\n\n- [Chatwoot capability index](README.md)\n- [Accounts, agents, teams, and bots](accounts-agents-teams-and-bots.md)\n- [Run the Chatwoot connector quickstart](../getting-started/quickstart.md)\n- [Approvals and policy](../../../concepts/approvals-and-policy.md)\n- [Error reference](../../../reference/errors.md)\n",
    "text": "Chatwoot conversations and messages\n\nUse these 28 provider-catalogue capabilities to find conversations, change\ntheir state, manage routing metadata, and work with messages. Start by choosing\nthe exact capability ID; three similar connector composites use different\npunctuation and different contracts.\n\nThe connector inserts its configured Chatwoot account. Applications supply\nonly conversation, message, query, and provider-body values allowed by the\nselected operation.\n\nFamily at a glance\n\n| Group | Operations | Reads | Mutations | High risk |\n\n| Core conversation records | 9 | 5 | 4 | 1 |\n| State, routing, and metadata | 13 | 3 | 10 | 0 |\n| Messages | 6 | 1 | 5 | 1 |\n| Total | 28 | 9 | 19 | 2 |\n\nThe method split is nine GET, 15 POST, two PATCH, and two DELETE\noperations. The nine reads are low risk, 17 mutations are medium risk, and the\ntwo deletes are high risk.\n\nTwenty-seven capabilities are Tools. conversation.transcript is a Workflow,\nbut its execution contract is still synchronous and has no async, streaming,\nor cancellation support.\n\nDistinguish catalogue operations from composites\n\n| Provider-catalogue capability on this page | Similar connector composite | Important difference |\n\n| cap:chatwoot:message.create | cap:chatwoot:message:create | Dot ID uses generic provider input and result; colon ID has strict connector-owned message fields |\n| cap:chatwoot:conversation.togglestatus | cap:chatwoot:conversation:status | Dot ID passes a generic provider body; colon ID accepts a strict status enum |\n| cap:chatwoot:conversation.assignment | cap:chatwoot:conversation:handoff | Dot ID calls the assignment route; colon ID can assign and add a private note |\n\nDo not normalize dots and colons. They are distinct capability IDs, and an\napproval or idempotency record for one does not authorize another.\n\nCore conversation operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n\n| cap:chatwoot:conversation.list | GET /api/v1/accounts/{accountid}/conversations | List conversations | Low | No |\n| cap:chatwoot:conversation.create | POST /api/v1/accounts/{accountid}/conversations | Create a conversation | Medium | Required |\n| cap:chatwoot:conversation.get | GET /api/v1/accounts/{accountid}/conversations/{conversationid} | Read one conversation | Low | No |\n| cap:chatwoot:conversation.update | PATCH /api/v1/accounts/{accountid}/conversations/{conversationid} | Update one conversation | Medium | Required |\n| cap:chatwoot:conversation.delete | DELETE /api/v1/accounts/{accountid}/conversations/{conversationid} | Delete one conversation | High | Required |\n| cap:chatwoot:conversation.meta | GET /api/v1/accounts/{accountid}/conversations/meta | Read counters and metadata | Low | No |\n| cap:chatwoot:conversation.search | GET /api/v1/accounts/{accountid}/conversations/search | Search conversations | Low | No |\n| cap:chatwoot:conversation.unreadcounts | GET /api/v1/accounts/{accountid}/conversations/unreadcounts | Read unread counts | Low | No |\n| cap:chatwoot:conversation.filter | POST /api/v1/accounts/{accountid}/conversations/filter | Filter conversations | Medium | Required |\n\nconversation.filter has a read-like purpose but uses POST. The frozen\ncatalogue classifies every non-GET operation as a mutation. It therefore\nrequires approval and an idempotency key and does not advertise retry support.\n\nState, routing, and metadata operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n\n| cap:chatwoot:conversation.mute | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/mute | Mute a conversation | Medium | Required |\n| cap:chatwoot:conversation.unmute | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/unmute | Unmute a conversation | Medium | Required |\n| cap:chatwoot:conversation.transcript | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/transcript | Request a transcript | Medium | Required |\n| cap:chatwoot:conversation.priority | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/togglepriority | Update priority | Medium | Required |\n| cap:chatwoot:conversation.unread | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/unread | Mark unread | Medium | Required |\n| cap:chatwoot:conversation.customattributes | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/customattributes | Update custom attributes | Medium | Required |\n| cap:chatwoot:conversation.attachment.list | GET /api/v1/accounts/{accountid}/conversations/{conversationid}/attachments | List attachments | Low | No |\n| cap:chatwoot:conversation.assignment | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/assignments | Assign an agent or team | Medium | Required |\n| cap:chatwoot:conversation.label.list | GET /api/v1/accounts/{accountid}/conversations/{conversationid}/labels | List applied labels | Low | No |\n| cap:chatwoot:conversation.label.update | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/labels | Replace applied labels | Medium | Required |\n| cap:chatwoot:conversation.togglestatus | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/togglestatus | Toggle provider status | Medium | Required |\n| cap:chatwoot:conversation.toggletyping | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/toggletypingstatus | Publish typing state | Medium | Required |\n| cap:chatwoot:conversation.reportingevent.list | GET /api/v1/accounts/{accountid}/conversations/{conversationid}/reportingevents | List enterprise reporting events | Low | No |\n\nThe word list in conversation.reportingevent.list matches its GET\ncontract. The word transcript does not imply a background AIP run; this\nWorkflow completes through the same synchronous catalogue path.\n\nTyping state, labels, priority, assignment, and custom attributes can affect\ncustomer-service workflows. The generic contract marks only write and\nexternalnetwork, so policy must also inspect the exact capability and body.\n\nMessage operations\n\n| Capability | Provider request | Purpose | Risk | Approval |\n\n| cap:chatwoot:message.list | GET /api/v1/accounts/{accountid}/conversations/{conversationid}/messages | List messages | Low | No |\n| cap:chatwoot:message.update | PATCH /api/v1/accounts/{accountid}/conversations/{conversationid}/messages/{messageid} | Update one message | Medium | Required |\n| cap:chatwoot:message.delete | DELETE /api/v1/accounts/{accountid}/conversations/{conversationid}/messages/{messageid} | Delete one message | High | Required |\n| cap:chatwoot:message.translate | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/messages/{messageid}/translate | Translate one message | Medium | Required |\n| cap:chatwoot:message.retry | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/messages/{messageid}/retry | Ask Chatwoot to retry a failed outgoing message | Medium | Required |\n| cap:chatwoot:message.create | POST /api/v1/accounts/{accountid}/conversations/{conversationid}/messages | Create a message with optional attachments | Medium | Required |\n\nmessage.retry is a provider operation, not permission for AIP to repeat the\nAction. Its own capability contract declares retry unsafe. Repeating it after\nan uncertain result can ask Chatwoot to process the failed message again.\n\nAccount and path inputs\n\nThe host inserts accountid. It is not a caller input.\n\nconversationid is required by 22 operations. It is omitted only for:\n• conversation.list;\n• conversation.create;\n• conversation.meta;\n• conversation.search;\n• conversation.unreadcounts;\n• conversation.filter.\n\nmessageid is additionally required by message.update, message.delete,\nmessage.translate, and message.retry.\n\nEvery path input is a non-blank string of at most 512 bytes without control\ncharacters. Each value becomes one encoded URL segment.\n\nGeneric input envelope\n\nThe catalogue adds optional query, body, and multipart properties around\nthe required path IDs:\n\n| Property | Connector boundary |\n\n| query | Object with at most 128 keys; scalar values or arrays of at most 256 scalars |\n| body | Object with at most 512 properties and a 16 MiB encoded limit |\n| multipart.fields | Object with at most 512 fields |\n| multipart.files | Array with at most 20 file objects |\n\nbody and multipart are mutually exclusive. Provider-specific message,\nconversation, filter, assignment, label, status, and translation fields are\nnot frozen by this generic schema.\n\nAn input can satisfy the AIP schema and still be rejected by Chatwoot. Use the\npayload contract for the exact pinned provider route, then retain its canonical\nform with approval evidence.\n\nRead one conversation\n\nUse a conversation ID obtained from the same account route:\n\naipctl action call \\\n  \"$AIPURL\" \\\n  cap:chatwoot:conversation.get \\\n  --action-id actchatwootconversationget001 \\\n  --input '{\"conversationid\":\"314\"}'\n\nThe connector sends:\n\nGET /api/v1/accounts/{configuredaccountid}/conversations/314\n\nThis read needs no capability-level approval and advertises safe retry. Its\nresult can contain customer and message metadata, so the restricted-data and\nredaction contract still applies.\n\nCreate a message with an attachment\n\nThe pinned connector fixture exercises cap:chatwoot:message.create with this\nexact input shape:\n\n{\n  \"conversationid\": \"conversation-1\",\n  \"multipart\": {\n    \"fields\": {\n      \"content\": \"Evidence attached\",\n      \"private\": false\n    },\n    \"files\": [\n      {\n        \"fieldname\": \"attachments[]\",\n        \"filename\": \"evidence.txt\",\n        \"contenttype\": \"text/plain\",\n        \"contentbase64\": \"aGVsbG8=\"\n      }\n    ]\n  }\n}\n\nThe fixture proves connector-side multipart encoding and allowlist\nenforcement. It does not prove that an unidentified Chatwoot version accepts\nthe same payload.\n\nMultipart bounds\n\n| Value | Hard connector bound |\n\n| Files per request | 20 |\n| Decoded bytes per file | 25 MiB |\n| Combined field-value and decoded-file bytes | 64 MiB |\n| Serialized bytes per field value | 1 MiB |\n| Field name | 1–128 bytes; no control characters |\n| Filename | 1–255 bytes; basename only |\n| Content type | 1–255 bytes |\n\nEach file object must contain exactly fieldname, filename,\ncontenttype, and standard-base64 contentbase64. An empty multipart\nobject is rejected.\n\nSubmit the message mutation with a unique Action ID, exact approval, and one\nexternal-account-scoped idempotency key. The connector forwards\nX-AIP-Action-ID and Idempotency-Key to the provider.\n\nShared mutation contract\n\nAll 19 non-GET operations declare:\n\n| Contract field | Value |\n\n| Approval | Required; tenant-policy selector |\n| Approval validity | 900,000 ms |\n| Approval evidence | Reason, input snapshot, policy decision |\n| Idempotency | Required; external-account scope; 86,400,000 ms published TTL |\n| Connector retry | Not supported; unsafe |\n| Side effects | write, externalnetwork |\n| Data | Restricted; contains PII; redaction required |\n| Execution | Synchronous; no async, streaming, or cancellation support |\n| Compensation | Rollback not supported |\n\nThe connector forwards an idempotency key but does not prove provider\ndeduplication. Preserve one key only for the same capability, account, Action,\npath IDs, and canonical input.\n\nResult contract\n\nA successful catalogue operation returns:\n\n{\n  \"httpstatus\": 200,\n  \"body\": {},\n  \"providerrequestid\": null\n}\n\nbody contains parsed JSON, null for an empty provider body, or a text\nwrapper for non-JSON bytes. providerrequestid reads x-request-id first\nand x-runtime second.\n\nThis generic result differs from the strict outputs of the three colon-named\ncomposites. Do not deserialize one as the other.\n\nFailures and recovery\n\n| Failure code | Typical cause | Safe response |\n\n| connector.chatwoot.invalidaction | Unknown or unadmitted ID, missing path input, conflicting body formats, or malformed multipart | Correct input or refresh discovery before dispatch |\n| connector.chatwoot.missingidempotencykey | Non-GET Action has no valid key | Restore the key for the original intent |\n| connector.chatwoot.authentication | Provider returned 401 or 403 | Verify account binding and credential revision |\n| connector.chatwoot.remoterejected | Chatwoot rejected input or state | Correct authoritative state before another Action |\n| connector.chatwoot.remotetemporary | Provider returned 429 or a server error | Retry a read within policy; reconcile a mutation |\n| connector.chatwoot.transport | Provider exchange failed | Retry a read within policy; treat a mutation as uncertain |\n| connector.chatwoot.responsetoolarge | Response exceeded the active bound | Preserve evidence and reconcile a mutation |\n\nConnector failures set retryable: false. Only the nine read contracts\nadvertise retry support.\n\nFor an uncertain create or update, search or read the target before submitting\na correction. For an uncertain delete, compare authoritative state and audit\nevidence. For an uncertain message.retry or message.create, inspect the\nconversation before risking duplicate customer-visible delivery.\n\nApproval and idempotency do not provide rollback. Corrective writes require a\nnew decision based on current Chatwoot state.\n\nVerify an integration\n\nRequire all of the following:\n• discovery returns the exact dot-named catalogue capability;\n• the Action does not contain a caller-selected account ID;\n• conversation and message IDs belong to the configured account;\n• provider body fields match the pinned route;\n• every non-GET operation has exact approval and one retained key;\n• multipart content stays within every decoded and aggregate bound;\n• the completed result belongs to the original Action and preserves provider\n  status and request identity;\n• consequential mutations are confirmed through authoritative conversation\n  state;\n• restricted conversation, message, transcript, and attachment data is\n  redacted and retained under tenant policy;\n• uncertain mutations are reconciled instead of repeated.\n\nThese checks validate application behavior. They do not establish live\nChatwoot qualification or customer-delivery correctness.\n\nRelated documentation\n• Chatwoot capability index (README.md)\n• Accounts, agents, teams, and bots (accounts-agents-teams-and-bots.md)\n• Run the Chatwoot connector quickstart (../getting-started/quickstart.md)\n• Approvals and policy (../../../concepts/approvals-and-policy.md)\n• Error reference (../../../reference/errors.md)\n"
  },
  "integrity": {
    "algorithm": "sha256",
    "sourceDigest": "c662942bd8eea55feb8bc3600bf226f51f31685b4e8931ceaaa90f4ef0ddfb4b"
  }
}
