
{"name":"CommsHarbor","description":"Transactional email and permission-based marketing infrastructure.","build":"67e71a51","environment":"production","base_url":"https://commsharbor.com","docs":{"llms":"https://commsharbor.com/llms.txt","llms_full":"https://commsharbor.com/llms-full.txt","openapi":"https://commsharbor.com/openapi.json","mcp":"https://commsharbor.com/mcp","pricing":"https://commsharbor.com/api/pricing","billing":"https://commsharbor.com/api/billing","human_ui":"https://commsharbor.com/","data_indexes":[{"id":"cep","produto":"https://pontofato.com","caminho":"/enderecos","title":"Postal codes and addresses","description":"IBGE, CNEFE 2022: observed addresses; not a current postal-code certification.","hierarchy":"State → municipality → locality → street → addresses","url":"https://pontofato.com/enderecos/","formats":{"html":"https://pontofato.com/enderecos/","json":"https://pontofato.com/enderecos/index.json","md":"https://pontofato.com/enderecos/index.md","okf":"https://pontofato.com/enderecos/index.okf.md"},"llms":"https://pontofato.com/enderecos/llms.txt","openapi":"https://pontofato.com/enderecos/openapi.json","mcp":"https://pontofato.com/enderecos/mcp","okf":"https://pontofato.com/enderecos/okf/index.md","access":"public-read-only","pagination":{"max_items":20,"next":"links.proximo"},"updates":"manual"},{"id":"editais","produto":"https://editalmd.com","caminho":"/licitacoes","title":"Public procurement","description":"PNCP: collected procurement metadata. Documents and their access terms belong to EditalMD.","hierarchy":"Procedure → state → year → month → day → municipality → purchases","url":"https://editalmd.com/licitacoes/","formats":{"html":"https://editalmd.com/licitacoes/","json":"https://editalmd.com/licitacoes/index.json","md":"https://editalmd.com/licitacoes/index.md","okf":"https://editalmd.com/licitacoes/index.okf.md"},"llms":"https://editalmd.com/licitacoes/llms.txt","openapi":"https://editalmd.com/licitacoes/openapi.json","mcp":"https://editalmd.com/licitacoes/mcp","okf":"https://editalmd.com/licitacoes/okf/index.md","access":"public-read-only","pagination":{"max_items":20,"next":"links.proximo"},"updates":"manual"}]},"auth":{"credito":"Prepaid credit token in `Authorization: Bearer cred_…` (or the `X-Credito` header). Not an account: it is a bearer of balance.","none":"Public endpoint. No tenant data is returned.","session":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied.","organization":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization.","organization_template_write":"Active organization identity with template:write permission.","organization_messages_send":"Active organization identity with messages:send permission. Idempotency-Key is mandatory.","organization_campaign_write":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key.","organization_admin":"Human organization member with the required role; API keys cannot manage credentials or membership.","platform_admin":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access.","aws_sns":"Amazon SNS signature, regional certificate URL and the exact configured TopicArn. This callback never accepts a user credential.","inbox_attachment_capability":"Signed, expiring capability scoped to one attachment of one message of one organization. It carries no login and grants nothing else.","preference_capability":"Signed, expiring capability scoped to one organization and contact. No login is required and no email address is embedded in the token."},"endpoints":[{"method":"GET","path":"/agent.json","auth":"none","summary":"Agent card: identity, operator, documentation, the MCP endpoint and the tools it serves. Same document as `/.well-known/agent-card.json`.","grupo":"Discovery","retorno":{"_texto":"`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`."},"exemplo":"curl -s $ORIGIN/agent.json","returns":"`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` and `skills[]`.","url":"https://commsharbor.com/agent.json","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/okf/:arquivo","auth":"none","summary":"OKF bundle (Open Knowledge Format v0.1): markdown with frontmatter so an agent reads the whole product without parsing HTML.","grupo":"Discovery","params":{"arquivo":{"desc":"`index.md`, `sobre.md`, `api.md` or `faq.md`.","exemplo":"index.md"}},"retorno":{"_texto":"`text/markdown`. Start at `/okf/index.md`, which lists the bundle."},"erros":{"404":"File outside the bundle."},"exemplo":"curl -s $ORIGIN/okf/index.md","returns":"`text/markdown`. Start at `/okf/index.md`, which lists the bundle.","url":"https://commsharbor.com/okf/:arquivo","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/.well-known/:arquivo","auth":"none","summary":"Machine discovery before the home page: `api-catalog` (RFC 9727, a linkset with the API and the MCP), `security.txt` (RFC 9116), `x402` (payment manifest: network, wallet and the routes that charge) and `mcp-registry-auth` (the official MCP registry key).","grupo":"Discovery","params":{"arquivo":{"desc":"`api-catalog`, `security.txt`, `x402`, `mcp-registry-auth` or `apis.json`.","exemplo":"api-catalog"}},"retorno":{"_texto":"`application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two."},"erros":{"404":"Name outside the five published."},"exemplo":"curl -s $ORIGIN/.well-known/api-catalog","returns":"`application/linkset+json` for the api-catalog; `application/json` for x402 and apis.json; `text/plain` for the other two.","url":"https://commsharbor.com/.well-known/:arquivo","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/apis.json","auth":"none","summary":"APIs.json (apisjson.org, 0.19): the index APIs.io harvests — the API, the MCP, OpenAPI, guide and OKF bundle in one file. Also at `/.well-known/apis.json`.","grupo":"Discovery","retorno":{"_texto":"`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`."},"exemplo":"curl -s $ORIGIN/apis.json","returns":"`application/json` in the APIs.json 0.19 format: `apis[]` with `baseURL`, `humanURL` and `properties[]`.","url":"https://commsharbor.com/apis.json","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/","auth":"none","grupo":"Discovery","summary":"Discover the whole API: every endpoint, every auth mode and the MCP endpoint.","retorno":"ApiIndex","returns":"{ name, description, build, environment, base_url, docs, auth, endpoints, mcp, mcp_tools }","url":"https://commsharbor.com/api/","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/health","auth":"none","grupo":"Discovery","summary":"Read liveness, environment and the commit currently deployed.","desc":"Smoke tests wait for their own commit to appear here instead of racing edge propagation.","retorno":"Health","returns":"{ ok, app, build, environment, timestamp }","url":"https://commsharbor.com/api/health","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/mcp","auth":"none","grupo":"Discovery","summary":"Inspect the remote MCP server card: transport, protocol and tool count.","desc":"`POST /mcp` speaks Streamable HTTP with JSON-RPC 2.0. The tools are the operations in this catalog; the MCP has no backend of its own.","retorno":{"transport":{"tipo":"string","desc":"How the server speaks — `streamable-http`."},"protocol_version":{"tipo":"string","desc":"MCP protocol version the server implements."},"endpoint":{"tipo":"string","desc":"Absolute URL to POST JSON-RPC to."},"server":{"tipo":"object","desc":"`name` and `version` of this server; the version is the deployed commit."},"tools":{"tipo":"int","desc":"How many tools the server exposes."},"usage":{"tipo":"string","desc":"One line saying how to call it."},"api_index":{"tipo":"string","desc":"The self-describing API index, for the operations behind the tools."}},"returns":"{ transport, protocol_version, endpoint, server, tools, usage, api_index }","url":"https://commsharbor.com/mcp","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/auth/bootstrap","auth":"none","grupo":"Account","summary":"Prepare the browser for global sign-in.","desc":"Sets a host-only HttpOnly browser cookie. CSRF is bound to the current session. No CORS.","retorno":{"csrf":{"tipo":"string","desc":"X-CSRF-Token"},"context":{"tipo":"string","desc":"Opaque view context, also in X-MM-Context; not a credential / contexto opaco da vista, não é credencial."}},"erros":{"400":"invalid_request / invalid_callback","403":"invalid_origin / invalid_csrf","503":"auth_unavailable: a sessão anterior é preservada / the previous session is preserved"},"returns":"{ csrf, context }","url":"https://commsharbor.com/api/auth/bootstrap","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"POST","path":"/api/auth/login","auth":"none","grupo":"Account","summary":"Start global sign-in; follow the returned redirect in this browser.","desc":"Requires bootstrap cookie, same-origin Origin and X-CSRF-Token. No credentials in the product.","corpo":{"returnTo":{"tipo":"string","obrigatorio":true,"desc":"Relative local path / caminho local relativo."}},"body":{"returnTo":"/"},"exemplo":"// Execute no console da página do produto / Run in the product page console.\n(async () => {\n  const origin = \"$ORIGIN\";\n  const {csrf} = await fetch(origin + \"/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(origin + \"/api/auth/login\", {\n    method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({returnTo: \"/\"})\n  });\n  if (!r.ok) throw new Error(\"Auth HTTP \" + r.status);\n  location.assign((await r.json()).redirect);\n})();","exemploLinguagem":"js","retorno":{"redirect":{"tipo":"string","desc":"Global issuer / emissor global."}},"erros":{"400":"invalid_request / invalid_callback","403":"invalid_origin / invalid_csrf","503":"auth_unavailable: a sessão anterior é preservada / the previous session is preserved"},"returns":"{ redirect }","url":"https://commsharbor.com/api/auth/login","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/auth/callback","auth":"none","grupo":"Account","statusOk":303,"summary":"Backend callback for global sign-in.","desc":"Not an agent tool. Requires the original browser flow; validates state, PKCE, nonce and signature.","retorno":{"_texto":"303 Location; Set-Cookie HttpOnly. No tokens in JSON / sem tokens em JSON."},"erros":{"400":"invalid_request / invalid_callback","403":"invalid_origin / invalid_csrf","503":"auth_unavailable: a sessão anterior é preservada / the previous session is preserved"},"returns":"303 Location; Set-Cookie HttpOnly. No tokens in JSON / sem tokens em JSON.","url":"https://commsharbor.com/api/auth/callback","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/account/profile","auth":"session","grupo":"Account","exemplo":"await fetch(\"$ORIGIN/api/account/profile\", {credentials: \"same-origin\"}).then(r => r.json());","exemploLinguagem":"js","summary":"Read your global profile.","desc":"Reads current preferences from the issuer. Edit them on your account; products never own a separate profile.","retorno":{"_texto":"{profile:{name,locale,timeZone,theme,revision}}"},"erros":{"401":"invalid_session","503":"auth_unavailable"},"returns":"{profile:{name,locale,timeZone,theme,revision}}","url":"https://commsharbor.com/api/account/profile","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/account/avatar","auth":"session","grupo":"Account","exemplo":"await fetch(\"$ORIGIN/api/account/avatar\", {credentials: \"same-origin\"}).then(r => {if (!r.ok) throw new Error(\"HTTP \" + r.status); return r.blob();});","exemploLinguagem":"js","summary":"Read your global profile photo.","desc":"Private WebP, up to 64 KiB, no cache. Change it on your account. No user ID or object URL accepted.","retorno":{"_texto":"image/webp; Cache-Control: no-store"},"erros":{"401":"invalid_session","404":"not_found: no photo / sem foto","503":"auth_unavailable"},"returns":"image/webp; Cache-Control: no-store","url":"https://commsharbor.com/api/account/avatar","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"POST","path":"/api/auth/logout","auth":"session","grupo":"Account","exemplo":"// Execute no console da página do produto / Run in the product page console.\n(async () => {\n  const origin = \"$ORIGIN\";\n  const {csrf} = await fetch(origin + \"/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(origin + \"/api/auth/logout\", {\n    method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({})\n  });\n  if (!r.ok) throw new Error(\"Auth HTTP \" + r.status);\n  return r.json();\n})();","exemploLinguagem":"js","summary":"Revoke this product session.","desc":"Bootstrap/CSRF must belong to this browser and session. Other product sessions remain active.","retorno":{"ok":{"tipo":"bool","desc":"true"}},"erros":{"400":"invalid_request / invalid_callback","403":"invalid_origin / invalid_csrf","503":"auth_unavailable: a sessão anterior é preservada / the previous session is preserved"},"returns":"{ ok }","url":"https://commsharbor.com/api/auth/logout","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/account/activation","auth":"session","grupo":"Account","exemplo":"await fetch(\"$ORIGIN/api/account/activation\", {credentials: \"same-origin\"}).then(r => r.json());","exemploLinguagem":"js","summary":"Whether this global account still has to be activated in this product.","desc":"Read-only: creates nothing. `existing` says a local history with the same verified e-mail is waiting to be linked.","retorno":{"required":{"tipo":"bool","desc":"true while there is no local user linked."},"userId":{"tipo":"string","desc":"The local user, when already linked.","opcional":true},"existing":{"tipo":"bool","desc":"A local history with this e-mail exists.","opcional":true},"email":{"tipo":"string","desc":"The verified e-mail of the global account.","opcional":true}},"erros":{"401":"invalid_session","503":"auth_unavailable"},"returns":"{ required, userId?, existing?, email? }","url":"https://commsharbor.com/api/account/activation","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"POST","path":"/api/account/activation","auth":"session","grupo":"Account","summary":"Activate the global account in this product: new local user, or link the existing history.","desc":"Idempotent by requestId. Linking an existing history requires the same verified e-mail (recent e-mail sign-in) or the legacy session token; IDs and trial dates are preserved. Bootstrap/CSRF of this browser required.","corpo":{"requestId":{"tipo":"string","obrigatorio":true,"desc":"UUID v4 chosen by the client; repeating it repeats the answer."},"linkExisting":{"tipo":"bool","obrigatorio":true,"desc":"Confirm the link when `existing` is true."},"legacyToken":{"tipo":"string","nulo":true,"desc":"Old `sess_…` token of this product, when the browser still has one."}},"body":{"requestId":"6b3b2c1e-8f4a-4c6e-9a1d-2f7c1b9e5d10","linkExisting":false,"legacyToken":null},"exemplo":"(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/activation\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({requestId: crypto.randomUUID(), linkExisting: false, legacyToken: null})});\n  return r.json();\n})();","exemploLinguagem":"js","retorno":{"ok":{"tipo":"bool","desc":"true"},"userId":{"tipo":"string","desc":"The local user now linked."}},"erros":{"400":"invalid_product_link","401":"invalid_session","403":"product_email_proof_required / legacy_proof_invalid","409":"product_link_confirmation_required / legacy_identity_ambiguous / product_link_conflict_or_limit","503":"auth_unavailable"},"returns":"{ ok, userId }","url":"https://commsharbor.com/api/account/activation","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/me","auth":"session","grupo":"Account","summary":"Read the global profile, every membership and the platform role, if any.","desc":"This is how a client discovers which organizations it may pass in `X-Organization-Id`. `user.id` is the local user linked to the global account.","retorno":{"user":{"tipo":"User","desc":"The person behind the session."},"profile":{"tipo":"Profile","desc":"Global MM profile — it belongs to the person, edited on the account, not to a tenant."},"organizations":{"tipo":"Organization[]","desc":"Every organization this person belongs to."},"platform_role":{"tipo":"string","desc":"Platform role, when one was explicitly granted. Owning a tenant grants nothing here.","nulo":true}},"erros":{"401":"No session, or the session expired.","409":"product_activation_required: activate CommsHarbor at `/conta/global`.","503":"auth_unavailable"},"exemplo":"await fetch(\"$ORIGIN/api/me\", {credentials: \"same-origin\"}).then(r => r.json());","exemploLinguagem":"js","returns":"{ user{id,email}, profile{name,locale,timeZone,theme,revision}, organizations[{id,name,sending_domain,created_at}], platform_role }","url":"https://commsharbor.com/api/me","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/organizations","auth":"session","grupo":"Organizations","summary":"List the organizations the current person belongs to.","retorno":{"organizations":{"tipo":"Organization[]","desc":"Every organization with a membership for this person."}},"erros":{"401":"No session, or the session expired."},"exemplo":"curl -s $ORIGIN/api/organizations -H \"Authorization: Bearer $TOKEN\"","returns":"{ organizations[{id,name,sending_domain,created_at}] }","url":"https://commsharbor.com/api/organizations","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"POST","path":"/api/organizations","auth":"session","grupo":"Organizations","summary":"Create one organization trial for a verified owner and a sending domain.","desc":"One trial per owner. The domain is registered here but not verified — DNS state is only ever observed, in the domains resource. The platform's own organization is the one exception: it is not a trial, it does not consume the owner's trial, and it exists at most once.","corpo":{"name":{"tipo":"string","desc":"Display name of the organization.","obrigatorio":true},"sending_domain":{"tipo":"string","desc":"Domain the organization will send from.","obrigatorio":true}},"body":{"name":"Acme","sending_domain":"example.com"},"retorno":"Organization","erros":{"400":"Missing name or domain.","401":"No session, or the session expired.","409":"This owner already has a trial organization, or the organization already exists."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"name\":\"Acme\",\"sending_domain\":\"example.com\"}'","returns":"{ id, name, sending_domain, created_at }","url":"https://commsharbor.com/api/organizations","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/context","auth":"organization","grupo":"Organizations","summary":"Resolve which organization and role the current credential is acting as.","desc":"Read this before a write when you are not certain which tenant is active. Guessing is how data lands in the wrong organization.","headers":{"X-Organization-Id":{"tipo":"string","desc":"Which organization to act in. Required with a human session; an API key determines its own and rejects a conflicting value.","obrigatorio":true}},"retorno":"Identity","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/context -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ kind, organizationId, userId?, email?, sessionId?, role?, organization?, apiKeyId?, scopes? }","url":"https://commsharbor.com/api/context","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id","auth":"organization","grupo":"Organizations","summary":"Read one organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Organization","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, sending_domain, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id","auth":"organization_admin","grupo":"Organizations","summary":"Update an organization's name.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"New display name.","obrigatorio":true}},"body":{"name":"Acme Global"},"retorno":"Organization","erros":{"400":"Empty name.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"name\":\"Acme Global\"}'","returns":"{ id, name, sending_domain, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/members","auth":"organization","grupo":"Organizations","summary":"List the members of an organization and their roles.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"members":{"tipo":"Membership[]","desc":"Every member and the role they hold."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/members -H \"Authorization: Bearer $TOKEN\"","returns":"{ members[{organization_id,user_id,role,created_at}] }","url":"https://commsharbor.com/api/organizations/:organization_id/members","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/members/:user_id","auth":"organization_admin","grupo":"Organizations","summary":"Change the role of a member who is not the owner.","desc":"The owner's role cannot be changed through this route — an organization that can lose its last owner is an organization nobody can administer.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"user_id":{"desc":"Member user ID, as returned by the members listing."}},"corpo":{"role":{"tipo":"string","desc":"Role to give the member from now on.","valores":["admin","marketer","viewer"],"obrigatorio":true}},"body":{"role":"marketer"},"retorno":"Membership","erros":{"400":"Unknown role.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG/members/$USER -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"role\":\"marketer\"}'","returns":"{ organization_id, user_id, role, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/members/:user_id","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/invitations","auth":"organization_admin","grupo":"Organizations","summary":"List invitations without their tokens.","desc":"The token is shown once, when the invitation is created. Listing never shows it again.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"invitations":{"tipo":"Invitation[]","desc":"Invitations for this organization, without tokens."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/invitations -H \"Authorization: Bearer $TOKEN\"","returns":"{ invitations[{id,email,role,expires_at,invitation_token?,token_notice?}] }","url":"https://commsharbor.com/api/organizations/:organization_id/invitations","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/invitations","auth":"organization_admin","grupo":"Organizations","summary":"Create an invitation and reveal its token exactly once.","desc":"Store the token now: this is the only response that carries it.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"email":{"tipo":"string","desc":"Who to invite.","obrigatorio":true},"role":{"tipo":"string","desc":"Role the invitation grants.","valores":["admin","marketer","viewer"],"obrigatorio":true}},"body":{"email":"member@example.com","role":"viewer"},"retorno":"Invitation","erros":{"400":"Missing email or unknown role.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/invitations -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"email\":\"member@example.com\",\"role\":\"viewer\"}'","returns":"{ id, email, role, expires_at, invitation_token?, token_notice? }","url":"https://commsharbor.com/api/organizations/:organization_id/invitations","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/invitations/accept","auth":"session","grupo":"Organizations","summary":"Accept an invitation and join the organization it points at.","desc":"Accepting joins an EXISTING organization trial. It never creates one, so an invitation cannot be used to mint tenants.","corpo":{"token":{"tipo":"string","desc":"The invitation token, from the response that created it.","obrigatorio":true}},"body":{"token":"invite_…"},"retorno":"Membership","erros":{"400":"Missing token.","401":"No session, or the session expired.","404":"Unknown, expired or already used invitation."},"exemplo":"curl -s -XPOST $ORIGIN/api/invitations/accept -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"token\":\"invite_…\"}'","returns":"{ organization_id, user_id, role, created_at }","url":"https://commsharbor.com/api/invitations/accept","auth_detail":"Global account: HttpOnly cookie `__Host-mm-session-commsharbor-web` (sign in at `/conta/global`); writes need the same Origin and `X-CSRF-Token` from `/api/auth/bootstrap`. No organization is implied."},{"method":"GET","path":"/api/organizations/:organization_id/api-keys","auth":"organization_admin","grupo":"Credentials","summary":"List API keys without token hashes or secrets.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"api_keys":{"tipo":"ApiKey[]","desc":"Keys of this organization, without the tokens."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/api-keys -H \"Authorization: Bearer $TOKEN\"","returns":"{ api_keys[{id,name,scopes,prefix,last_used_at,revoked_at,created_at,token?}] }","url":"https://commsharbor.com/api/organizations/:organization_id/api-keys","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/api-keys","auth":"organization_admin","grupo":"Credentials","summary":"Create a scoped API key and reveal it exactly once.","desc":"The key determines its own organization. It cannot manage credentials or membership — those stay with human admins.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Label so the key can be recognised later.","obrigatorio":true},"scopes":{"tipo":"string[]","desc":"What the key may do, e.g. `organization:read`, `crm:write`, `messages:send`.","obrigatorio":true}},"body":{"name":"Automation","scopes":["organization:read","crm:read","crm:write"]},"retorno":"ApiKey","erros":{"400":"Missing name or unknown scope.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/api-keys -H \"Authorization: Bearer $TOKEN\" -H 'content-type: application/json' -d '{\"name\":\"Automation\",\"scopes\":[\"crm:read\"]}'","returns":"{ id, name, scopes, prefix, last_used_at, revoked_at, created_at, token? }","url":"https://commsharbor.com/api/organizations/:organization_id/api-keys","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"DELETE","path":"/api/organizations/:organization_id/api-keys/:api_key_id","auth":"organization_admin","grupo":"Credentials","summary":"Revoke an API key. It stops working immediately, not at the next cache expiry.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"api_key_id":{"desc":"API key ID from the key listing. The token itself is never returned again."}},"retorno":"ApiKey","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/api-keys/$KEY -H \"Authorization: Bearer $TOKEN\"","returns":"{ id, name, scopes, prefix, last_used_at, revoked_at, created_at, token? }","url":"https://commsharbor.com/api/organizations/:organization_id/api-keys/:api_key_id","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/audit","auth":"organization_admin","grupo":"Credentials","summary":"List the append-only audit trail of the organization.","desc":"Audit records are never rewritten and never carry recipient PII.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"PageCamel<AuditEvent>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s '$ORIGIN/api/organizations/$ORG/audit?limit=20' -H \"Authorization: Bearer $TOKEN\"","returns":"{ items[{id,action,actor_user_id,target,metadata,created_at}], nextCursor }","url":"https://commsharbor.com/api/organizations/:organization_id/audit","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/platform/context","auth":"platform_admin","grupo":"Credentials","summary":"Confirm an explicitly granted platform administrator.","desc":"Tenant ownership grants nothing here: platform access is a separate, explicit grant.","retorno":{"role":{"tipo":"string","desc":"The platform role that was granted."},"user_id":{"tipo":"string","desc":"Who holds it."}},"erros":{"401":"No session.","403":"This person has no platform grant."},"exemplo":"curl -s $ORIGIN/api/platform/context -H \"Authorization: Bearer $TOKEN\"","returns":"{ role, user_id }","url":"https://commsharbor.com/api/platform/context","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/organizations/:organization_id/domains","auth":"organization","grupo":"Domains","summary":"List the sending domains of the organization and their last observed state.","desc":"`status` is what was last OBSERVED at SES and DNS. It does not become `active` because provisioning was requested.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Lista<Domain>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/domains -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,domain,status,dkim_tokens,dmarc,mail_from,last_observed_at,created_at}] }","url":"https://commsharbor.com/api/organizations/:organization_id/domains","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/domains","auth":"organization","grupo":"Domains","summary":"Register the organization's sending domain and queue idempotent SES provisioning.","desc":"Asking twice does not provision twice. Publish the returned DKIM records, then call `verify` to have the state observed.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"domain":{"tipo":"string","desc":"The domain to send from, e.g. `example.com`.","obrigatorio":true}},"body":{"domain":"example.com"},"retorno":{"domain":{"tipo":"Domain","desc":"The registered domain, with the DKIM records to publish."},"provisioning":{"tipo":"Provisioning","desc":"Whether this call enqueued provisioning work."}},"erros":{"400":"Missing or malformed domain.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/domains -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"domain\":\"example.com\"}'","returns":"{ domain{id,domain,status,dkim_tokens,dmarc,mail_from,last_observed_at,created_at}, provisioning{queued,job_id} }","url":"https://commsharbor.com/api/organizations/:organization_id/domains","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/domains/:domain_id","auth":"organization","grupo":"Domains","summary":"Read one sending domain, without inferring current DNS state.","desc":"This returns what was stored at the last observation. To look again, call `verify`.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"retorno":"Domain","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/domains/$DOMAIN -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, domain, status, dkim_tokens, dmarc, mail_from, last_observed_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/domains/:domain_id/verify","auth":"organization","grupo":"Domains","summary":"Observe SES, DKIM, DMARC and custom MAIL FROM state right now, and store what was seen.","desc":"This is the ONLY operation that can move a domain to `active`, and only because it actually looked.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"body":{},"retorno":"Domain","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/domains/$DOMAIN/verify -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ id, domain, status, dkim_tokens, dmarc, mail_from, last_observed_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id/verify","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/domains/:domain_id/smoke","auth":"organization","grupo":"Domains","summary":"Queue one controlled smoke message to the server-side QA recipient.","desc":"The request never accepts a recipient: the destination is a server-side secret. That is what keeps this from becoming a way to send mail to arbitrary addresses through someone else's verified domain.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"body":{},"retorno":{"delivery":{"tipo":"Delivery","desc":"The delivery record for the smoke."},"capacity":{"tipo":"Capacity","desc":"What is left to send after it."},"dispatch":{"tipo":"Dispatch","desc":"The queue work behind it."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The domain is not active yet — verify it first.","429":"No capacity left."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/domains/$DOMAIN/smoke -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ delivery{id,status,domain_id,template_id,template_version,ses_message_id,created_at}, capacity{remaining,global_remaining,hard_cap}, dispatch{queued,job_id} }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id/smoke","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/domains/:domain_id/deliveries","auth":"organization","grupo":"Deliveries","summary":"List deliveries sent from one domain, without recipient addresses.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"retorno":"Lista<Delivery>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/domains/$DOMAIN/deliveries -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,status,domain_id,template_id,template_version,ses_message_id,created_at}] }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id/deliveries","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/deliveries/:delivery_id","auth":"organization","grupo":"Deliveries","summary":"Read one delivery and its SES MessageId, without recipient data.","desc":"`ses_message_id` is what correlates this record with AWS when you need to chase a message there.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"delivery_id":{"desc":"Delivery ID returned when the message was queued."}},"retorno":"Delivery","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/deliveries/$DELIVERY -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, status, domain_id, template_id, template_version, ses_message_id, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/deliveries/:delivery_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/deliveries/:delivery_id/events","auth":"organization","grupo":"Deliveries","summary":"List the normalized SES feedback events for one delivery.","desc":"Open and Click are ADDITIVE: they are recorded alongside delivery state and never overwrite it.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"delivery_id":{"desc":"Delivery ID returned when the message was queued."}},"retorno":"Lista<DeliveryEvent>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/deliveries/$DELIVERY/events -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,event_type,occurred_at,detail}] }","url":"https://commsharbor.com/api/organizations/:organization_id/deliveries/:delivery_id/events","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/aws/sns","auth":"aws_sns","grupo":"Deliveries","summary":"Receive a signed Amazon SNS callback for the configured SES topic.","desc":"This callback never accepts a user credential. It requires a valid SNS signature, a certificate URL in the expected AWS region, and the exact configured TopicArn — anything else is rejected before the body is read.","retorno":{"_texto":"`204 No Content` when the notification was accepted."},"erros":{"400":"Malformed notification, or a certificate URL outside the expected region.","403":"Bad signature, or a TopicArn other than the configured one."},"exemplo":"# Amazon SNS posts this; a hand-made call is rejected at the signature check.\ncurl -s -XPOST $ORIGIN/api/aws/sns -H 'x-amz-sns-message-type: Notification' -H 'content-type: text/plain; charset=UTF-8' -d '{\"Type\":\"Notification\",\"TopicArn\":\"arn:aws:sns:…\",\"Signature\":\"…\",\"SigningCertURL\":\"https://sns.<region>.amazonaws.com/…\",\"Message\":\"{…SES event…}\"}'","returns":"`204 No Content` when the notification was accepted.","url":"https://commsharbor.com/api/aws/sns","auth_detail":"Amazon SNS signature, regional certificate URL and the exact configured TopicArn. This callback never accepts a user credential."},{"method":"GET","path":"/api/organizations/:organization_id/tracking-domain","auth":"organization","grupo":"Domains","summary":"Read the organization's tracking domain and the CNAME it needs.","desc":"`null` when the organization has none — then every link falls back to the platform origin.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"TrackingDomain","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/tracking-domain -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ organization_id, domain, state, checks, dns_record, last_checked_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/tracking-domain","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/tracking-domain","auth":"organization","grupo":"Domains","summary":"Register the host that will serve this organization's message links.","desc":"One per organization, and the host is unique across the platform — two tenants claiming the same name would make link routing ambiguous. Registering does not activate: publish the CNAME, then call `verify`.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"domain":{"tipo":"string","desc":"The tracking host, e.g. `links.example.com`.","obrigatorio":true}},"body":{"domain":"links.example.com"},"retorno":"TrackingDomain","erros":{"400":"Missing or malformed domain.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"This organization already has a tracking domain, or the host belongs to another one."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/tracking-domain -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"domain\":\"links.example.com\"}'","returns":"{ organization_id, domain, state, checks, dns_record, last_checked_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/tracking-domain","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/tracking-domain/verify","auth":"organization","grupo":"Domains","summary":"Probe the host right now and store what was seen.","desc":"The only operation that can move a tracking domain to `active`, and it does so only after reaching this product's own health endpoint ON that host. A host that used to answer and stopped becomes `failed`, and links go back to the platform origin immediately.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"body":{},"retorno":"TrackingDomain","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/tracking-domain/verify -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ organization_id, domain, state, checks, dns_record, last_checked_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/tracking-domain/verify","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/tracking-domain","auth":"organization","grupo":"Domains","summary":"Remove the tracking domain and send links back to the platform origin.","desc":"Links already sent keep pointing at the removed host: this stops NEW messages, not old ones.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"removed":{"tipo":"bool","desc":"Always true when it existed."},"domain":{"tipo":"string","desc":"The host that was removed."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/tracking-domain -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ removed, domain }","url":"https://commsharbor.com/api/organizations/:organization_id/tracking-domain","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/inboxes","auth":"organization","grupo":"Inbound","summary":"List the addresses this organization receives on.","desc":"Up to 100, newest first. A disabled address stays listed: its history is still readable.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Inbox[]","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/inboxes -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, local_part, domain, address, status, created_at, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/inboxes","auth":"organization","grupo":"Inbound","summary":"Create an address on a verified sending domain.","desc":"The domain must already be `verified` or `active` here — receiving on an unproven domain is relay. For mail to actually arrive, the domain's MX must point at this platform's inbound; until it does, the address exists and simply receives nothing.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"local_part":{"tipo":"string","desc":"What comes before the `@`: lowercase letters, digits and `._+-`, 1 to 64 characters.","obrigatorio":true},"domain":{"tipo":"string","desc":"A sending domain of this organization.","obrigatorio":true}},"body":{"local_part":"support","domain":"example.com"},"retorno":"Inbox","erros":{"400":"The local part is not a valid mailbox name.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"That address already exists.","422":"The sending domain is not registered or not verified yet; the message names it."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/inboxes -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"local_part\":\"support\",\"domain\":\"example.com\"}'","returns":"{ id, local_part, domain, address, status, created_at, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/inboxes/:inbox_id","auth":"organization","grupo":"Inbound","summary":"Read one receiving address and whether it is still accepting mail.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"inbox_id":{"desc":"Receiving address ID, from the inboxes listing."}},"retorno":"Inbox","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/inboxes/$INBOX -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, local_part, domain, address, status, created_at, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes/:inbox_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/inboxes/:inbox_id","auth":"organization","grupo":"Inbound","summary":"Stop accepting mail at this address.","desc":"Disables, never erases: mail already received stays readable, because it is the customer's data and losing it is not a cleanup. New mail to the address is dropped and counted.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"inbox_id":{"desc":"Receiving address ID, from the inboxes listing."}},"retorno":"Inbox","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/inboxes/$INBOX -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, local_part, domain, address, status, created_at, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes/:inbox_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/inboxes/:inbox_id/messages","auth":"organization","grupo":"Inbound","summary":"List what arrived, newest first.","desc":"Summaries only — no body. Read one message to get its text, HTML and headers.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"inbox_id":{"desc":"Receiving address ID, from the inboxes listing."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"colecao":"InboxMessageSummary","retorno":"Page<InboxMessageSummary>","erros":{"400":"Invalid cursor.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/inboxes/$INBOX/messages?limit=20 -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,inbox_id,message_id,from,to,subject,size_bytes,parse_state,attachments,received_at}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes/:inbox_id/messages","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/inboxes/:inbox_id/messages/:message_id","auth":"organization","grupo":"Inbound","summary":"Read one message with body, chosen headers and the sender's authentication result.","desc":"`auth` is what the receiving edge concluded about SPF, DKIM and DMARC. Treat `from` as text the sender chose: `auth` is the part that was checked.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"inbox_id":{"desc":"Receiving address ID, from the inboxes listing."},"message_id":{"desc":"Inbox message ID, as this product assigned it — not the sender's `Message-ID` header."}},"retorno":"InboxMessage","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/inboxes/$INBOX/messages/$MESSAGE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, inbox_id, message_id, from, to, subject, size_bytes, parse_state, attachments[{index,filename,content_type,disposition,byte_size}], received_at, text, html, headers, auth, parse_reason }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes/:inbox_id/messages/:message_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/inboxes/:inbox_id/messages/:message_id/attachments/:index","auth":"organization","grupo":"Inbound","summary":"Get a short-lived signed URL for one attachment.","desc":"Two steps on purpose: the URL is what travels to a browser, an agent or a chat, never your credential. It expires in five minutes; the stored object does not expire at all.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"inbox_id":{"desc":"Receiving address ID, from the inboxes listing."},"message_id":{"desc":"Inbox message ID, as this product assigned it — not the sender's `Message-ID` header."},"index":{"desc":"Attachment position inside the message, as listed in `attachments`."}},"retorno":"InboxAttachmentLink","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/inboxes/$INBOX/messages/$MESSAGE/attachments/0 -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ filename, content_type, byte_size, url, expires_at }","url":"https://commsharbor.com/api/organizations/:organization_id/inboxes/:inbox_id/messages/:message_id/attachments/:index","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/inbox-attachments/:token","auth":"inbox_attachment_capability","grupo":"Inbound","summary":"Download the attachment bytes with a signed capability.","desc":"The token carries organization, message and index, so no path from the request ever reaches storage. Expired tokens answer 410 — ask the attachment route for a fresh one.","params":{"token":{"desc":"Signed capability from the attachment route. It is scoped to one attachment and expires."}},"retorno":{"_texto":"The attachment bytes, with the sender's declared `content-type`, `nosniff` and `content-disposition: attachment`. There is no JSON envelope: the body is the file."},"erros":{"401":"The capability is malformed or its signature does not verify. This route accepts no session and no API key — the token is the whole credential.","404":"The capability verifies, but that attachment is not there — including a token signed for another organization.","410":"The capability expired. Ask the attachment route for a fresh one."},"exemplo":"curl -s $ORIGIN/api/inbox-attachments/$TOKEN --output anexo.bin","returns":"The attachment bytes, with the sender's declared `content-type`, `nosniff` and `content-disposition: attachment`. There is no JSON envelope: the body is the file.","url":"https://commsharbor.com/api/inbox-attachments/:token","auth_detail":"Signed, expiring capability scoped to one attachment of one message of one organization. It carries no login and grants nothing else."},{"method":"GET","path":"/api/organizations/:organization_id/crm/contacts","auth":"organization","grupo":"CRM","summary":"List contacts in the tenant CRM — a person in the tenant CRM.","desc":"Being in the CRM is not permission to email: consent lives in the `marketing` sub-resource.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"company_id":{"tipo":"string","desc":"Restrict to one CRM company."}},"retorno":"Page<Contact>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/contacts -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,email,first_name,last_name,company_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/contacts","auth":"organization","grupo":"CRM","summary":"Create a contact in the tenant CRM.","desc":"Being in the CRM is not permission to email: consent lives in the `marketing` sub-resource.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"email":{"tipo":"string","desc":"Email address. Normalized and never truncated.","obrigatorio":true},"first_name":{"tipo":"string","desc":"Given name of the contact.","obrigatorio":true},"last_name":{"tipo":"string","desc":"Family name."},"company_id":{"tipo":"string","desc":"Company this contact belongs to."}},"body":{"email":"buyer@example.com","first_name":"Buyer","company_id":"co_…"},"retorno":"Contact","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/contacts -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"email\":\"buyer@example.com\",\"first_name\":\"Buyer\",\"company_id\":\"co_…\"}'","returns":"{ id, email, first_name, last_name, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/contacts/:contact_id","auth":"organization","grupo":"CRM","summary":"Read one contact from the tenant CRM.","desc":"Being in the CRM is not permission to email: consent lives in the `marketing` sub-resource.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"retorno":"Contact","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/contacts/contact_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, email, first_name, last_name, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/contacts/:contact_id","auth":"organization","grupo":"CRM","summary":"Update one contact in the tenant CRM. Only the fields you send change.","desc":"Being in the CRM is not permission to email: consent lives in the `marketing` sub-resource.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"corpo":{"email":{"tipo":"string","desc":"Email address. Normalized and never truncated.","obrigatorio":true},"first_name":{"tipo":"string","desc":"Given name of the contact.","obrigatorio":true},"last_name":{"tipo":"string","desc":"Family name."},"company_id":{"tipo":"string","desc":"Company this contact belongs to."}},"body":{"email":"buyer@example.com","first_name":"Buyer","company_id":"co_…"},"retorno":"Contact","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/contacts/contact_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"email\":\"buyer@example.com\",\"first_name\":\"Buyer\",\"company_id\":\"co_…\"}'","returns":"{ id, email, first_name, last_name, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/contacts/:contact_id","auth":"organization","grupo":"CRM","summary":"Delete one contact from the tenant CRM. The response carries the record as it was.","desc":"Being in the CRM is not permission to email: consent lives in the `marketing` sub-resource.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"retorno":"Contact","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/contacts/contact_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, email, first_name, last_name, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/companies","auth":"organization","grupo":"CRM","summary":"List companies in the tenant CRM — an organization in the tenant CRM — a customer of the customer.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."}},"retorno":"Page<Company>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/companies -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,name,domain,website,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/companies","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/companies","auth":"organization","grupo":"CRM","summary":"Create a company in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Company name.","obrigatorio":true},"domain":{"tipo":"string","desc":"Primary domain, used to group contacts."},"website":{"tipo":"string","desc":"Website URL."}},"body":{"name":"Acme","domain":"example.com","website":"https://example.com"},"retorno":"Company","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/companies -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Acme\",\"domain\":\"example.com\",\"website\":\"https://example.com\"}'","returns":"{ id, name, domain, website, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/companies","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/companies/:company_id","auth":"organization","grupo":"CRM","summary":"Read one company from the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"company_id":{"desc":"CRM company ID inside the active organization."}},"retorno":"Company","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/companies/company_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, domain, website, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/companies/:company_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/companies/:company_id","auth":"organization","grupo":"CRM","summary":"Update one company in the tenant CRM. Only the fields you send change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"company_id":{"desc":"CRM company ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"Company name.","obrigatorio":true},"domain":{"tipo":"string","desc":"Primary domain, used to group contacts."},"website":{"tipo":"string","desc":"Website URL."}},"body":{"name":"Acme","domain":"example.com","website":"https://example.com"},"retorno":"Company","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/companies/company_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Acme\",\"domain\":\"example.com\",\"website\":\"https://example.com\"}'","returns":"{ id, name, domain, website, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/companies/:company_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/companies/:company_id","auth":"organization","grupo":"CRM","summary":"Delete one company from the tenant CRM. The response carries the record as it was.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"company_id":{"desc":"CRM company ID inside the active organization."}},"retorno":"Company","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/companies/company_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, domain, website, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/companies/:company_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/pipelines","auth":"organization","grupo":"CRM","summary":"List pipelines in the tenant CRM — a named sequence of stages that deals move through.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."}},"retorno":"Page<Pipeline>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/pipelines -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,name,created_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/pipelines","auth":"organization","grupo":"CRM","summary":"Create a pipeline in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Pipeline name.","obrigatorio":true},"stages":{"tipo":"string[]","desc":"Stage names to create with the pipeline, in order."}},"body":{"name":"Sales","stages":["New","Proposal","Won"]},"retorno":"Pipeline","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/pipelines -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Sales\",\"stages\":[\"New\",\"Proposal\",\"Won\"]}'","returns":"{ id, name, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth":"organization","grupo":"CRM","summary":"Read one pipeline from the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."}},"retorno":"Pipeline","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth":"organization","grupo":"CRM","summary":"Update one pipeline in the tenant CRM. Only the fields you send change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"Pipeline name.","obrigatorio":true},"stages":{"tipo":"string[]","desc":"Stage names to create with the pipeline, in order."}},"body":{"name":"Sales","stages":["New","Proposal","Won"]},"retorno":"Pipeline","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Sales\",\"stages\":[\"New\",\"Proposal\",\"Won\"]}'","returns":"{ id, name, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth":"organization","grupo":"CRM","summary":"Delete one pipeline from the tenant CRM. The response carries the record as it was.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."}},"retorno":"Pipeline","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/deals","auth":"organization","grupo":"CRM","summary":"List deals in the tenant CRM — an opportunity moving through a pipeline.","desc":"Money is in minor units: `value_minor: 10000` with `currency: \"USD\"` is $100.00, not $10,000.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"pipeline_id":{"tipo":"string","desc":"Restrict to one pipeline."},"stage_id":{"tipo":"string","desc":"Restrict to one pipeline stage."},"status":{"tipo":"string","desc":"Restrict to one status value."}},"retorno":"Page<Deal>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/deals -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,title,pipeline_id,stage_id,status,value_minor,currency,contact_id,company_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/deals","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/deals","auth":"organization","grupo":"CRM","summary":"Create a deal in the tenant CRM.","desc":"Money is in minor units: `value_minor: 10000` with `currency: \"USD\"` is $100.00, not $10,000.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"title":{"tipo":"string","desc":"What the deal is.","obrigatorio":true},"pipeline_id":{"tipo":"string","desc":"Pipeline the deal lives in.","obrigatorio":true},"stage_id":{"tipo":"string","desc":"Stage the deal is at.","obrigatorio":true},"value_minor":{"tipo":"int","desc":"Value in the currency's MINOR unit — cents, not dollars."},"currency":{"tipo":"string","desc":"ISO 4217 code for `value_minor`."}},"body":{"title":"Renewal","pipeline_id":"pl_…","stage_id":"st_…","value_minor":10000,"currency":"USD"},"retorno":"Deal","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/deals -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Renewal\",\"pipeline_id\":\"pl_…\",\"stage_id\":\"st_…\",\"value_minor\":10000,\"currency\":\"USD\"}'","returns":"{ id, title, pipeline_id, stage_id, status, value_minor, currency, contact_id, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/deals","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/deals/:deal_id","auth":"organization","grupo":"CRM","summary":"Read one deal from the tenant CRM.","desc":"Money is in minor units: `value_minor: 10000` with `currency: \"USD\"` is $100.00, not $10,000.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"deal_id":{"desc":"CRM deal ID inside the active organization."}},"retorno":"Deal","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/deals/deal_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, pipeline_id, stage_id, status, value_minor, currency, contact_id, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/deals/:deal_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/deals/:deal_id","auth":"organization","grupo":"CRM","summary":"Update one deal in the tenant CRM. Only the fields you send change.","desc":"Money is in minor units: `value_minor: 10000` with `currency: \"USD\"` is $100.00, not $10,000.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"deal_id":{"desc":"CRM deal ID inside the active organization."}},"corpo":{"title":{"tipo":"string","desc":"What the deal is.","obrigatorio":true},"pipeline_id":{"tipo":"string","desc":"Pipeline the deal lives in.","obrigatorio":true},"stage_id":{"tipo":"string","desc":"Stage the deal is at.","obrigatorio":true},"value_minor":{"tipo":"int","desc":"Value in the currency's MINOR unit — cents, not dollars."},"currency":{"tipo":"string","desc":"ISO 4217 code for `value_minor`."}},"body":{"title":"Renewal","pipeline_id":"pl_…","stage_id":"st_…","value_minor":10000,"currency":"USD"},"retorno":"Deal","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/deals/deal_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Renewal\",\"pipeline_id\":\"pl_…\",\"stage_id\":\"st_…\",\"value_minor\":10000,\"currency\":\"USD\"}'","returns":"{ id, title, pipeline_id, stage_id, status, value_minor, currency, contact_id, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/deals/:deal_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/deals/:deal_id","auth":"organization","grupo":"CRM","summary":"Delete one deal from the tenant CRM. The response carries the record as it was.","desc":"Money is in minor units: `value_minor: 10000` with `currency: \"USD\"` is $100.00, not $10,000.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"deal_id":{"desc":"CRM deal ID inside the active organization."}},"retorno":"Deal","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/deals/deal_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, pipeline_id, stage_id, status, value_minor, currency, contact_id, company_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/deals/:deal_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/activities","auth":"organization","grupo":"CRM","summary":"List activities in the tenant CRM — something that happened with a contact, company or deal.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"deal_id":{"tipo":"string","desc":"Restrict to one deal."},"contact_id":{"tipo":"string","desc":"Restrict to one CRM contact."},"company_id":{"tipo":"string","desc":"Restrict to one CRM company."},"activity_type":{"tipo":"string","desc":"Restrict to one activity type, e.g. `note` or `call`."}},"retorno":"Page<Activity>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/activities -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,activity_type,note,deal_id,contact_id,company_id,created_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/activities","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/activities","auth":"organization","grupo":"CRM","summary":"Create a activity in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"note":{"tipo":"string","desc":"The text of the activity.","obrigatorio":true},"activity_type":{"tipo":"string","desc":"What kind it was, e.g. `note`, `call`, `meeting`."},"deal_id":{"tipo":"string","desc":"Deal it refers to."},"contact_id":{"tipo":"string","desc":"Contact it refers to."},"company_id":{"tipo":"string","desc":"Company it refers to."}},"body":{"activity_type":"note","note":"Followed up","deal_id":"de_…"},"retorno":"Activity","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/activities -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"activity_type\":\"note\",\"note\":\"Followed up\",\"deal_id\":\"de_…\"}'","returns":"{ id, activity_type, note, deal_id, contact_id, company_id, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/activities","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/activities/:activity_id","auth":"organization","grupo":"CRM","summary":"Read one activity from the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"retorno":"Activity","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, activity_type, note, deal_id, contact_id, company_id, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/activities/:activity_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/activities/:activity_id","auth":"organization","grupo":"CRM","summary":"Update one activity in the tenant CRM. Only the fields you send change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"corpo":{"note":{"tipo":"string","desc":"The text of the activity.","obrigatorio":true},"activity_type":{"tipo":"string","desc":"What kind it was, e.g. `note`, `call`, `meeting`."},"deal_id":{"tipo":"string","desc":"Deal it refers to."},"contact_id":{"tipo":"string","desc":"Contact it refers to."},"company_id":{"tipo":"string","desc":"Company it refers to."}},"body":{"activity_type":"note","note":"Followed up","deal_id":"de_…"},"retorno":"Activity","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"activity_type\":\"note\",\"note\":\"Followed up\",\"deal_id\":\"de_…\"}'","returns":"{ id, activity_type, note, deal_id, contact_id, company_id, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/activities/:activity_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/activities/:activity_id","auth":"organization","grupo":"CRM","summary":"Delete one activity from the tenant CRM. The response carries the record as it was.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"retorno":"Activity","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, activity_type, note, deal_id, contact_id, company_id, created_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/activities/:activity_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/tasks","auth":"organization","grupo":"CRM","summary":"List tasks in the tenant CRM — work someone still has to do in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"status":{"tipo":"string","desc":"Restrict to one status value."},"deal_id":{"tipo":"string","desc":"Restrict to one deal."},"contact_id":{"tipo":"string","desc":"Restrict to one CRM contact."},"assignee_user_id":{"tipo":"string","desc":"Restrict to the member the work is assigned to."}},"retorno":"Page<Task>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/tasks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,title,status,due_at,assignee_user_id,deal_id,contact_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/tasks","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/tasks","auth":"organization","grupo":"CRM","summary":"Create a task in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"title":{"tipo":"string","desc":"What has to be done.","obrigatorio":true},"status":{"tipo":"string","desc":"Current state.","valores":["open","done","cancelled"],"padrao":"open"},"due_at":{"tipo":"string","desc":"When it is due, ISO-8601."},"assignee_user_id":{"tipo":"string","desc":"Member responsible for it."},"deal_id":{"tipo":"string","desc":"Deal the task belongs to."},"contact_id":{"tipo":"string","desc":"Contact the task belongs to."}},"body":{"title":"Follow up","status":"open","deal_id":"de_…"},"retorno":"Task","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/tasks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Follow up\",\"status\":\"open\",\"deal_id\":\"de_…\"}'","returns":"{ id, title, status, due_at, assignee_user_id, deal_id, contact_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/tasks","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/tasks/:task_id","auth":"organization","grupo":"CRM","summary":"Read one task from the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"task_id":{"desc":"CRM task ID inside the active organization."}},"retorno":"Task","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, status, due_at, assignee_user_id, deal_id, contact_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/tasks/:task_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/tasks/:task_id","auth":"organization","grupo":"CRM","summary":"Update one task in the tenant CRM. Only the fields you send change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"task_id":{"desc":"CRM task ID inside the active organization."}},"corpo":{"title":{"tipo":"string","desc":"What has to be done.","obrigatorio":true},"status":{"tipo":"string","desc":"Current state.","valores":["open","done","cancelled"],"padrao":"open"},"due_at":{"tipo":"string","desc":"When it is due, ISO-8601."},"assignee_user_id":{"tipo":"string","desc":"Member responsible for it."},"deal_id":{"tipo":"string","desc":"Deal the task belongs to."},"contact_id":{"tipo":"string","desc":"Contact the task belongs to."}},"body":{"title":"Follow up","status":"open","deal_id":"de_…"},"retorno":"Task","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Follow up\",\"status\":\"open\",\"deal_id\":\"de_…\"}'","returns":"{ id, title, status, due_at, assignee_user_id, deal_id, contact_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/tasks/:task_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/tasks/:task_id","auth":"organization","grupo":"CRM","summary":"Delete one task from the tenant CRM. The response carries the record as it was.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"task_id":{"desc":"CRM task ID inside the active organization."}},"retorno":"Task","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, status, due_at, assignee_user_id, deal_id, contact_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/tasks/:task_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages","auth":"organization","grupo":"CRM","summary":"List stages in the tenant CRM — one step of a pipeline, addressed under the pipeline it belongs to.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<Stage>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id/stages -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,pipeline_id,name,position,probability,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages","auth":"organization","grupo":"CRM","summary":"Create a stage in the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"Stage name, e.g. `Proposal`.","obrigatorio":true},"position":{"tipo":"int","desc":"Order within the pipeline, lowest first."},"probability":{"tipo":"int","desc":"Chance of winning at this stage, 0 to 100."}},"body":{"name":"Proposal","position":2,"probability":60},"retorno":"Stage","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id/stages -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Proposal\",\"position\":2,\"probability\":60}'","returns":"{ id, pipeline_id, name, position, probability, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth":"organization","grupo":"CRM","summary":"Read one stage from the tenant CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."},"stage_id":{"desc":"Pipeline stage ID. Stages live under one pipeline."}},"retorno":"Stage","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id/stages/stage_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, pipeline_id, name, position, probability, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth":"organization","grupo":"CRM","summary":"Update one stage in the tenant CRM. Only the fields you send change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."},"stage_id":{"desc":"Pipeline stage ID. Stages live under one pipeline."}},"corpo":{"name":{"tipo":"string","desc":"Stage name, e.g. `Proposal`.","obrigatorio":true},"position":{"tipo":"int","desc":"Order within the pipeline, lowest first."},"probability":{"tipo":"int","desc":"Chance of winning at this stage, 0 to 100."}},"body":{"name":"Proposal","position":2,"probability":60},"retorno":"Stage","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id/stages/stage_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Proposal\",\"position\":2,\"probability\":60}'","returns":"{ id, pipeline_id, name, position, probability, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth":"organization","grupo":"CRM","summary":"Delete one stage from the tenant CRM. The response carries the record as it was.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"pipeline_id":{"desc":"CRM pipeline ID inside the active organization."},"stage_id":{"desc":"Pipeline stage ID. Stages live under one pipeline."}},"retorno":"Stage","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/organization_id/crm/pipelines/pipeline_id/stages/stage_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, pipeline_id, name, position, probability, url }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/pipelines/:pipeline_id/stages/:stage_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/platform/crm/leads","auth":"platform_admin","grupo":"Platform CRM","summary":"List leads in the platform CRM — a prospective ORGANIZATION in our own funnel — platform CRM is not tenant data.","params":{},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"stage":{"tipo":"string","desc":"Restrict to one funnel stage of the platform lead."}},"retorno":"Page<Lead>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/leads -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,email,name,company_name,source,stage,organization_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/platform/crm/leads","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"POST","path":"/api/platform/crm/leads","auth":"platform_admin","grupo":"Platform CRM","summary":"Create a lead in the platform CRM.","params":{},"corpo":{"email":{"tipo":"string","desc":"Contact email for the lead.","obrigatorio":true},"name":{"tipo":"string","desc":"Who to talk to.","obrigatorio":true},"company_name":{"tipo":"string","desc":"Name of the prospective organization."},"source":{"tipo":"string","desc":"Where the lead came from, e.g. `manual`."},"stage":{"tipo":"string","desc":"Where it sits in our funnel, e.g. `new`."},"organization_id":{"tipo":"string","desc":"The organization it became, once converted."}},"body":{"email":"lead@example.com","name":"Lead","company_name":"Acme","source":"manual","stage":"new","organization_id":"org_…"},"retorno":"Lead","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/platform/crm/leads -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"email\":\"lead@example.com\",\"name\":\"Lead\",\"company_name\":\"Acme\",\"source\":\"manual\",\"stage\":\"new\",\"organization_id\":\"org_…\"}'","returns":"{ id, email, name, company_name, source, stage, organization_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/leads","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/platform/crm/leads/:lead_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Read one lead from the platform CRM.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."}},"retorno":"Lead","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/leads/lead_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, email, name, company_name, source, stage, organization_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"PATCH","path":"/api/platform/crm/leads/:lead_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Update one lead in the platform CRM. Only the fields you send change.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."}},"corpo":{"email":{"tipo":"string","desc":"Contact email for the lead.","obrigatorio":true},"name":{"tipo":"string","desc":"Who to talk to.","obrigatorio":true},"company_name":{"tipo":"string","desc":"Name of the prospective organization."},"source":{"tipo":"string","desc":"Where the lead came from, e.g. `manual`."},"stage":{"tipo":"string","desc":"Where it sits in our funnel, e.g. `new`."},"organization_id":{"tipo":"string","desc":"The organization it became, once converted."}},"body":{"email":"lead@example.com","name":"Lead","company_name":"Acme","source":"manual","stage":"new","organization_id":"org_…"},"retorno":"Lead","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/platform/crm/leads/lead_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"email\":\"lead@example.com\",\"name\":\"Lead\",\"company_name\":\"Acme\",\"source\":\"manual\",\"stage\":\"new\",\"organization_id\":\"org_…\"}'","returns":"{ id, email, name, company_name, source, stage, organization_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"DELETE","path":"/api/platform/crm/leads/:lead_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Delete one lead from the platform CRM. The response carries the record as it was.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."}},"retorno":"Lead","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/platform/crm/leads/lead_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, email, name, company_name, source, stage, organization_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/platform/crm/tasks","auth":"platform_admin","grupo":"Platform CRM","summary":"List tasks in the platform CRM — work on a platform lead — about a prospective tenant, not about a tenant's customer.","params":{},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."},"status":{"tipo":"string","desc":"Restrict to one status value."},"lead_id":{"tipo":"string","desc":"Restrict to one platform lead."},"assignee_user_id":{"tipo":"string","desc":"Restrict to the member the work is assigned to."}},"retorno":"Page<PlatformTask>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/tasks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,title,status,lead_id,due_at,assignee_user_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/platform/crm/tasks","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"POST","path":"/api/platform/crm/tasks","auth":"platform_admin","grupo":"Platform CRM","summary":"Create a task in the platform CRM.","params":{},"corpo":{"title":{"tipo":"string","desc":"What has to be done.","obrigatorio":true},"lead_id":{"tipo":"string","desc":"Lead the task belongs to."},"due_at":{"tipo":"string","desc":"When it is due, ISO-8601."},"assignee_user_id":{"tipo":"string","desc":"Who is responsible."}},"body":{"title":"Follow up","lead_id":"ld_…","due_at":"2026-09-01T12:00:00Z"},"retorno":"PlatformTask","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/platform/crm/tasks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Follow up\",\"lead_id\":\"ld_…\",\"due_at\":\"2026-09-01T12:00:00Z\"}'","returns":"{ id, title, status, lead_id, due_at, assignee_user_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/tasks","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/platform/crm/tasks/:task_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Read one task from the platform CRM.","params":{"task_id":{"desc":"CRM task ID inside the active organization."}},"retorno":"PlatformTask","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, status, lead_id, due_at, assignee_user_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/tasks/:task_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"PATCH","path":"/api/platform/crm/tasks/:task_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Update one task in the platform CRM. Only the fields you send change.","params":{"task_id":{"desc":"CRM task ID inside the active organization."}},"corpo":{"title":{"tipo":"string","desc":"What has to be done.","obrigatorio":true},"lead_id":{"tipo":"string","desc":"Lead the task belongs to."},"due_at":{"tipo":"string","desc":"When it is due, ISO-8601."},"assignee_user_id":{"tipo":"string","desc":"Who is responsible."}},"body":{"title":"Follow up","lead_id":"ld_…","due_at":"2026-09-01T12:00:00Z"},"retorno":"PlatformTask","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/platform/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"title\":\"Follow up\",\"lead_id\":\"ld_…\",\"due_at\":\"2026-09-01T12:00:00Z\"}'","returns":"{ id, title, status, lead_id, due_at, assignee_user_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/tasks/:task_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"DELETE","path":"/api/platform/crm/tasks/:task_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Delete one task from the platform CRM. The response carries the record as it was.","params":{"task_id":{"desc":"CRM task ID inside the active organization."}},"retorno":"PlatformTask","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/platform/crm/tasks/task_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, title, status, lead_id, due_at, assignee_user_id, created_at, updated_at, url }","url":"https://commsharbor.com/api/platform/crm/tasks/:task_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/platform/crm/leads/:lead_id/activities","auth":"platform_admin","grupo":"Platform CRM","summary":"List activities in the platform CRM — our note about a prospective tenant.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50},"q":{"tipo":"string","desc":"Free-text search over the record's main fields."}},"retorno":"Page<PlatformActivity>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/leads/lead_id/activities -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,activity_type,note,lead_id,created_at,url}], next_cursor }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id/activities","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"POST","path":"/api/platform/crm/leads/:lead_id/activities","auth":"platform_admin","grupo":"Platform CRM","summary":"Create a activity in the platform CRM.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."}},"corpo":{"note":{"tipo":"string","desc":"The text of the activity.","obrigatorio":true},"activity_type":{"tipo":"string","desc":"What kind it was, e.g. `note`."}},"body":{"activity_type":"note","note":"Followed up"},"retorno":"PlatformActivity","erros":{"400":"A required field is missing, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/platform/crm/leads/lead_id/activities -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"activity_type\":\"note\",\"note\":\"Followed up\"}'","returns":"{ id, activity_type, note, lead_id, created_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id/activities","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/platform/crm/leads/:lead_id/activities/:activity_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Read one activity from the platform CRM.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"retorno":"PlatformActivity","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/platform/crm/leads/lead_id/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, activity_type, note, lead_id, created_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id/activities/:activity_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"PATCH","path":"/api/platform/crm/leads/:lead_id/activities/:activity_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Update one activity in the platform CRM. Only the fields you send change.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"corpo":{"note":{"tipo":"string","desc":"The text of the activity.","obrigatorio":true},"activity_type":{"tipo":"string","desc":"What kind it was, e.g. `note`."}},"body":{"activity_type":"note","note":"Followed up"},"retorno":"PlatformActivity","erros":{"400":"A field is invalid, or a referenced record does not exist here.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/platform/crm/leads/lead_id/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"activity_type\":\"note\",\"note\":\"Followed up\"}'","returns":"{ id, activity_type, note, lead_id, created_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id/activities/:activity_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"DELETE","path":"/api/platform/crm/leads/:lead_id/activities/:activity_id","auth":"platform_admin","grupo":"Platform CRM","summary":"Delete one activity from the platform CRM. The response carries the record as it was.","params":{"lead_id":{"desc":"Platform CRM lead ID. Platform CRM is not tenant data."},"activity_id":{"desc":"CRM activity ID inside the active organization."}},"retorno":"PlatformActivity","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/platform/crm/leads/lead_id/activities/activity_id -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, activity_type, note, lead_id, created_at, url }","url":"https://commsharbor.com/api/platform/crm/leads/:lead_id/activities/:activity_id","auth_detail":"Session with an explicit platform_roles grant. Tenant ownership does not grant platform access."},{"method":"GET","path":"/api/organizations/:organization_id/crm/contacts/:contact_id/marketing","auth":"organization","grupo":"Consent","summary":"Read consent and marketing preference for one CRM contact.","desc":"Being in the CRM is not permission to email. This resource is where permission actually lives.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"retorno":"Marketing","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/crm/contacts/$CONTACT/marketing -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ marketing_enabled, basis, source, captured_at, unsubscribed_at }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id/marketing","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PUT","path":"/api/organizations/:organization_id/crm/contacts/:contact_id/marketing","auth":"organization","grupo":"Consent","summary":"Record permission-based marketing consent for one contact.","desc":"This NEVER restores a previous unsubscribe. If the contact opted out, they stay out and `marketing_enabled` remains false — recording consent after the fact does not undo their decision.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"corpo":{"basis":{"tipo":"string","desc":"Why sending is allowed.","valores":["explicit","documented_relationship"],"obrigatorio":true},"source":{"tipo":"string","desc":"Where the consent came from, e.g. the signup form that captured it.","obrigatorio":true},"captured_at":{"tipo":"string","desc":"When consent was captured, ISO-8601.","obrigatorio":true}},"body":{"basis":"explicit","source":"website signup form","captured_at":"2026-08-29T12:00:00.000Z"},"retorno":"Marketing","erros":{"400":"Missing basis, source or capture time, or an unknown basis.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPUT $ORIGIN/api/organizations/$ORG/crm/contacts/$CONTACT/marketing -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"basis\":\"explicit\",\"source\":\"website signup form\",\"captured_at\":\"2026-08-29T12:00:00.000Z\"}'","returns":"{ marketing_enabled, basis, source, captured_at, unsubscribed_at }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id/marketing","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/crm/contacts/:contact_id/preference-token","auth":"organization","grupo":"Consent","summary":"Create a signed preference and one-click unsubscribe capability for a contact.","desc":"The capability is scoped to one organization and one contact, it expires, and it embeds no email address. Put `marketing_headers` in the message and the unsubscribe works without a login.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"body":{},"retorno":"PreferenceToken","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/crm/contacts/$CONTACT/preference-token -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ api_url, preferences_url, unsubscribe_url, marketing_headers }","url":"https://commsharbor.com/api/organizations/:organization_id/crm/contacts/:contact_id/preference-token","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/preferences/:token","auth":"preference_capability","grupo":"Consent","summary":"Read a contact's preference through a signed capability, with no login.","desc":"The token IS the credential. It reveals preference state and nothing else — no email address, no CRM record.","params":{"token":{"desc":"Signed preference capability. It is scoped to one organization and one contact, it expires, and it never embeds an email address."}},"retorno":"PreferenceState","erros":{"401":"Bad signature.","404":"Unknown or expired capability."},"exemplo":"curl -s $ORIGIN/api/preferences/$TOKEN","returns":"{ marketing_enabled, unsubscribed_at, expires_at }","url":"https://commsharbor.com/api/preferences/:token","auth_detail":"Signed, expiring capability scoped to one organization and contact. No login is required and no email address is embedded in the token."},{"method":"POST","path":"/api/preferences/:token/unsubscribe","auth":"preference_capability","grupo":"Consent","summary":"Apply an RFC 8058 one-click unsubscribe, idempotently.","desc":"This is the endpoint mail clients call from the `List-Unsubscribe-Post` header, which is why the body is form-encoded and fixed. Calling it twice is the same as calling it once.","params":{"token":{"desc":"Signed preference capability. It is scoped to one organization and one contact, it expires, and it never embeds an email address."}},"body":"List-Unsubscribe=One-Click","bodyContentType":"application/x-www-form-urlencoded","retorno":{"unsubscribed":{"tipo":"bool","desc":"Always true once the contact is unsubscribed, whether or not this call was the one that did it."}},"erros":{"401":"Bad signature.","404":"Unknown or expired capability."},"exemplo":"curl -s -XPOST $ORIGIN/api/preferences/$TOKEN/unsubscribe -H 'content-type: application/x-www-form-urlencoded' -d 'List-Unsubscribe=One-Click'","returns":"{ unsubscribed }","url":"https://commsharbor.com/api/preferences/:token/unsubscribe","auth_detail":"Signed, expiring capability scoped to one organization and contact. No login is required and no email address is embedded in the token."},{"method":"POST","path":"/api/organizations/:organization_id/domains/:domain_id/marketing-smoke","auth":"organization","grupo":"Consent","summary":"Queue one controlled permission-based marketing message to the server-side recipient.","desc":"Like the transactional smoke, the destination is a server-side secret. `contact_id` must be the CRM contact that matches it — you cannot point this at an arbitrary person.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"headers":{"Idempotency-Key":{"tipo":"string","desc":"Unique key for this controlled send. Replaying the same key returns the same result and produces NO second Queue message; a different payload under the same key conflicts.","obrigatorio":true}},"corpo":{"contact_id":{"tipo":"string","desc":"CRM contact matching the server-side QA recipient.","obrigatorio":true}},"body":{"contact_id":"ct_controlled"},"retorno":"Send","erros":{"400":"Missing contact.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The contact does not match the controlled recipient, or the domain is not active."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/domains/$DOMAIN/marketing-smoke -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{\"contact_id\":\"ct_controlled\"}'","returns":"{ delivery{id,status,domain_id,template_id,template_version,ses_message_id,created_at}, capacity{remaining,global_remaining,hard_cap}, dispatch{queued,job_id}, replayed }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id/marketing-smoke","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/contact-imports","auth":"organization","grupo":"Imports","summary":"List the contact imports of the organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<ContactImport>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/contact-imports -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,status,rows,accepted,rejected,basis,file_id,created_at}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/contact-imports","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/contact-imports","auth":"organization","grupo":"Imports","summary":"Upload a consent-declared CSV and get back a safe preview before anything is imported.","desc":"Nothing is created by this call. The consent declaration is mandatory: an import that cannot say why these people may be emailed is an import that does not happen.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"csv":{"tipo":"string","desc":"The CSV itself, up to 5 MB and 10,000 rows.","obrigatorio":true},"mapping":{"tipo":"object","desc":"Which CSV column feeds which contact field, e.g. `{ \"email\": \"Email\" }`.","obrigatorio":true},"basis":{"tipo":"string","desc":"Why sending is allowed.","valores":["explicit","documented_relationship"],"obrigatorio":true},"source":{"tipo":"string","desc":"Where the consent came from, e.g. the signup form that captured it.","obrigatorio":true},"captured_at":{"tipo":"string","desc":"When consent was captured, ISO-8601.","obrigatorio":true}},"body":{"csv":"Email,First name\\nalice@example.com,Alice","mapping":{"email":"Email","first_name":"First name"},"basis":"explicit","source":"website signup form","captured_at":"2026-08-29T12:00:00.000Z"},"retorno":{"import":{"tipo":"ContactImport","desc":"The import in `preview` state."},"preview":{"tipo":"object[]","desc":"The first parsed rows, so you can check the mapping before confirming."},"errors":{"tipo":"ImportError[]","desc":"Rows that would be rejected, addressed by line number."}},"erros":{"400":"CSV too large, unparseable, or missing the consent declaration.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","413":"Above the size limit."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/contact-imports -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"csv\":\"Email\\\\nalice@example.com\",\"mapping\":{\"email\":\"Email\"},\"basis\":\"explicit\",\"source\":\"website signup form\",\"captured_at\":\"2026-08-29T12:00:00.000Z\"}'","returns":"{ import{id,status,rows,accepted,rejected,basis,file_id,created_at}, preview, errors[{row,code,message}] }","url":"https://commsharbor.com/api/organizations/:organization_id/contact-imports","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/contact-imports/:import_id","auth":"organization","grupo":"Imports","summary":"Read one durable contact import and its current counts.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"import_id":{"desc":"Contact import ID returned by the CSV preview."}},"retorno":"ContactImport","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/contact-imports/$IMPORT -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, status, rows, accepted, rejected, basis, file_id, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/contact-imports/:import_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/contact-imports/:import_id/confirm","auth":"organization","grupo":"Imports","summary":"Confirm a previewed import and enqueue it, exactly once.","desc":"The idempotency key is mandatory here. Reusing it returns the same import and never creates a second Queue message — which is what keeps a retry from importing everyone twice.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"import_id":{"desc":"Contact import ID returned by the CSV preview."}},"headers":{"Idempotency-Key":{"tipo":"string","desc":"Unique key for this import confirmation. Replaying the same key returns the same result and produces NO second Queue message; a different payload under the same key conflicts.","obrigatorio":true}},"body":{},"retorno":"ContactImport","erros":{"400":"Missing Idempotency-Key.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The same key was used with a different payload, or the import was already confirmed."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/contact-imports/$IMPORT/confirm -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{}'","returns":"{ id, status, rows, accepted, rejected, basis, file_id, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/contact-imports/:import_id/confirm","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/contact-imports/:import_id/errors","auth":"organization","grupo":"Imports","summary":"List the row-numbered errors of one import, so the source file can be fixed.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"import_id":{"desc":"Contact import ID returned by the CSV preview."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<ImportError>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/contact-imports/$IMPORT/errors -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{row,code,message}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/contact-imports/:import_id/errors","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/contact-files/:file_id","auth":"organization","grupo":"Imports","summary":"Download a tenant-owned CSV before its seven-day expiry.","desc":"Files expire seven days after creation. Durable audit and row-level results survive the file.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"file_id":{"desc":"Contact file ID. Files expire seven days after they are created."}},"retorno":{"_texto":"`text/csv` as an attachment, with the tenant's file name."},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","410":"The file expired. Its audit record still exists."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/contact-files/$FILE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"`text/csv` as an attachment, with the tenant's file name.","url":"https://commsharbor.com/api/organizations/:organization_id/contact-files/:file_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/contacts/export","auth":"organization","grupo":"Imports","summary":"Create a CSV export of the organization's contacts, retained for seven days.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"body":{},"retorno":{"export":{"tipo":"ContactImport","desc":"The export record, with its file and expiry."},"download_url":{"tipo":"string","desc":"Where to fetch the CSV while it lasts."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/contacts/export -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ export{id,status,rows,accepted,rejected,basis,file_id,created_at}, download_url }","url":"https://commsharbor.com/api/organizations/:organization_id/contacts/export","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/suppressions","auth":"organization","grupo":"Suppressions","summary":"List the organization's suppressions, without exposing email hashes.","desc":"Global, organization and SES tenant suppressions are all checked BEFORE quota and before any queue work.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<Suppression>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/suppressions -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,scope,reason,contact_id,created_at}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/suppressions","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/suppressions","auth":"organization","grupo":"Suppressions","summary":"Suppress one recipient inside the active organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"email":{"tipo":"string","desc":"Address to suppress.","obrigatorio":true},"contact_id":{"tipo":"string","desc":"CRM contact it corresponds to, when you know it."}},"body":{"email":"alice@example.com","contact_id":"ct_example"},"retorno":{"suppressed":{"tipo":"bool","desc":"Always true once the address is suppressed."}},"erros":{"400":"Missing or malformed email.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/suppressions -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"email\":\"alice@example.com\"}'","returns":"{ suppressed }","url":"https://commsharbor.com/api/organizations/:organization_id/suppressions","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/audiences","auth":"organization","grupo":"Audiences","summary":"List static audiences and saved segments.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<Audience>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/audiences -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,name,kind,filter,member_count,created_at}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/audiences","auth":"organization","grupo":"Audiences","summary":"Create a static audience or a saved segment with an allowlisted filter.","desc":"Only allowlisted filter fields are accepted — a saved segment cannot be turned into an arbitrary query over the CRM.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Audience name.","obrigatorio":true},"kind":{"tipo":"string","desc":"How membership is decided.","valores":["static","saved_segment"],"obrigatorio":true},"filter":{"tipo":"object","desc":"The saved filter, for `saved_segment`. Allowlisted fields only."}},"body":{"name":"Newsletter","kind":"static"},"retorno":"Audience","erros":{"400":"Missing name or kind, or a filter field outside the allowlist.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/audiences -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Newsletter\",\"kind\":\"static\"}'","returns":"{ id, name, kind, filter, member_count, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/audiences/:audience_id","auth":"organization","grupo":"Audiences","summary":"Read one audience of this organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."}},"retorno":"Audience","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, kind, filter, member_count, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/audiences/:audience_id","auth":"organization","grupo":"Audiences","summary":"Rename an audience or change its saved filter.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"New audience name."},"filter":{"tipo":"object","desc":"New saved filter. Allowlisted fields only."}},"body":{"name":"Customers","filter":{"consent_basis":"explicit"}},"erros":{"400":"A filter field outside the allowlist.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"retorno":"Audience","exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Customers\"}'","returns":"{ id, name, kind, filter, member_count, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/audiences/:audience_id","auth":"organization","grupo":"Audiences","summary":"Delete an audience and its memberships. Contacts themselves are untouched.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."}},"retorno":"Audience","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, kind, filter, member_count, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/audiences/:audience_id/members","auth":"organization","grupo":"Audiences","summary":"List the contacts currently in one audience.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"Page<Contact>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE/members -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,email,first_name,last_name,company_id,created_at,updated_at,url}], next_cursor }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id/members","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/audiences/:audience_id/members","auth":"organization","grupo":"Audiences","summary":"Add a CRM contact to a static audience.","desc":"Only for `static` audiences: a saved segment's membership comes from its filter, not from this route.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."}},"corpo":{"contact_id":{"tipo":"string","desc":"CRM contact to add.","obrigatorio":true}},"body":{"contact_id":"ct_example"},"retorno":{"membership":{"tipo":"object","desc":"The audience membership that was created."}},"erros":{"400":"Missing contact.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The audience is a saved segment and has no manual membership."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE/members -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"contact_id\":\"ct_example\"}'","returns":"{ membership }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id/members","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/audiences/:audience_id/members/:contact_id","auth":"organization","grupo":"Audiences","summary":"Remove a contact from a static audience.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"audience_id":{"desc":"Audience ID inside the active organization."},"contact_id":{"desc":"CRM contact ID inside the active organization."}},"retorno":{"membership":{"tipo":"object","desc":"The membership as it was before removal."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/audiences/$AUDIENCE/members/$CONTACT -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ membership }","url":"https://commsharbor.com/api/organizations/:organization_id/audiences/:audience_id/members/:contact_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/templates","auth":"organization","grupo":"Templates","summary":"List the versioned email templates of the organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"PageCamel<Template>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/templates -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,name,message_type,subject,variables,blocks,status,latest_version,updated_at}], nextCursor }","url":"https://commsharbor.com/api/organizations/:organization_id/templates","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/templates","auth":"organization_template_write","grupo":"Templates","summary":"Create a template draft from canonical blocks.","desc":"Creating never publishes. Nothing can send this template until `publish` freezes a version.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Template name.","obrigatorio":true},"message_type":{"tipo":"string","desc":"What the template may be used for. A marketing campaign will not accept a transactional template.","valores":["transactional","marketing"],"obrigatorio":true},"subject":{"tipo":"string","desc":"Subject line, with `{{variable}}` placeholders.","obrigatorio":true},"variables":{"tipo":"object[]","desc":"Typed variables the template declares: `name`, `type` and whether it is `required`."},"blocks":{"tipo":"object[]","desc":"Canonical content blocks. This is the stored form — HTML is converted into it, never kept raw."}},"body":{"name":"Welcome","message_type":"transactional","subject":"Welcome, {{name}}","variables":[{"name":"name","type":"string","required":true}],"blocks":[{"type":"heading","text":"Hello {{name}}","level":1,"align":"left"}]},"retorno":"Template","erros":{"400":"Missing name, subject or message type, or an unknown block type.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/templates -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Welcome\",\"message_type\":\"transactional\",\"subject\":\"Welcome\"}'","returns":"{ id, name, message_type, subject, variables, blocks, status, latest_version, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates","auth_detail":"Active organization identity with template:write permission."},{"method":"GET","path":"/api/organizations/:organization_id/templates/:template_id","auth":"organization","grupo":"Templates","summary":"Read one template draft owned by this organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"retorno":"Template","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, message_type, subject, variables, blocks, status, latest_version, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/templates/:template_id","auth":"organization_template_write","grupo":"Templates","summary":"Update a template as a new draft, leaving published versions untouched.","desc":"Editing a draft can never change what a past delivery rendered: published versions are immutable.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"Template name.","obrigatorio":true},"message_type":{"tipo":"string","desc":"What the template may be used for. A marketing campaign will not accept a transactional template.","valores":["transactional","marketing"],"obrigatorio":true},"subject":{"tipo":"string","desc":"Subject line, with `{{variable}}` placeholders.","obrigatorio":true},"variables":{"tipo":"object[]","desc":"Typed variables the template declares: `name`, `type` and whether it is `required`."},"blocks":{"tipo":"object[]","desc":"Canonical content blocks. This is the stored form — HTML is converted into it, never kept raw."}},"body":{"name":"Welcome","message_type":"transactional","subject":"Welcome, {{name}}","variables":[{"name":"name","type":"string","required":true}],"blocks":[{"type":"heading","text":"Hello {{name}}","level":1,"align":"left"}]},"retorno":"Template","erros":{"400":"Invalid field or unknown block type.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"subject\":\"Welcome aboard\"}'","returns":"{ id, name, message_type, subject, variables, blocks, status, latest_version, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id","auth_detail":"Active organization identity with template:write permission."},{"method":"DELETE","path":"/api/organizations/:organization_id/templates/:template_id","auth":"organization_template_write","grupo":"Templates","summary":"Archive a template without deleting its published versions.","desc":"Deliveries that referenced a version must keep resolving to it, so archiving hides the draft and keeps the history.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"retorno":"Template","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, message_type, subject, variables, blocks, status, latest_version, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id","auth_detail":"Active organization identity with template:write permission."},{"method":"POST","path":"/api/organizations/:organization_id/templates/:template_id/publish","auth":"organization_template_write","grupo":"Templates","summary":"Publish an immutable, content-hashed version of the draft.","desc":"The version's identity is the hash of its compiled content — publishing identical content does not create a second version.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"body":{},"retorno":"TemplateVersion","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The draft does not compile, or nothing changed since the last version."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE/publish -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ version, content_hash, subject, published_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id/publish","auth_detail":"Active organization identity with template:write permission."},{"method":"GET","path":"/api/organizations/:organization_id/templates/:template_id/versions","auth":"organization","grupo":"Templates","summary":"List the immutable published versions of a template.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"retorno":"Lista<TemplateVersion>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE/versions -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{version,content_hash,subject,published_at}] }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id/versions","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/templates/preview","auth":"organization_template_write","grupo":"Templates","summary":"Compile and safely render a draft, without saving or publishing anything.","desc":"`warnings` tells you what was stripped and what would not render — read it before publishing rather than after sending.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Template name.","obrigatorio":true},"message_type":{"tipo":"string","desc":"What the template may be used for. A marketing campaign will not accept a transactional template.","valores":["transactional","marketing"],"obrigatorio":true},"subject":{"tipo":"string","desc":"Subject line, with `{{variable}}` placeholders.","obrigatorio":true},"variables":{"tipo":"object[]","desc":"Typed variables the template declares: `name`, `type` and whether it is `required`."},"blocks":{"tipo":"object[]","desc":"Canonical content blocks. This is the stored form — HTML is converted into it, never kept raw."},"values":{"tipo":"object","desc":"Values to substitute into the declared variables for this preview."}},"body":{"name":"Welcome","message_type":"transactional","subject":"Welcome, {{name}}","variables":[{"name":"name","type":"string","required":true}],"blocks":[{"type":"heading","text":"Hello {{name}}","level":1,"align":"left"}],"values":{"name":"Ada"}},"retorno":"TemplatePreview","erros":{"400":"The draft does not compile.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/templates/preview -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Welcome\",\"message_type\":\"transactional\",\"subject\":\"Hi {{name}}\",\"values\":{\"name\":\"Ada\"}}'","returns":"{ subject, html, text, warnings }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/preview","auth_detail":"Active organization identity with template:write permission."},{"method":"GET","path":"/api/organizations/:organization_id/templates/:template_id/export","auth":"organization","grupo":"Templates","summary":"Export the latest published version as HTML, plain text and MJML.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"template_id":{"desc":"Email template ID inside the active organization."}},"retorno":"TemplateExport","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The template has never been published."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/templates/$TEMPLATE/export -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ template_id, version, subject, html, text, mjml, content_hash }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/:template_id/export","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/templates/import-html","auth":"organization_template_write","grupo":"Templates","summary":"Import a conservative HTML subset and convert it into canonical blocks.","desc":"Active content, forms and unsafe URLs are rejected, not sanitised-and-kept. What survives is stored as blocks, so an imported template behaves exactly like an authored one.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Template name.","obrigatorio":true},"message_type":{"tipo":"string","desc":"What it may be used for.","valores":["transactional","marketing"],"obrigatorio":true},"subject":{"tipo":"string","desc":"Subject line.","obrigatorio":true},"html":{"tipo":"string","desc":"The HTML to import. Scripts, forms, event handlers and unsafe URLs are rejected.","obrigatorio":true}},"body":{"name":"Imported","message_type":"transactional","subject":"Imported","html":"<h1>Safe</h1><p>Content</p>"},"retorno":"Template","erros":{"400":"The HTML carries active content, a form, or a URL scheme that is not allowed.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/templates/import-html -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"Imported\",\"message_type\":\"transactional\",\"subject\":\"Imported\",\"html\":\"<h1>Safe</h1>\"}'","returns":"{ id, name, message_type, subject, variables, blocks, status, latest_version, updated_at }","url":"https://commsharbor.com/api/organizations/:organization_id/templates/import-html","auth_detail":"Active organization identity with template:write permission."},{"method":"POST","path":"/api/messages","auth":"organization_messages_send","grupo":"Messages","summary":"Queue one idempotent transactional delivery for the active organization.","desc":"The canonical send route. Suppressions are checked before quota, and quota before any Queue work — a suppressed recipient never costs a send. The response carries no recipient address and no message content.","headers":{"Idempotency-Key":{"tipo":"string","desc":"Unique key for this logical message. An equivalent replay returns the SAME delivery and produces no second send; the same key with a different payload conflicts before quota or Queue work.","obrigatorio":true}},"corpo":{"domain_id":{"tipo":"string","desc":"Active sending domain to send from.","obrigatorio":true},"to":{"tipo":"string","desc":"Recipient address. It is not echoed back in the response.","obrigatorio":true},"template_id":{"tipo":"string","desc":"Template to render.","obrigatorio":true},"template_version":{"tipo":"int","desc":"Published version to use. Without it, the latest published version is used — pin it when the content must not drift."},"variables":{"tipo":"object","desc":"Values for the template's declared variables."},"reply_to":{"tipo":"string","desc":"Reply-To address, when it differs from the sending domain."}},"body":{"domain_id":"dom_…","to":"recipient@example.com","template_id":"tpl_…","template_version":1,"variables":{"name":"Ada"},"reply_to":"support@example.com"},"retorno":"Send","erros":{"400":"Missing Idempotency-Key, unknown template, or a required variable with no value.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The same Idempotency-Key was used with a different payload, or the recipient is suppressed.","429":"No capacity left for this organization, or the global monthly cap was reached."},"exemplo":"curl -s -XPOST $ORIGIN/api/messages -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{\"domain_id\":\"dom_1\",\"to\":\"a@example.com\",\"template_id\":\"tpl_1\"}'","returns":"{ delivery{id,status,domain_id,template_id,template_version,ses_message_id,created_at}, capacity{remaining,global_remaining,hard_cap}, dispatch{queued,job_id}, replayed }","url":"https://commsharbor.com/api/messages","auth_detail":"Active organization identity with messages:send permission. Idempotency-Key is mandatory."},{"method":"POST","path":"/api/organizations/:organization_id/messages","auth":"organization_messages_send","grupo":"Messages","summary":"Send one transactional message with the organization in the path instead of the header.","desc":"Same behaviour and same idempotency as `POST /api/messages`; it exists for clients that cannot set `X-Organization-Id`. Prefer the canonical route.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"headers":{"Idempotency-Key":{"tipo":"string","desc":"Unique key for this logical message. An equivalent replay returns the SAME delivery and produces no second send; the same key with a different payload conflicts before quota or Queue work.","obrigatorio":true}},"corpo":{"domain_id":{"tipo":"string","desc":"Active sending domain to send from.","obrigatorio":true},"to":{"tipo":"string","desc":"Recipient address. It is not echoed back in the response.","obrigatorio":true},"template_id":{"tipo":"string","desc":"Template to render.","obrigatorio":true},"template_version":{"tipo":"int","desc":"Published version to use. Without it, the latest published version is used — pin it when the content must not drift."},"variables":{"tipo":"object","desc":"Values for the template's declared variables."},"reply_to":{"tipo":"string","desc":"Reply-To address, when it differs from the sending domain."}},"body":{"domain_id":"dom_…","to":"recipient@example.com","template_id":"tpl_…","variables":{"name":"Ada"}},"retorno":"Send","erros":{"400":"Missing Idempotency-Key, unknown template, or a required variable with no value.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"Key reused with a different payload, or the recipient is suppressed.","429":"No capacity left."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/messages -H \"Authorization: Bearer $TOKEN\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{\"domain_id\":\"dom_1\",\"to\":\"a@example.com\",\"template_id\":\"tpl_1\"}'","returns":"{ delivery{id,status,domain_id,template_id,template_version,ses_message_id,created_at}, capacity{remaining,global_remaining,hard_cap}, dispatch{queued,job_id}, replayed }","url":"https://commsharbor.com/api/organizations/:organization_id/messages","auth_detail":"Active organization identity with messages:send permission. Idempotency-Key is mandatory."},{"method":"GET","path":"/api/organizations/:organization_id/campaigns","auth":"organization","grupo":"Campaigns","summary":"List the campaigns of the organization.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"query":{"cursor":{"tipo":"string","desc":"Opaque cursor from the previous page. Do not build or parse it."},"limit":{"tipo":"int","desc":"Page size, from 1 to 100.","padrao":50}},"retorno":"PageCamel<Campaign>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/campaigns -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,name,status,domain_id,audience_id,template_id,template_version,scheduled_for,frozen_recipients,created_at}], nextCursor }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/campaigns","auth":"organization_campaign_write","grupo":"Campaigns","summary":"Create a campaign draft from an active domain, an audience and a published marketing template.","desc":"All three must already exist and be usable: a draft cannot be created against an unverified domain or an unpublished template.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"name":{"tipo":"string","desc":"Campaign name.","obrigatorio":true},"domain_id":{"tipo":"string","desc":"Active sending domain to send from.","obrigatorio":true},"audience_id":{"tipo":"string","desc":"Audience the campaign goes to.","obrigatorio":true},"template_id":{"tipo":"string","desc":"Published MARKETING template. A transactional template is refused here.","obrigatorio":true},"template_version":{"tipo":"int","desc":"Published version to freeze into the campaign."}},"body":{"name":"August update","domain_id":"dom_…","audience_id":"aud_…","template_id":"tpl_…","template_version":1},"retorno":"Campaign","erros":{"400":"Missing field.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The domain is not active, the template is not published, or it is transactional."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/campaigns -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"name\":\"August update\",\"domain_id\":\"dom_1\",\"audience_id\":\"aud_1\",\"template_id\":\"tpl_1\"}'","returns":"{ id, name, status, domain_id, audience_id, template_id, template_version, scheduled_for, frozen_recipients, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/organizations/:organization_id/campaigns/:campaign_id","auth":"organization","grupo":"Campaigns","summary":"Read one campaign, without any recipient data.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"campaign_id":{"desc":"Campaign ID inside the active organization."}},"retorno":"Campaign","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/campaigns/$CAMPAIGN -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, name, status, domain_id, audience_id, template_id, template_version, scheduled_for, frozen_recipients, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns/:campaign_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/campaigns/:campaign_id","auth":"organization_campaign_write","grupo":"Campaigns","summary":"Edit a draft, or pause, resume or cancel a campaign that already launched.","desc":"Content can only change while the campaign is a draft. After launch this route moves state — the frozen recipient set and the frozen template version do not change.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"campaign_id":{"desc":"Campaign ID inside the active organization."}},"corpo":{"name":{"tipo":"string","desc":"New campaign name."},"domain_id":{"tipo":"string","desc":"New sending domain, while still a draft."},"audience_id":{"tipo":"string","desc":"New audience, while still a draft."},"template_id":{"tipo":"string","desc":"New published marketing template, while still a draft."},"template_version":{"tipo":"int","desc":"Published version to freeze into the campaign."},"status":{"tipo":"string","desc":"Move a launched campaign.","valores":["paused","sending","cancelled"]}},"body":{"name":"August update","status":"paused"},"retorno":"Campaign","erros":{"400":"Unknown status.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"Editing content after launch, or resuming while marketing is paused for the organization."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG/campaigns/$CAMPAIGN -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"status\":\"paused\"}'","returns":"{ id, name, status, domain_id, audience_id, template_id, template_version, scheduled_for, frozen_recipients, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns/:campaign_id","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"POST","path":"/api/organizations/:organization_id/campaigns/:campaign_id/launch","auth":"organization_campaign_write","grupo":"Campaigns","summary":"Freeze the eligible recipients and launch — or schedule — the campaign, exactly once.","desc":"The freeze happens once and never again: consent, suppressions and audience membership are evaluated at this moment, and the resulting set is what gets sent. Replaying the same Idempotency-Key returns the same campaign and produces no second dispatch.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"campaign_id":{"desc":"Campaign ID inside the active organization."}},"headers":{"Idempotency-Key":{"tipo":"string","desc":"Stable key for this launch. A replay returns the same campaign and never freezes a second recipient set.","obrigatorio":true}},"corpo":{"scheduled_for":{"tipo":"string","desc":"When to send, ISO-8601 with offset, interpreted in the organization's timezone. Omit to send now."}},"body":{"scheduled_for":"2026-08-30T14:00:00-03:00"},"retorno":{"campaign":{"tipo":"Campaign","desc":"The campaign, now scheduled or sending, with the frozen recipient count."},"dispatch_job_id":{"tipo":"string","desc":"The dispatch job that will walk the frozen set.","nulo":true},"replayed":{"tipo":"bool","desc":"True when this was a replay and nothing new was frozen or queued."}},"erros":{"400":"Missing Idempotency-Key or an unparseable schedule.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"Already launched, marketing paused for the organization, or no eligible recipients.","429":"Not enough capacity for the frozen recipient set."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/campaigns/$CAMPAIGN/launch -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{\"scheduled_for\":\"2026-08-30T14:00:00-03:00\"}'","returns":"{ campaign{id,name,status,domain_id,audience_id,template_id,template_version,scheduled_for,frozen_recipients,created_at}, dispatch_job_id, replayed }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns/:campaign_id/launch","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/organizations/:organization_id/campaigns/:campaign_id/report","auth":"organization","grupo":"Campaigns","summary":"Reconcile a campaign: delivery counts and normalized feedback counts.","desc":"Counts only. Which specific person opened what is not something this API answers.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"campaign_id":{"desc":"Campaign ID inside the active organization."}},"retorno":"CampaignReport","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/campaigns/$CAMPAIGN/report -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ campaign{id,name,status,domain_id,audience_id,template_id,template_version,scheduled_for,frozen_recipients,created_at}, deliveries, events }","url":"https://commsharbor.com/api/organizations/:organization_id/campaigns/:campaign_id/report","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/messaging-settings","auth":"organization","grupo":"Deliverability","summary":"Read the organization's timezone and whether marketing is currently paused.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"MessagingSettings","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/messaging-settings -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ timezone, marketing_state, paused_reason }","url":"https://commsharbor.com/api/organizations/:organization_id/messaging-settings","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"PATCH","path":"/api/organizations/:organization_id/messaging-settings","auth":"organization_campaign_write","grupo":"Deliverability","summary":"Change the scheduling timezone, or pause and safely resume marketing.","desc":"Pausing is always allowed. Resuming is not: if the pause came from reputation or SES tenant risk, a healthy observation has to exist first.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"timezone":{"tipo":"string","desc":"IANA timezone used to interpret campaign schedules, e.g. `America/Sao_Paulo`."},"marketing_state":{"tipo":"string","desc":"Whether marketing may go out.","valores":["active","paused"]}},"body":{"timezone":"America/Sao_Paulo","marketing_state":"active"},"retorno":"MessagingSettings","erros":{"400":"Unknown timezone or state.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"Resuming while the risk that caused the pause is still observed."},"exemplo":"curl -s -XPATCH $ORIGIN/api/organizations/$ORG/messaging-settings -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"timezone\":\"America/Sao_Paulo\"}'","returns":"{ timezone, marketing_state, paused_reason }","url":"https://commsharbor.com/api/organizations/:organization_id/messaging-settings","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/organizations/:organization_id/deliverability","auth":"organization","grupo":"Deliverability","summary":"Read delivery, backlog, suppression, reputation and dead-letter aggregates in one call.","desc":"This is the operator's single view of whether sending is healthy. It carries no recipient PII.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"settings":{"tipo":"MessagingSettings","desc":"Timezone and marketing state."},"deliveries":{"tipo":"object","desc":"Delivery counts by state."},"backlog":{"tipo":"object","desc":"What is still queued and how old the oldest item is."},"dead_letters":{"tipo":"object","desc":"Dead-letter counts by origin."},"suppressions":{"tipo":"object","desc":"Suppression counts by scope."},"domains":{"tipo":"object[]","desc":"Per-domain reputation and state."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/deliverability -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ settings{timezone,marketing_state,paused_reason}, deliveries, backlog, dead_letters, suppressions, domains }","url":"https://commsharbor.com/api/organizations/:organization_id/deliverability","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/domains/:domain_id/report","auth":"organization","grupo":"Deliverability","summary":"Read delivery and feedback aggregates for one sending domain.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"domain_id":{"desc":"Sending domain ID, from the domains listing."}},"retorno":{"domain":{"tipo":"Domain","desc":"The domain being reported on."},"deliveries":{"tipo":"object","desc":"Delivery counts by state for this domain."},"events":{"tipo":"object","desc":"Normalized feedback counts by event type."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/domains/$DOMAIN/report -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ domain{id,domain,status,dkim_tokens,dmarc,mail_from,last_observed_at,created_at}, deliveries, events }","url":"https://commsharbor.com/api/organizations/:organization_id/domains/:domain_id/report","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/webhooks","auth":"organization","grupo":"Webhooks","summary":"List the webhook endpoints of the organization, without their signing secrets.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Lista<Webhook>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/webhooks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,url,event_types,status,created_at,secret?}] }","url":"https://commsharbor.com/api/organizations/:organization_id/webhooks","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/webhooks","auth":"organization_campaign_write","grupo":"Webhooks","summary":"Create an HTTPS webhook and reveal its signing secret exactly once.","desc":"Deliveries are signed with timestamped HMAC-SHA256 and retried with exponential backoff; what still fails lands in the tenant-scoped dead-letter queue. Store the secret now — it is never shown again.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"url":{"tipo":"string","desc":"Public HTTPS destination. Plain HTTP is refused.","obrigatorio":true},"event_types":{"tipo":"string[]","desc":"Which events to deliver. Delivery feedback: `Delivery`, `DeliveryDelay`, `Bounce`, `Complaint`, `Reject`, `RenderingFailure`, `Open`, `Click`. Campaigns: `campaign.completed`, `campaign.paused`. Inbound: `inbox.message.received` and `inbox.reply.matched`, the reply correlated to the delivery that provoked it.","obrigatorio":true}},"body":{"url":"https://receiver.example.com/events","event_types":["Delivery","Bounce"]},"retorno":"Webhook","erros":{"400":"Non-HTTPS URL or an unknown event type.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/webhooks -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"url\":\"https://receiver.example.com/events\",\"event_types\":[\"Delivery\"]}'","returns":"{ id, url, event_types, status, created_at, secret? }","url":"https://commsharbor.com/api/organizations/:organization_id/webhooks","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/organizations/:organization_id/webhooks/:webhook_id","auth":"organization","grupo":"Webhooks","summary":"Read one webhook, without its signing secret.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"webhook_id":{"desc":"Webhook endpoint ID. Signing secrets are revealed once, at creation."}},"retorno":"Webhook","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/webhooks/$WEBHOOK -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, url, event_types, status, created_at, secret? }","url":"https://commsharbor.com/api/organizations/:organization_id/webhooks/:webhook_id","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"DELETE","path":"/api/organizations/:organization_id/webhooks/:webhook_id","auth":"organization_campaign_write","grupo":"Webhooks","summary":"Disable a webhook without deleting the evidence of what it already delivered.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"webhook_id":{"desc":"Webhook endpoint ID. Signing secrets are revealed once, at creation."}},"retorno":"Webhook","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XDELETE $ORIGIN/api/organizations/$ORG/webhooks/$WEBHOOK -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, url, event_types, status, created_at, secret? }","url":"https://commsharbor.com/api/organizations/:organization_id/webhooks/:webhook_id","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/organizations/:organization_id/webhooks/:webhook_id/deliveries","auth":"organization","grupo":"Webhooks","summary":"List the signed attempts made to one webhook and their retry state.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"webhook_id":{"desc":"Webhook endpoint ID. Signing secrets are revealed once, at creation."}},"retorno":{"items":{"tipo":"object[]","desc":"One record per attempt: status, response code, when it ran and when it will retry."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/webhooks/$WEBHOOK/deliveries -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items }","url":"https://commsharbor.com/api/organizations/:organization_id/webhooks/:webhook_id/deliveries","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"GET","path":"/api/organizations/:organization_id/dead-letters","auth":"organization","grupo":"Webhooks","summary":"Inspect the tenant's dead letters by opaque record ID.","desc":"What ended up here after every retry. Records are addressed by opaque ID and carry no recipient PII.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"items":{"tipo":"object[]","desc":"One record per dead letter: origin, reason, when it failed."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/dead-letters -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items }","url":"https://commsharbor.com/api/organizations/:organization_id/dead-letters","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/dead-letters/:record_id/replay","auth":"organization_campaign_write","grupo":"Webhooks","summary":"Replay one campaign or webhook dead letter, by name.","desc":"One record at a time, addressed explicitly. There is no \"replay everything\": a bulk replay of an unknown set is how a bad hour becomes a bad day.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"record_id":{"desc":"Dead-letter record ID from the dead-letter listing."}},"body":{},"retorno":{"dead_letter":{"tipo":"object","desc":"The record with its new replay state."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The record was already replayed or is not replayable."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/dead-letters/$RECORD/replay -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ dead_letter }","url":"https://commsharbor.com/api/organizations/:organization_id/dead-letters/:record_id/replay","auth_detail":"Active organization identity with campaign:write permission. Campaign launches require Idempotency-Key."},{"method":"GET","path":"/api/billing","auth":"none","grupo":"Billing","summary":"Read the versioned trial, pass and top-up catalog, plus the x402 network in force.","desc":"Public and unauthenticated: an agent should be able to learn what things cost before deciding whether to sign up at all.","retorno":"BillingPublic","exemplo":"curl -s $ORIGIN/api/billing","returns":"{ catalog{version,trial,pass,topup,checkout_live,global_recipient_hard_cap,auto_renew}, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,gratis?,facilitator,asset,asset_address,faucet,wallets}, invite_only }","url":"https://commsharbor.com/api/billing","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/organizations/:organization_id/billing","auth":"organization","grupo":"Billing","summary":"Read this organization's entitlement, quota allocation and expiration warning.","desc":"Read this before a bulk send: `state` says how many sends remain and `warning` says when the entitlement runs out.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"BillingTenant","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/billing -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ catalog{version,trial,pass,topup,checkout_live,global_recipient_hard_cap,auto_renew}, state, warning, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,gratis?,facilitator,asset,asset_address,faucet,wallets} }","url":"https://commsharbor.com/api/organizations/:organization_id/billing","auth_detail":"Session plus X-Organization-Id membership, or a scoped API key that determines the organization."},{"method":"POST","path":"/api/organizations/:organization_id/billing/purchases/:action","auth":"organization_admin","grupo":"Billing","summary":"Request a pass or a top-up. While live checkout is off, this answers with an x402 challenge.","desc":"The response is a standard **402 with `accepts[]`** unless `catalog.checkout_live` is true — nobody is charged by accident. The Idempotency-Key makes a retry safe: the same logical purchase never grants entitlement twice.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"action":{"desc":"Which purchase to request.","valores":["pass","topup"]}},"headers":{"Idempotency-Key":{"tipo":"string","desc":"Stable key for this logical purchase. A replay returns the same state and grants nothing extra.","obrigatorio":true},"X-PAYMENT":{"tipo":"string","desc":"Standard x402 payment payload, when live checkout is explicitly enabled.","obrigatorio":false}},"body":{},"retorno":{"replayed":{"tipo":"bool","desc":"True when this key had already been used and nothing new was granted."},"state":{"tipo":"object","desc":"The entitlement after the request: what is active, what remains, when it expires."}},"erros":{"400":"Missing Idempotency-Key, or an action other than `pass`/`topup`.","401":"No session, no API key, or the credential does not resolve to this organization.","402":"Payment required — the body carries `accepts[]`. This is the normal answer while live checkout is disabled.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The same key was used for a different purchase."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/billing/purchases/pass -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H \"Idempotency-Key: $KEY\" -H 'content-type: application/json' -d '{}'","returns":"{ replayed, state }","url":"https://commsharbor.com/api/organizations/:organization_id/billing/purchases/:action","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/operations","auth":"organization_admin","grupo":"Operations","summary":"List the organization's current operational alerts.","desc":"Covers dead letters, backlog, worker and SNS failures, reputation, paused sending, quota and conservative SES/SNS cost capacity — never with recipient PII.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":{"items":{"tipo":"object[]","desc":"One entry per active alert, with its kind, severity and what to do about it."}},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/operations -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items }","url":"https://commsharbor.com/api/organizations/:organization_id/operations","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/operations","auth":"organization_admin","grupo":"Operations","summary":"Re-observe alerts, quota and global capacity right now.","desc":"The GET reads what was last stored; this goes and looks again. Same distinction as domain verification.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"body":{},"retorno":"Operations","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/operations -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ alerts, billing, capacity }","url":"https://commsharbor.com/api/organizations/:organization_id/operations","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/data-exports","auth":"organization_admin","grupo":"Data","summary":"List the tenant data exports, which are retained for seven days.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Lista<DataExport>","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/data-exports -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ items[{id,status,expires_at,created_at}] }","url":"https://commsharbor.com/api/organizations/:organization_id/data-exports","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/data-exports","auth":"organization_admin","grupo":"Data","summary":"Create a tenant-scoped JSON export of the organization's data.","desc":"Scoped to one organization by construction: an export can never contain another tenant's data.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"body":{},"retorno":"DataExport","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/data-exports -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ id, status, expires_at, created_at }","url":"https://commsharbor.com/api/organizations/:organization_id/data-exports","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/data-exports/:export_id","auth":"organization_admin","grupo":"Data","summary":"Download one tenant-scoped JSON export before it expires.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"export_id":{"desc":"Tenant data export ID. Exports expire seven days after they are created."}},"retorno":{"_texto":"`application/json` as an attachment, with the organization's data."},"erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The export is not ready yet.","410":"It expired after seven days."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/data-exports/$EXPORT -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"`application/json` as an attachment, with the organization's data.","url":"https://commsharbor.com/api/organizations/:organization_id/data-exports/:export_id","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"GET","path":"/api/organizations/:organization_id/deletion-requests","auth":"organization_admin","grupo":"Data","summary":"Read the latest erasure request and where it is in the grace period.","desc":"`status: \"none\"` means no erasure was ever requested — the resource always answers, so a client never has to interpret a 404 as \"nothing scheduled\".","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"retorno":"Deletion","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere."},"exemplo":"curl -s $ORIGIN/api/organizations/$ORG/deletion-requests -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\"","returns":"{ id, status, scheduled_for, requested_by }","url":"https://commsharbor.com/api/organizations/:organization_id/deletion-requests","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/deletion-requests","auth":"organization_admin","grupo":"Data","summary":"Schedule the erasure of the organization, after a seven-day grace period.","desc":"The confirmation phrase must be exactly `delete <organization_id>` — typing the id is the point, so nobody erases the wrong tenant by clicking. After erasure only pseudonymous financial and audit evidence remains.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."}},"corpo":{"confirmation":{"tipo":"string","desc":"The exact phrase `delete <organization_id>`.","obrigatorio":true}},"body":{"confirmation":"delete org_…"},"retorno":"Deletion","erros":{"400":"The confirmation phrase does not match this organization exactly.","401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"An erasure is already scheduled."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/deletion-requests -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{\"confirmation\":\"delete $ORG\"}'","returns":"{ id, status, scheduled_for, requested_by }","url":"https://commsharbor.com/api/organizations/:organization_id/deletion-requests","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/organizations/:organization_id/deletion-requests/:request_id/cancel","auth":"organization_admin","grupo":"Data","summary":"Cancel a scheduled erasure while it is still inside the grace period.","desc":"That is what the seven days are for: after they pass, there is nothing left to cancel.","params":{"organization_id":{"desc":"Active organization ID. It must match the organization your session header or API key resolves to."},"request_id":{"desc":"Deletion request ID from the deletion-requests resource."}},"body":{},"retorno":"Deletion","erros":{"401":"No session, no API key, or the credential does not resolve to this organization.","403":"The identity is valid but lacks the required role or scope for this operation.","404":"The resource does not exist in this organization. Another tenant's ID answers the same 404 — the API never confirms that it exists elsewhere.","409":"The erasure already ran, or the request was cancelled before."},"exemplo":"curl -s -XPOST $ORIGIN/api/organizations/$ORG/deletion-requests/$REQUEST/cancel -H \"Authorization: Bearer $TOKEN\" -H \"X-Organization-Id: $ORG\" -H 'content-type: application/json' -d '{}'","returns":"{ id, status, scheduled_for, requested_by }","url":"https://commsharbor.com/api/organizations/:organization_id/deletion-requests/:request_id/cancel","auth_detail":"Human organization member with the required role; API keys cannot manage credentials or membership."},{"method":"POST","path":"/api/credito","auth":"none","summary":"Top up prepaid credit: pay once with x402 and get the token that debits on any API of the house.","grupo":"Credit","query":{"usd":{"tipo":"int","desc":"Package: 1, 5, 10 ou 25 dollars.","obrigatorio":true}},"retorno":{"token":{"tipo":"string","desc":"Bearer token for the balance (`cred_…`). Shown ONCE — it cannot be recovered."},"saldo_usd":{"tipo":"string","desc":"Credited balance."},"guarde":{"tipo":"string","desc":"Warning that the token is the bearer of the credit."},"usar":{"tipo":"string","desc":"How to present the token on paid routes."},"saldo_em":{"tipo":"string","desc":"Where to check balance and statement."}},"erros":{"400":"Package outside the list (1, 5, 10 ou 25).","402":"Unpaid — the body carries the x402 `accepts[]`."},"exemplo":"curl -s -XPOST '$ORIGIN/api/credito?usd=10'","returns":"{ token, saldo_usd, guarde, usar, saldo_em }","url":"https://commsharbor.com/api/credito","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/credito","auth":"credito","summary":"Credit balance and statement — the latest movements, without returning the token.","grupo":"Credit","retorno":{"saldo_micros":{"tipo":"int","desc":"Balance in micro-dollars (1e-6 USD)."},"saldo_usd":{"tipo":"string","desc":"Formatted balance."},"criado_em":{"tipo":"string","desc":"When the credit was opened."},"movimentos":{"tipo":"object[]","desc":"Recent credits and debits, with product and resource."}},"erros":{"401":"No token, or unknown token."},"exemplo":"curl -s $ORIGIN/api/credito -H 'Authorization: Bearer cred_…'","returns":"{ saldo_micros, saldo_usd, criado_em, movimentos }","url":"https://commsharbor.com/api/credito","auth_detail":"Prepaid credit token in `Authorization: Bearer cred_…` (or the `X-Credito` header). Not an account: it is a bearer of balance."},{"method":"POST","path":"/api/erro-cliente","auth":"none","summary":"Browser error report, sent by the interface itself. Agents need not call it.","grupo":"Operations","desc":"The interface reports on its own JS errors, unhandled rejections, scripts/CSS that failed to load and CSP blocks — once per session — and the app reports handled failures through `window.mmErro.relata`. The server validates the envelope, redacts credentials, e-mails and phone numbers, merges repeats of the same failure per minute and records an operational event; nothing is written to a database. It keeps no IP, cookie, query string or full User-Agent. Always answers 204, even for an invalid report.","corpo":{"code":{"tipo":"string","desc":"Failure code, `UI-` + letters/digits (`UI-JS-001` global error, `UI-PROMESSA-001`, `UI-RECURSO-001`, `UI-CSP-001`, `UI-APP-001` app report).","obrigatorio":true},"phase":{"tipo":"string","desc":"Where it broke, lowercase: `global`, `promessa`, `script`, `load_list`…","obrigatorio":true},"path":{"tipo":"string","desc":"Path of the open page, without query."},"message":{"tipo":"string","desc":"Error message, up to 2000 characters."},"stack":{"tipo":"string","desc":"Stack trace, up to 12000 characters."},"source":{"tipo":"string","desc":"Originating script; only its path is kept."},"line":{"tipo":"int","desc":"Line in the originating script."},"column":{"tipo":"int","desc":"Column in the originating script."},"visivel":{"tipo":"bool","desc":"Whether the tab was visible when it broke."}},"body":{"code":"UI-APP-001","phase":"carregar_lista","path":"/","message":"lista 500"},"retorno":{"_texto":"204 with no body, always — an invalid, repeated or over-cap report also gets 204."},"exemplo":"curl -s -XPOST $ORIGIN/api/erro-cliente -H 'content-type: application/json' -d '{\"code\":\"UI-APP-001\",\"phase\":\"carregar_lista\",\"path\":\"/\",\"message\":\"lista 500\"}'","returns":"204 with no body, always — an invalid, repeated or over-cap report also gets 204.","url":"https://commsharbor.com/api/erro-cliente","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/vitrine","auth":"none","grupo":"Public stats","summary":"The product's public numbers: traffic, agents, usage and reliability, no money.","desc":"Projection published hourly by the house collector, rounded to two significant digits; `null` is a missing measurement, never zero. 15-minute cache with ETag (`If-None-Match` → 304). There is no way to send numbers through this route: publishing belongs to the collector, with its own token.","retorno":{"v":{"tipo":"int","desc":"Contract version (1)."},"produto":{"tipo":"string","desc":"Product id."},"publicado":{"tipo":"bool","desc":"`false` before the collector's first publication; then only these five keys come."},"atualizado_em":{"tipo":"string","desc":"When the collector published (ISO 8601).","nulo":true},"stale":{"tipo":"bool","desc":"`true` when the projection is older than 26 h."},"nome":{"tipo":"string","desc":"Product name.","opcional":true},"desde":{"tipo":"string","desc":"First day the series covers.","nulo":true,"opcional":true},"fuso":{"tipo":"string","desc":"Time zone of the days (`UTC`).","opcional":true},"hoje":{"tipo":"object","desc":"Today: pages by class (human, AI, bot), API calls by class, machine-surface reads and product usage.","opcional":true},"dias":{"tipo":"object[]","desc":"Up to 31 days, oldest first: `dia`, `paginas`, `api`, `api_ia`, `maquina`, `visitantes`, `uso`.","opcional":true},"janelas":{"tipo":"object","desc":"7- and 30-day sums (`d7`, `d30`).","opcional":true},"visitantes":{"tipo":"object","desc":"Unique visitors at the edge over 7 days.","opcional":true},"pessoas":{"tipo":"object","desc":"GA4 when available: users, sessions, countries, devices and who arrived from AI.","nulo":true,"opcional":true},"agentes":{"tipo":"object","desc":"The AI agents and bots that read the most, 7 days.","opcional":true},"superficies":{"tipo":"object","desc":"Reads of OKF, llms, well-known, OpenAPI and MCP over 7 days.","opcional":true},"mcp":{"tipo":"object","desc":"MCP calls over 7 days.","opcional":true},"uso":{"tipo":"object","desc":"Real product usage per resource: label, today, 7 and 30 days.","opcional":true},"contas":{"tipo":"object","desc":"Users and guests.","nulo":true,"opcional":true},"confiabilidade":{"tipo":"object","desc":"Share of requests without 5xx over 7 days, and the live build.","opcional":true},"catalogo":{"tipo":"object","desc":"Size of the catalog, when the product has one.","nulo":true,"opcional":true},"apoio":{"tipo":"object","desc":"Impressions and clicks per sponsor, when any.","opcional":true}},"exemplo":"curl -s $ORIGIN/api/vitrine","returns":"{ v, produto, publicado, atualizado_em, stale, nome?, desde?, fuso?, hoje?, dias?, janelas?, visitantes?, pessoas?, agentes?, superficies?, mcp?, uso?, contas?, confiabilidade?, catalogo?, apoio? }","url":"https://commsharbor.com/api/vitrine","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/vitrine/operador","auth":"none","grupo":"Public stats","summary":"The product's full document on the operator panel — operator token only.","headers":{"Authorization":{"tipo":"string","desc":"`Bearer <METRICS_TOKEN>` — the operator class.","obrigatorio":true}},"retorno":{"produto":{"tipo":"string","desc":"Product id."},"atualizado_em":{"tipo":"string","desc":"When the collector published.","nulo":true},"operador":{"tipo":"object","desc":"The collector's full document, with what the public projection leaves out.","nulo":true}},"erros":{"401":"No token, wrong token or a token of another class.","503":"Worker without `METRICS_TOKEN` or without the control plane."},"exemplo":"curl -s $ORIGIN/api/vitrine/operador -H \"Authorization: Bearer $METRICS_TOKEN\"","returns":"{ produto, atualizado_em, operador }","url":"https://commsharbor.com/api/vitrine/operador","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/vitrine/painel","auth":"none","grupo":"Public stats","summary":"The whole house panel, in the shape the gm reads — operator token only.","headers":{"Authorization":{"tipo":"string","desc":"`Bearer <METRICS_TOKEN>` — the operator class.","obrigatorio":true}},"retorno":{"apps":{"tipo":"object[]","desc":"One operator document per product, ordered by id."},"updated":{"tipo":"string","desc":"When the collector closed the round.","opcional":true},"totals":{"tipo":"object","desc":"House totals.","opcional":true}},"erros":{"401":"No token, wrong token or a token of another class.","503":"Worker without `METRICS_TOKEN` or without the control plane."},"exemplo":"curl -s $ORIGIN/api/vitrine/painel -H \"Authorization: Bearer $METRICS_TOKEN\"","returns":"{ apps, updated?, totals? }","url":"https://commsharbor.com/api/vitrine/painel","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/vitrine/cursores","auth":"none","grupo":"Public stats","summary":"The resolved-error cursor per product (`borda`, `cli`) — operator token only.","headers":{"Authorization":{"tipo":"string","desc":"`Bearer <METRICS_TOKEN>` — the operator class.","obrigatorio":true}},"retorno":{"_texto":"JSON: `{ [product]: { borda?: ISO, cli?: ISO } }`; empty is `{}`."},"erros":{"401":"No token, wrong token or a token of another class.","503":"Worker without `METRICS_TOKEN` or without the control plane."},"exemplo":"curl -s $ORIGIN/api/vitrine/cursores -H \"Authorization: Bearer $METRICS_TOKEN\"","returns":"JSON: `{ [product]: { borda?: ISO, cli?: ISO } }`; empty is `{}`.","url":"https://commsharbor.com/api/vitrine/cursores","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/partners","auth":"none","grupo":"Partnership","summary":"Partnership, sponsorship and advertising: the product's placements with a suggested price, the public numbers next to them and how to propose.","desc":"Information on request, no activation: placements from the house catalogue priced in USD per 30 days (90 and 365 days discounted), sponsors in effect, an excerpt of `/api/vitrine`, the house wallet (USDC on Base) and the contact path — bank deposit, PIX or invoice are arranged in the reply. Cached for 1 hour.","retorno":{"status":{"tipo":"string","desc":"`sob_consulta`: information and proposal, no activation and no charge."},"produto":{"tipo":"string","desc":"Product name."},"idioma":{"tipo":"string","desc":"Language of the texts (the product's)."},"titulo":{"tipo":"string","desc":"Title of the offer."},"descricao":{"tipo":"string","desc":"One sentence about the offer."},"publico":{"tipo":"string","desc":"Who uses the product — the audience a sponsor reaches."},"modalidades":{"tipo":"object[]","desc":"`{ id, nome }`: patrocinio, parceria, anuncio."},"placements":{"tipo":"object[]","desc":"The product's placements: `id`, `nome`, `onde`, `formato`, `exclusivo`, `medicao`, `price_usd_30d` (suggested; `null` is on request), `exposure[{ dias, price_usd }]` for 30, 90 and 365 days, `disponivel`."},"house_bundle":{"tipo":"object","desc":"The house bundle: footer and agent mention across the ten products, discounted."},"parcerias":{"tipo":"string[]","desc":"Partnership ideas the product is open to discuss."},"current_sponsors":{"tipo":"object[]","desc":"Sponsors in effect: `id`, `nome`, `url`, `frase`, `espacos`, `ate`."},"stats":{"tipo":"object","desc":"Excerpt of the public numbers (`hoje`, `janelas`, `agentes`, `confiabilidade`) and the `link` to `/api/vitrine`; `publicado: false` before the first publication."},"payment":{"tipo":"object","desc":"How to pay: `rede`, `chain_id`, `ativo`, `pay_to`, `eip681` (the house wallet, when declared), `alternativas` and the `nota` — bank deposit, PIX or invoice in the reply."},"contact":{"tipo":"object","desc":"`email`, `form_url`, `api_url` (`POST /api/contact` where the handler exists), `campos` (required), `campos_proposta` (the optional proposal fields, each with its accepted values), `price_agent_usd`, `message_template`, `instructions`."},"politica":{"tipo":"object","desc":"Placement label, refused sectors, prepayment, deadlines."},"_links":{"tipo":"object","desc":"`self`, `stats`, `page` (`null` until the page exists), `contact`, `casa` (the same path on the ten products)."}},"exemplo":"curl -s $ORIGIN/api/partners","returns":"{ status, produto, idioma, titulo, descricao, publico, modalidades, placements, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }","url":"https://commsharbor.com/api/partners","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/metrics","auth":"none","summary":"Last-7-day metrics for the operator dashboard; with the token, payments come along.","grupo":"Operations","desc":"Without credentials it returns product usage: deliveries per day and organization totals. With `METRICS_TOKEN` as Bearer it adds `payments` — x402 settled on Base mainnet only.","headers":{"Authorization":{"tipo":"string","desc":"`Bearer <METRICS_TOKEN>` to include the financial block; a wrong token is 401.","obrigatorio":false}},"retorno":"Metricas","erros":{"401":"Wrong operator token.","503":"Worker without METRICS_TOKEN configured."},"exemplo":"curl -s $ORIGIN/api/metrics -H \"Authorization: Bearer $METRICS_TOKEN\"","returns":"{ app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments? }","url":"https://commsharbor.com/api/metrics","auth_detail":"Public endpoint. No tenant data is returned."},{"method":"GET","path":"/api/pricing","auth":"none","grupo":"Discovery","summary":"Current prices and free allowances.","retorno":{"product":{"tipo":"string","desc":"Product name."},"quota":{"tipo":"PaymentQuota","desc":"Public allowances and current list prices; not personal usage."},"pricing":{"tipo":"string","desc":"Absolute URL of the current price list."},"billing":{"tipo":"string","desc":"Absolute URL of payment discovery or the existing billing summary."},"api_index":{"tipo":"string","desc":"Absolute URL of the API catalog."}},"erros":{"405":"Use GET or HEAD."},"exemplo":"curl -s $ORIGIN/api/pricing","returns":"{ product, quota{free,paid,how_to_pay,live,free_now?,trial?}, pricing, billing, api_index }","url":"https://commsharbor.com/api/pricing","auth_detail":"Public endpoint. No tenant data is returned."}],"mcp":{"endpoint":"https://commsharbor.com/mcp","transport":"streamable-http","tools":150},"mcp_tools":["commsharbor_health","commsharbor_logout","commsharbor_me","commsharbor_organizations","commsharbor_organization_create","commsharbor_context","commsharbor_organization_get","commsharbor_organization_update","commsharbor_members","commsharbor_member_role","commsharbor_invitations","commsharbor_invitation_create","commsharbor_invitation_accept","commsharbor_api_keys","commsharbor_api_key_create","commsharbor_api_key_revoke","commsharbor_audit","commsharbor_platform_context","commsharbor_domains","commsharbor_domain_create","commsharbor_domain_get","commsharbor_domain_verify","commsharbor_domain_smoke","commsharbor_domain_deliveries","commsharbor_delivery_get","commsharbor_delivery_events","commsharbor_crm_contacts_list","commsharbor_crm_contacts_create","commsharbor_crm_contacts_get","commsharbor_crm_contacts_update","commsharbor_crm_contacts_delete","commsharbor_crm_companies_list","commsharbor_crm_companies_create","commsharbor_crm_companies_get","commsharbor_crm_companies_update","commsharbor_crm_companies_delete","commsharbor_crm_pipelines_list","commsharbor_crm_pipelines_create","commsharbor_crm_pipelines_get","commsharbor_crm_pipelines_update","commsharbor_crm_pipelines_delete","commsharbor_crm_deals_list","commsharbor_crm_deals_create","commsharbor_crm_deals_get","commsharbor_crm_deals_update","commsharbor_crm_deals_delete","commsharbor_crm_activities_list","commsharbor_crm_activities_create","commsharbor_crm_activities_get","commsharbor_crm_activities_update","commsharbor_crm_activities_delete","commsharbor_crm_tasks_list","commsharbor_crm_tasks_create","commsharbor_crm_tasks_get","commsharbor_crm_tasks_update","commsharbor_crm_tasks_delete","commsharbor_crm_stages_list","commsharbor_crm_stages_create","commsharbor_crm_stages_get","commsharbor_crm_stages_update","commsharbor_crm_stages_delete","commsharbor_platform_crm_leads_list","commsharbor_platform_crm_leads_create","commsharbor_platform_crm_leads_get","commsharbor_platform_crm_leads_update","commsharbor_platform_crm_leads_delete","commsharbor_platform_crm_tasks_list","commsharbor_platform_crm_tasks_create","commsharbor_platform_crm_tasks_get","commsharbor_platform_crm_tasks_update","commsharbor_platform_crm_tasks_delete","commsharbor_platform_crm_activities_list","commsharbor_platform_crm_activities_create","commsharbor_platform_crm_activities_get","commsharbor_platform_crm_activities_update","commsharbor_platform_crm_activities_delete","commsharbor_contact_marketing_get","commsharbor_contact_marketing_put","commsharbor_preference_token_create","commsharbor_preference_get","commsharbor_preference_unsubscribe","commsharbor_marketing_smoke","commsharbor_contact_imports","commsharbor_contact_import_preview","commsharbor_contact_import_get","commsharbor_contact_import_confirm","commsharbor_contact_import_errors","commsharbor_contact_file_get","commsharbor_contacts_export","commsharbor_suppressions","commsharbor_suppression_create","commsharbor_audiences","commsharbor_audience_create","commsharbor_audience_get","commsharbor_audience_update","commsharbor_audience_delete","commsharbor_audience_members","commsharbor_audience_member_add","commsharbor_audience_member_remove","commsharbor_templates","commsharbor_template_create","commsharbor_template_get","commsharbor_template_update","commsharbor_template_archive","commsharbor_template_publish","commsharbor_template_versions","commsharbor_template_preview","commsharbor_template_export","commsharbor_template_import_html","commsharbor_message_send","commsharbor_campaigns","commsharbor_campaign_create","commsharbor_campaign_get","commsharbor_campaign_update","commsharbor_campaign_launch","commsharbor_campaign_report","commsharbor_messaging_settings","commsharbor_messaging_settings_update","commsharbor_deliverability","commsharbor_domain_report","commsharbor_webhooks","commsharbor_webhook_create","commsharbor_webhook_get","commsharbor_webhook_disable","commsharbor_webhook_deliveries","commsharbor_dead_letters","commsharbor_dead_letter_replay","commsharbor_billing_catalog","commsharbor_billing","commsharbor_billing_purchase","commsharbor_operations","commsharbor_operations_refresh","commsharbor_data_exports","commsharbor_data_export_create","commsharbor_data_export_download","commsharbor_deletion_request","commsharbor_deletion_schedule","commsharbor_deletion_cancel","commsharbor_tracking_domain","commsharbor_tracking_domain_create","commsharbor_tracking_domain_verify","commsharbor_tracking_domain_remove","commsharbor_inboxes","commsharbor_inbox_create","commsharbor_inbox_get","commsharbor_inbox_disable","commsharbor_inbox_messages","commsharbor_inbox_message","commsharbor_inbox_attachment","pricing"]}