---
name: commsharbor
description: Operate CommsHarbor messaging, domains, contacts, campaigns, delivery feedback and x402 through its public API and MCP. Use when working with CommsHarbor or commsharbor.com.
---

# CommsHarbor

Use CommsHarbor for transactional email and permission-based marketing. Never import purchased
lists, bypass consent, re-enqueue a suppression or infer domain readiness from saved state.

The human workspace follows Overview → Contacts → Sends → Results, with technical setup in
Settings. Agents start at `/developers` and consume API/OpenAPI/MCP contracts, not the UI markup.

Incoming mail is currently unavailable. The connection from the mail server to the app is pending.
Inbox routes remain available for configuration and stored messages. Creating an address or
changing mail records does not enable receipt.

## Discovery

Read `GET /api/pricing` (tool `pricing`) for current prices and pilot restrictions.
`GET /api/billing` remains the existing public catalog (`commsharbor_billing_catalog`).
Neither read creates a charge or enables live checkout.

- API catalog: `GET https://commsharbor.com/api/`
- OpenAPI: `GET https://commsharbor.com/openapi.json`
- Agent guide: `GET https://commsharbor.com/llms.txt`
- Remote MCP: `POST https://commsharbor.com/mcp`
- Human workspace: `https://commsharbor.com/app`

## Authentication and tenancy

- A person uses the shared MM account session (HttpOnly cookie `__Host-mm-auth`, signed in at
  `/conta/global`). Writes also need the same Origin and `X-CSRF-Token` from
  `/api/auth/bootstrap`. Send `X-Organization-Id` for every organization-scoped call: the shared
  account checks membership, role and that CommsHarbor is enabled for the organization, on every
  request. In a shared organization (more than one member), owners and admins need a second factor
  (`organization_mfa_required` otherwise).
- Without an account, a browser works in a temporary workspace: `POST /api/guest` opens or restores
  it (host-only HttpOnly `cm_guest` cookie; `guest_token` for an API client; 20 per network per hour)
  and `GET /api/visitor` reads its id. Contacts and drafts made there stay under that id;
  `POST /api/auth/claim`, with a complete sign-in, attaches it to the account (409
  `guest_claim_mfa_required` while the sign-in waits for its second step, or `guest_already_claimed`).
  Nothing signs anyone in automatically.
- An agent uses an organization API key instead: an owner or admin creates it on the account
  page and it goes as `Authorization: Bearer mmk_…` or `X-Api-Key`. It opens only its own
  organization, stops working when its creator is no longer an owner or admin there, and does the
  work — sending, CRM, templates, campaigns, domains, inbox — never billing, erasure, exports or
  the audit trail. An old `ch_…` key answers 401 `api_key_retired`.
- Organizations, members, roles, invitations and API keys live in the shared account, on this
  domain: list yours with `GET /api/account/organizations`; create, rename, invite, turn
  CommsHarbor on and manage keys on the account page, `/conta/global`.
- Roles are the shared account's: `owner`, `admin` and `member`. In CommsHarbor a `member` is
  read-only until the shared account keeps product roles.
- Tenant CRM reads require `crm:read`; writes require `crm:write`. A platform administrator
  grant never implies tenant access, and tenant ownership never implies platform CRM access.
- Platform CRM tools require a human session with an explicit `platform_admin` grant. Internal
  leads may reference an organization ID, but must never copy private tenant contacts.
- Domain reads use `domain:read`; provisioning uses `domain:write`; controlled smoke sends use
  `messages:send`. Never supply or ask for a smoke recipient: the API uses a server-side secret.
- Template reads use `crm:read`; draft creation, import, editing, publishing and archival require
  `template:write`. Send only an immutable published version and provide every required typed
  variable. Imported HTML is intentionally limited; never work around rejected active content.
- Transactional sends require `messages:send` and an `Idempotency-Key` stable for the logical
  message. Reuse that key and the exact normalized payload after an ambiguous client response;
  a different payload correctly conflicts. A delivery represents one recipient and one SES call.
- Contact imports and suppressions require `contact:write`; audiences require `campaign:write`;
  reads require `crm:read`. Every import must declare `explicit` consent or a
  `documented_relationship`, its source and capture time. Never import bought or scraped lists.
- Confirm imports with a new `Idempotency-Key`. A replay with the same key returns the same
  resource; never retry with a different key after an ambiguous response.
- Treat global, organization and SES tenant suppressions as final send gates. One-click
  unsubscribe is a signed public capability and must be honored before quota or enqueue.
