# Chatwoot Connector

The Chatwoot connector turns customer conversations into AIP channel events
and exposes governed actions for replies, conversation status, and human
handoff.

## Capability Surface

| Capability id | Effect | Retry contract |
|---|---|---|
| `cap:chatwoot:message:create` | Send a public or private conversation message | Unsafe to retry automatically |
| `cap:chatwoot:conversation:status` | Set `open`, `resolved`, or `pending` | Safe to retry |
| `cap:chatwoot:conversation:handoff` | Assign a conversation and optionally add a private note | Unsafe to retry automatically |

All three operations require AIP approval and an external-account-scoped
idempotency key. Contracts mark customer and contact data as restricted,
PII-bearing, and subject to redaction.

## Inbound Webhooks

The frozen ingestion boundary accepts an exact `ChatwootWebhookDelivery` with:

- `X-Chatwoot-Delivery` as the delivery identity;
- `X-Chatwoot-Timestamp` within a five-minute window;
- `X-Chatwoot-Signature` as HMAC-SHA256 over the exact raw body;
- the original UTF-8 body without JSON reserialization.

Replay admission happens only after signature and timestamp verification. The
file replay store is suitable for one process; active-active deployments need
an atomic database uniqueness boundary.

The constructor permits omitting a webhook secret for mapping tests. A
production host must call `with_webhook_security` and fail startup when the
secret or durable replay store is unavailable; otherwise inbound deliveries
are not authenticated.

Outbound messages add an AIP action marker to Chatwoot content attributes.
Inbound mapping ignores those marked deliveries to prevent response loops.

## Deployment Boundary

`aip-connector-chatwoot` is an embeddable connector crate. The stock `aipd`
1.0 binary does not provide Chatwoot CLI options or an HTTP webhook route for
it. A deployment host must:

1. construct `ChatwootConnector` with the base URL, account id, and secret API
   token;
2. require webhook verification and a durable replay store;
3. register its discovered capabilities and frozen handlers with the AIP
   gateway;
4. expose an ingress route that preserves the exact signed body and headers;
5. bind the connector to trusted tenant and credential policy.

Do not expose a generic JSON endpoint that parses and reserializes the webhook
before verification.

## Runtime Behavior

The connector implements discovery, health, inbound, channel, outbound, and
frozen connector boundaries. Provider failures become typed connector errors.
It does not advertise provider cancellation, streaming, transactions,
reconciliation, compensation, or connector-owned credential handles.

A cancelled local request before provider completion is an uncertain outcome,
not proof that Chatwoot did not mutate.

## Qualification Boundary

Deterministic unit and contract tests cover mapping, signatures, replay
storage, loop prevention, capabilities, and error behavior. A complete retained
isolated-live campaign against a pinned Chatwoot deployment is not present.
Production promotion therefore requires exact-version webhook, retry, restart,
tenant-isolation, load, and external-observation evidence.

See [Build a Connector](../guides/build-a-connector.md),
[Conformance and Qualification](../reference/conformance.md), and
[Pinned Upstream Baselines](upstream-baselines.md).