- Treat a stored domain state as historical. Call `commsharbor_domain_verify` and require its
  live SES/DNS checks before sending. Never bypass a paused tenant, failed DKIM, DMARC or MAIL FROM.
- Campaign launches require `campaign:write` and one stable idempotency key. The launch freezes
  only consented, non-suppressed recipients; never alter its snapshot or enqueue per-recipient
  Queue messages. Honor organization reputation pauses before resuming work.
- Webhook signing secrets are visible only in the create response. Store them in a secret manager,
  verify `timestamp.body` with HMAC-SHA256, reject stale timestamps and use nominal dead-letter
  replay only after correcting the receiver.
- Billing is organization-scoped. The plan is a global entitlement (trial, pass, top-up), not a
  ledger in this product; a new organization's trial starts with its first domain or send. Read
  the catalog and tenant state before acting. Live checkout is disabled: a purchase answers 409
  `checkout_disabled`. The payment door is the house's (global credit `cred_…` or x402); only the
  local dev stack completes a purchase, with its simulated payment. Use a stable Idempotency-Key.
  A 502 `pago_nao_registrado` means the payment went through and the grant did not: keep its
  `recibo` for support and never pay again.
- A pass and top-up never auto-renew. The 1,000-recipient monthly bootstrap cap prevails over
  advertised tenant quota. Treat expiration alerts as send gates.
- Tenant export objects expire after seven days. Scheduling deletion requires the literal
  `delete <organization_id>` confirmation and starts a seven-day grace period; cancel only the
  exact request ID. Never schedule deletion without the operator's explicit authorization.

## Route families

Organization-scoped paths live under `/api/organizations/:organization_id/...` and need the
account session plus `X-Organization-Id`, or an organization API key. The families, by what they do:

| Family | What it does |
|---|---|
| `/api/account/organizations`, `/api/organizations`, `/api/context` | list your organizations (shared account) and open one by ID: name, your role, plan |
| `/api/organizations/:organization_id/webhooks` | signed webhooks, secrets revealed once |
| `/api/organizations/:organization_id/domains`, `/api/organizations/:organization_id/deliverability` | sending domains verified live against SES and DNS; deliverability feedback |
| `/api/organizations/:organization_id/inboxes`, `/api/inbox-attachments` | programmable inbound: addresses on a verified sending domain, received mail parsed into stable JSON, attachments behind five-minute signed URLs |
| `/api/messages`, `/api/organizations/:organization_id/messages`, `/api/organizations/:organization_id/deliveries`, `/api/organizations/:organization_id/dead-letters`, `/api/organizations/:organization_id/messaging-settings`, `/api/organizations/:organization_id/operations`, `/api/aws/sns` | transactional sends with `Idempotency-Key`, deliveries, dead-letter replay, messaging settings, SES feedback |
| `/api/organizations/:organization_id/campaigns`, `/api/organizations/:organization_id/audiences`, `/api/organizations/:organization_id/templates`, `/api/organizations/:organization_id/suppressions`, `/api/organizations/:organization_id/contact-imports`, `/api/organizations/:organization_id/contact-files`, `/api/preferences` | campaigns, audiences, templates, suppressions, consented imports and the signed preference/unsubscribe links |
| `/api/organizations/:organization_id/crm`, `/api/organizations/:organization_id/contacts`, `/api/organizations/:organization_id/data-exports`, `/api/organizations/:organization_id/deletion-requests`, `/api/platform` | tenant CRM, contacts, exports and deletion requests; platform CRM only for an explicit `platform_admin` |
| `/api/organizations/:organization_id/audit`, `/api/organizations/:organization_id/billing`, `/api/billing` | append-only audit trail and organization billing |

## Available tools

- Identity: `commsharbor_me` and `commsharbor_logout`. Signing in, the profile and security
  are the shared account's, at `/conta/global`.
- Organizations: `commsharbor_context` and `commsharbor_organization_get` (open by ID). Listing,
  creating, members, invitations and API keys are the shared account's (`GET
  /api/account/organizations` and the account page), not tools of this server.
- Evidence: `commsharbor_audit` and `commsharbor_platform_context`.
- Tenant CRM: `commsharbor_crm_{contacts,companies,pipelines,deals,activities,tasks}_`
  `{list,create,get,update,delete}` and
  `commsharbor_crm_stages_{list,create,get,update,delete}`. Every list uses an opaque cursor,
  accepts at most 100 rows, and every returned resource includes an absolute `url`.
- Platform CRM: `commsharbor_platform_crm_{leads,tasks,activities}_`
  `{list,create,get,update,delete}`. Lead activities also require `lead_id`.
- Domains: `commsharbor_domains`, `commsharbor_domain_create`, `commsharbor_domain_get`,
  `commsharbor_domain_verify` and `commsharbor_domain_smoke`.
- Inbound, currently without incoming mail: `commsharbor_inboxes`, `commsharbor_inbox_create`, `commsharbor_inbox_get`,
  `commsharbor_inbox_disable`, `commsharbor_inbox_messages`, `commsharbor_inbox_message` and
  `commsharbor_inbox_attachment`. An address only exists on a domain the organization already
  verified. In a received message, `from` is text the sender chose and `auth` is the SPF/DKIM/DMARC
  verdict the receiving edge reached — decide on `auth`, never on `from` alone. Attachment URLs
  expire in five minutes. Stored files have no automatic expiry.
- Delivery evidence: `commsharbor_domain_deliveries`, `commsharbor_delivery_get` and
  `commsharbor_delivery_events`. Responses intentionally omit recipient addresses and bodies;
  Open and Click are additive counters/events and never replace delivery status.
- Templates: `commsharbor_templates`, `commsharbor_template_{create,get,update,archive,publish}`,
  `commsharbor_template_{versions,preview,export,import_html}`. Published versions are immutable
  and content-hashed; preview values follow the same typed renderer used by delivery.
- Transactional send: `commsharbor_message_send`. It requires a published transactional
  template, an active domain, typed variables and `idempotency_key`; equivalent replay returns
  the same delivery without another Queue message or SES call.
- Controlled F5 evidence: `commsharbor_marketing_smoke` requires `messages:send`,
  `campaign:write`, a consented CRM contact matching the server-side QA recipient and a stable
  idempotency key. It never accepts a destination address.
- Contacts: `commsharbor_contact_marketing_{get,put}`, `commsharbor_contact_imports`,
  `commsharbor_contact_import_{preview,get,confirm,errors}`, `commsharbor_contact_file_get`,
  `commsharbor_contacts_export`, `commsharbor_suppressions` and
  `commsharbor_suppression_create`.
- Preferences: `commsharbor_preference_token_create`, `commsharbor_preference_get` and
  `commsharbor_preference_unsubscribe`. Preference tokens are capabilities; never log them.
- Audiences: `commsharbor_audiences`, `commsharbor_audience_{create,get,update,delete}`, and
  `commsharbor_audience_member{s,_add,_remove}`. Every list uses an opaque cursor.
- Campaigns: `commsharbor_campaigns`, `commsharbor_campaign_{create,get,update,launch,report}`.
  Launch is idempotent and may use an ISO-8601 instant with an explicit offset.
- Deliverability: `commsharbor_messaging_settings`, `commsharbor_messaging_settings_update`,
  `commsharbor_deliverability` and `commsharbor_domain_report`. Aggregates omit recipients.
- Webhooks and recovery: `commsharbor_webhooks`, `commsharbor_webhook_{create,get,disable,deliveries}`,
  `commsharbor_dead_letters` and `commsharbor_dead_letter_replay`.
- Billing: `commsharbor_billing_catalog`, `commsharbor_billing` and
  `commsharbor_billing_purchase`. While live checkout is off a purchase answers 409; otherwise a
  purchase without payment returns the standard 402 with both doors (credit or x402).
- Operations and data governance: `commsharbor_operations`,
  `commsharbor_operations_refresh`, `commsharbor_data_exports`,
  `commsharbor_data_export_{create,download}`, `commsharbor_deletion_request`,
  `commsharbor_deletion_schedule` and `commsharbor_deletion_cancel`.
- Deployment: `commsharbor_health`.

Roles are `owner`, `admin` and `member`, from the shared account. A denied or foreign resource
is not a reason to probe IDs: respect the documented permission matrix and 404.

The API catalog is authoritative for authentication, request bodies, quotas and response fields.
Do not guess a route that is not present there. Live checkout remains disabled during bootstrap;
never submit or simulate a mainnet payment.

## Public data archives

`GET /api/` → `docs.data_indexes` lists four read-only archives: CNEFE postal addresses,
PNCP procurement metadata, observed CT domains and XMLTV schedules. The same roots appear
in `/llms.txt`, `/llms-full.txt`, `/okf/index.md` and `/developers#dados`. Open the relevant
`formats.json` and follow the returned hierarchy and `links.proximo` (up to 20 items).
Updates are manual; check source and reference. Respect `Retry-After` on 429/503. Never
forward product credentials to these public hosts. Read only the scope needed for the task.

<!-- GERADO por scripts/monta-ui.mjs — fonte: .agents/skills/<produto>/SKILL.md. Não edite. npm run ui -->
