Channels API
Configure outbound and inbound messaging, manage send/receive addresses and explicit inbound routes, queue messages, and audit activity. Each channel config is rooted in a zero-trust channel zone, so access is governed by per-channel and per-address grants. Conversations consumes route snapshots to create or continue one participant thread, request exactly one Workflows item for a process route, and invoke the effective auto-reply agent independently. Address-gate changes publish `channels.inbound_route.address_gate.updated`.
/api/v1/channelsAutomation triggers: view every Channels event, payload field, and predicate.
Configs
Create and manage email setups per company. Platform Domain uses an Ergon-owned domain immediately; Custom Domain verifies a customer-owned domain. Both create virtual/routed addresses, not mailboxes. Connected Mailbox is Coming soon. Each config roots a zero-trust channel zone at org/{company_id}/channel/{config_id}.
/api/v1/channels/configsCreate Config
Register a Platform Domain or Custom Domain configuration. Connected Mailbox is reserved but not yet available. The API uses integration_type with no aliases for historical provider values.
Bearer token required. x-company-id header required.
Request Body
| Name | Type | Description |
|---|---|---|
name* | string | Display name (1–200 characters) |
integration_type* | "platform-domain" | "custom-domain" | "connected-mailbox" | Email setup model. Connected mailbox is Coming soon and rejected. |
domain | string | Customer-owned domain for custom-domain (3–253 characters). Omit for platform-domain. |
channel_type | string | Channel implementation slugDefault: email |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string | Config ID |
company_id* | string | Owning company ID |
channel_type* | string | Channel type slug |
integration_type* | "platform-domain" | "custom-domain" | "connected-mailbox" | "business-account" | Provider-neutral setup model for email and WhatsApp Business accounts. |
name* | string | Display name |
domain* | string | null | Configured domain |
status* | string | Lifecycle status (e.g. pending_dns, verifying, verified) |
setup_details* | object | null | Safe, channel-specific setup metadata. Email details include kind=email plus DNS records or the Platform Domain mail namespace; WhatsApp details expose operational identifiers but never secrets. |
inbound_enabled* | boolean | Whether inbound handling is enabled for this config |
created_at* | string | Creation time (ISO 8601) |
updated_at* | string | Last update time (ISO 8601) |
capabilities | object | What the calling principal may do with this config |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs \
-H "Authorization: Bearer {token}" \
-H "x-company-id: {company_id}" \
-H "Content-Type: application/json" \
-d '{
"name": "Primary email",
"integration_type": "custom-domain",
"domain": "mail.example.com",
"channel_type": "email"
}'Response
201 Created{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "email",
"integration_type": "custom-domain",
"name": "Primary email",
"domain": "mail.example.com",
"status": "pending_dns",
"setup_details": {
"kind": "email",
"dns_records": [
{
"type": "TXT",
"name": "resend._domainkey.mail.example.com",
"value": "p=MIGfMA0GCS..."
}
]
},
"inbound_enabled": false,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-01T12:00:00Z",
"capabilities": {
"can_list_addresses": true,
"can_create_address": true,
"can_delete_address": true,
"can_send": true,
"manage_addresses": true,
"manage_settings": true,
"manage_security": true,
"view_activity": true
}
}/api/v1/channels/configsList Configs
Return all channel configs visible to the caller for their company.
Bearer token required. x-company-id header required.
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | ConfigResponse[] | Configs ordered by created_at descending |
curl https://platform.ergondata.ai/api/v1/channels/configs \
-H "Authorization: Bearer {token}" \
-H "x-company-id: {company_id}"Response
200 OK[
{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "email",
"integration_type": "custom-domain",
"name": "Primary email",
"domain": "mail.example.com",
"status": "verified",
"setup_details": { "kind": "email", "dns_records": [] },
"inbound_enabled": true,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-02T09:15:00Z",
"capabilities": { "can_send": true, "manage_settings": true }
}
]/api/v1/channels/configs/{config_id}Get Config
Fetch one config by ID. Custom Domain may refresh DNS records and verification status; Platform Domain is already verified.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id} \
-H "Authorization: Bearer {token}"Response
200 OK{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "email",
"integration_type": "custom-domain",
"name": "Primary email",
"domain": "mail.example.com",
"status": "verified",
"setup_details": {
"kind": "email",
"dns_records": []
},
"inbound_enabled": true,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-02T09:15:00Z",
"capabilities": { "can_send": true, "manage_settings": true }
}/api/v1/channels/configs/{config_id}Update Config
Update the display name for a config.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Request Body
| Name | Type | Description |
|---|---|---|
name | string | null | New display name |
curl -X PATCH https://platform.ergondata.ai/api/v1/channels/configs/{config_id} \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"name": "Primary email (updated)"}'Response
200 OK{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "email",
"integration_type": "custom-domain",
"name": "Primary email (updated)",
"domain": "mail.example.com",
"status": "verified",
"setup_details": { "kind": "email", "dns_records": [] },
"inbound_enabled": true,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-03T16:00:00Z"
}/api/v1/channels/configs/{config_id}/verifyVerify Config
Verify DNS for a Custom Domain and move it toward verified. Platform Domain requires no DNS verification.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/verify \
-H "Authorization: Bearer {token}"Response
200 OK{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "email",
"integration_type": "custom-domain",
"name": "Primary email",
"domain": "mail.example.com",
"status": "verifying",
"setup_details": { "kind": "email", "dns_records": [] },
"inbound_enabled": true,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-03T14:22:00Z"
}/api/v1/channels/configs/{config_id}/whatsapp/phone-numbersDiscover WhatsApp Phone Numbers
List phone numbers directly from the config's Meta WABA, including verification and quality state and whether each number is already connected.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Ready WhatsApp business-account config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | WhatsAppPhoneNumberCandidate[] | Meta-derived phone IDs, normalized numbers, verification/quality state, and local connected state |
total* | integer | Number of candidates returned by Meta |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/whatsapp/phone-numbers \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"phone_number_id": "123456789012345",
"business_phone_number": "+5511914409811",
"display_name": "Brazil support",
"verification_status": "VERIFIED",
"quality_rating": "GREEN",
"platform_type": "CLOUD_API",
"operational_status": "CONNECTED",
"connected": false,
"connected_address_id": null
}
],
"total": 1
}/api/v1/channels/configs/{config_id}/whatsapp/phone-numbersAdd WhatsApp Phone Number
Add one verified number discovered under the existing WABA. Channels re-fetches the number from Meta and derives every address field; the generic address endpoint cannot create WhatsApp numbers.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Ready WhatsApp business-account config ID |
Request Body
| Name | Type | Description |
|---|---|---|
phone_number_id* | string | Meta phone-number ID returned by the discovery endpoint |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/whatsapp/phone-numbers \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"phone_number_id":"123456789012345"}'Response
201 Created{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "+5511914409811",
"display_name": "Brazil support",
"direction": "both",
"status": "active",
"channel_type": "whatsapp",
"provider_phone_number_id": "123456789012345",
"operational_status": "connected",
"quality_rating": "GREEN"
}/api/v1/channels/configs/{config_id}/whatsapp/credentials/connectConnect WhatsApp Credentials
Re-run WhatsApp provisioning for the config: connect the Vault credential consumer for the channel principal, validate the Meta credentials, and refresh the config status. Use after granting or rotating the Vault credentials referenced by the config.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | WhatsApp business-account config ID |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/whatsapp/credentials/connect \
-H "Authorization: Bearer {token}"Response
200 OK{
"id": "8f2c1a00-1111-4222-8333-444455556666",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_type": "whatsapp",
"integration_type": "whatsapp-business-account",
"name": "WhatsApp support",
"status": "verified",
"setup_details": { "kind": "whatsapp", "provisioning_status": "ready" },
"inbound_enabled": true,
"created_at": "2026-04-01T12:00:00Z",
"updated_at": "2026-04-03T14:22:00Z"
}/api/v1/channels/configs/{config_id}Delete Config
Remove the config and integration-owned domain state. The account-level Resend webhook is deployment configuration and is never deleted by config lifecycle.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id} \
-H "Authorization: Bearer {token}"Response
204 No Content/api/v1/channels/companies/{company_id}/channel-prefsGet Channel Preferences
Get the current member's channel-tree presentation preferences. This is user-session UI state, not an agent tool or IAM resource.
Bearer user token required; token company must match company_id.
Path Parameters
| Name | Type | Description |
|---|---|---|
company_id* | string (UUID) | Company ID from the current user session |
Response Fields
| Name | Type | Description |
|---|---|---|
favorite_config_id | string (UUID) | null | Favorite channel config, if set |
config_order* | string (UUID)[] | Custom channel config ordering |
curl https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/channel-prefs \
-H "Authorization: Bearer {token}"Response
200 OK{
"favorite_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"config_order": ["8f2c1a00-1111-4222-8333-444455556666"]
}/api/v1/channels/companies/{company_id}/channel-prefsUpdate Channel Preferences
Partially update the current member's favorite channel and custom channel-tree order.
Bearer user token required; token company must match company_id.
Path Parameters
| Name | Type | Description |
|---|---|---|
company_id* | string (UUID) | Company ID from the current user session |
Request Body
| Name | Type | Description |
|---|---|---|
favorite_config_id | string (UUID) | null | Favorite channel config; null clears it |
config_order | string (UUID)[] | null | Replacement custom ordering |
curl -X PUT https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/channel-prefs \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"favorite_config_id":"8f2c1a00-1111-4222-8333-444455556666"}'Response
200 OK{
"favorite_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"config_order": []
}Addresses
Manage send/receive addresses under a config, and list every address visible to the current company.
/api/v1/channels/addressesList Company Addresses
List channel addresses for the caller's company. Optionally filter by channel type, direction, or only sendable verified addresses.
Bearer token required. x-company-id header required.
Query Parameters
| Name | Type | Description |
|---|---|---|
channel_type | string | Filter by config channel type (e.g. email) |
direction | string | Filter by direction: send, receive, or both |
sendable | boolean | When true, only active send/both addresses on verified configsDefault: false |
authorized_to_send | boolean | When true, filter rows by the caller's channels:addresses:send permission instead of channels:addresses:viewDefault: false |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | AddressResponse[] | id, channel_config_id, address, display_name, direction, status, channel_type, channel_name, timestamps |
curl "https://platform.ergondata.ai/api/v1/channels/addresses?sendable=true&channel_type=email" \
-H "Authorization: Bearer {token}" \
-H "x-company-id: {company_id}"Response
200 OK[
{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "hello@mail.example.com",
"display_name": "Support",
"direction": "both",
"status": "active",
"channel_type": "email",
"channel_name": "Primary email",
"created_at": "2026-04-02T10:00:00Z",
"updated_at": "2026-04-02T10:00:00Z"
}
]/api/v1/channels/configs/{config_id}/addressesCreate Address
Add an email address under a config. The address must use the config domain. Receive/both addresses require inbound to be available and may enable inbound on the config. WhatsApp numbers must use the Meta-backed discovery and add endpoints.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Request Body
| Name | Type | Description |
|---|---|---|
address* | string | Full address, e.g. support@mail.example.com (3–320 characters) |
display_name | string | null | Optional display name for From headers |
direction | string | send, receive, or bothDefault: send |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"address": "support@mail.example.com",
"display_name": "Support",
"direction": "send"
}'Response
201 Created{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "support@mail.example.com",
"display_name": "Support",
"direction": "send",
"status": "active",
"channel_type": null,
"channel_name": null,
"created_at": "2026-04-02T10:00:00Z",
"updated_at": "2026-04-02T10:00:00Z"
}/api/v1/channels/configs/{config_id}/addressesList Addresses
List all addresses belonging to a single channel config.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "support@mail.example.com",
"display_name": "Support",
"direction": "send",
"status": "active",
"channel_type": "email",
"channel_name": "Primary email",
"created_at": "2026-04-02T10:00:00Z",
"updated_at": "2026-04-02T10:00:00Z"
}
]/api/v1/channels/addresses/whatsapp/outboundList WhatsApp Outbound Addresses
List WhatsApp phone numbers the caller can send from: active send/both addresses on verified WhatsApp configs, filtered by the caller's send permission. Prefer this over the generic address list when starting or continuing WhatsApp outreach.
Bearer token required. Requires the X-Company-Id header.
Query Parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Page size (default 100, max 200) |
offset | integer | Pagination offset (default 0) |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | AddressResponse[] | WhatsApp addresses the caller may send from |
total* | integer | Total matching addresses |
curl "https://platform.ergondata.ai/api/v1/channels/addresses/whatsapp/outbound?limit=50" \
-H "Authorization: Bearer {token}" \
-H "X-Company-Id: {company_id}"Response
200 OK{
"items": [
{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "+5511914409811",
"display_name": "Brazil support",
"direction": "both",
"status": "active",
"channel_type": "whatsapp"
}
],
"total": 1
}/api/v1/channels/addresses/{address_id}/whatsapp/send-optionsGet WhatsApp Send Options
Return what may be sent from this WhatsApp address to one recipient right now: whether the 24-hour customer-service window is open (free-form allowed), when the session expires, and the approved utility templates enabled for the address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
address_id* | string (UUID) | WhatsApp address ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
to* | string | Recipient phone number in E.164 format |
limit | integer | Template page size (default 100, max 200) |
offset | integer | Template pagination offset (default 0) |
Response Fields
| Name | Type | Description |
|---|---|---|
free_form_allowed* | boolean | True when the 24-hour session window with this recipient is open |
session_expires_at* | string (ISO 8601) | null | When the open session window closes, if one exists |
items* | WhatsAppTemplateResponse[] | Approved, active utility templates enabled for this address |
total* | integer | Total templates available to this address |
curl "https://platform.ergondata.ai/api/v1/channels/addresses/{address_id}/whatsapp/send-options?to=%2B5511999999999" \
-H "Authorization: Bearer {token}"Response
200 OK{
"free_form_allowed": false,
"session_expires_at": null,
"items": [
{
"id": "77e3a9b2-1234-4cde-9f00-aabbccddeeff",
"name": "order_update",
"language": "pt_BR",
"category": "UTILITY",
"status": "APPROVED",
"components": [],
"is_active": true,
"allowed_address_ids": ["a1d2e3f4-5566-7788-99aa-bbccddeeff00"],
"last_synced_at": "2026-04-03T14:22:00Z"
}
],
"total": 1
}/api/v1/channels/addresses/{address_id}/whatsapp/contacts/{wa_id}/marketing-policyUpdate WhatsApp Marketing Policy
Record a marketing opt-out (or opt-in) for one WhatsApp contact on this address. Opted-out contacts are excluded from marketing template sends while transactional traffic continues.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
address_id* | string (UUID) | WhatsApp address ID |
wa_id* | string | WhatsApp contact ID (phone-derived) |
Request Body
| Name | Type | Description |
|---|---|---|
opted_out* | boolean | True to opt the contact out of marketing sends |
Response Fields
| Name | Type | Description |
|---|---|---|
wa_id* | string | WhatsApp contact ID |
opted_out* | boolean | Current marketing opt-out state |
updated_at* | string (ISO 8601) | When the policy was last changed |
curl -X PATCH https://platform.ergondata.ai/api/v1/channels/addresses/{address_id}/whatsapp/contacts/{wa_id}/marketing-policy \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"opted_out":true}'Response
200 OK{
"wa_id": "5511999999999",
"opted_out": true,
"updated_at": "2026-04-03T14:22:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}Update Address
Update the display name, direction, or status slug of an address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Request Body
| Name | Type | Description |
|---|---|---|
display_name | string | null | New display name |
direction | string | null | send, receive, or both |
status | string | null | Address status slug (e.g. active, disabled) |
curl -X PATCH https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id} \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"direction": "both"}'Response
200 OK{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "support@mail.example.com",
"display_name": "Support",
"direction": "both",
"status": "active",
"channel_type": null,
"channel_name": null,
"created_at": "2026-04-02T10:00:00Z",
"updated_at": "2026-04-03T11:30:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}Delete Address
Remove an address from the config and reconcile inbound settings if needed.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentSend
Queue an outbound message from a verified, active address. Enforces the channels:addresses:send ACL on the address and any matching service access grants.
/api/v1/channels/sendSend Message
Queue a message for asynchronous delivery. For cross-service sends, supply service_name and resource_id so a matching address grant is checked. Pass an optional Idempotency-Key header to make retries safe; a replay returns the original result with idempotent_replay set to true.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
channel | string | Channel to use; currently only emailDefault: email |
address_id* | string (UUID) | Sending address ID |
config* | object | Channel-specific payload. For email: to, subject, html, plus optional cc, bcc, reply_to, in_reply_to, and attachments |
service_name | string | null | Calling service slug for grant checks (e.g. workflows) |
resource_id | string | null | External resource ID for grant checks |
Response Fields
| Name | Type | Description |
|---|---|---|
status* | string | Typically queued |
channel* | string | Channel used |
log_id | string | null | Activity log row ID for tracking the send |
provider_id | string | null | Provider slug handling delivery |
provider_message_id | string | null | Outbound SMTP Message-ID set on the email, used for reply correlation |
thread_id | string | null | Channel thread ID for the outbound message |
idempotent_replay | boolean | True when the request matched a prior Idempotency-Key and was not re-dispatchedDefault: false |
curl -X POST https://platform.ergondata.ai/api/v1/channels/send \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: {idempotency_key}" \
-d '{
"channel": "email",
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"config": {
"to": ["customer@example.com"],
"subject": "Your order has shipped",
"html": "<p>Thanks for your purchase!</p>",
"reply_to": "support@mail.example.com",
"cc": [],
"bcc": []
},
"service_name": "workflows",
"resource_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}'Response
202 Accepted{
"status": "queued",
"channel": "email",
"log_id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"provider_id": "resend",
"provider_message_id": "<msg_01hqabc@mail.example.com>",
"thread_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"idempotent_replay": false
}/api/v1/channels/send/whatsappSend WhatsApp Message
Queue one outbound WhatsApp message from a send-capable address. The typed config carries the recipient and payload: free-form text, bucket-backed media, interactive reply buttons or list menus (all only inside the open 24-hour session window), or an approved template (allowed anytime). Check Get WhatsApp Send Options first to learn the session state and allowed templates.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
channel* | "whatsapp" | Channel discriminator |
address_id* | string (UUID) | Send-capable WhatsApp address the message goes out from |
config* | WhatsAppTextConfig | WhatsAppTemplatePayload | WhatsAppMediaPayload | WhatsAppInteractivePayload | Discriminated by `type` (text | template | media | interactive); every variant carries `to` in E.164 format |
service_name | string | Originating service for attribution |
resource_id | string (UUID) | Originating resource for attribution |
curl -X POST https://platform.ergondata.ai/api/v1/channels/send/whatsapp \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"channel": "whatsapp",
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"config": {"type": "text", "to": "+5511999999999", "text": "Your order shipped!"}
}'Response
202 Accepted{
"status": "queued",
"channel": "whatsapp",
"log_id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"provider_id": "whatsapp",
"thread_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"idempotent_replay": false
}WhatsApp Templates
Meta-approved message templates synchronized per WhatsApp config. Templates unlock outbound messages outside the 24-hour session window; each template must be explicitly enabled per address before agents can use it.
/api/v1/channels/configs/{config_id}/whatsapp/templatesList WhatsApp Templates
List the templates synchronized from Meta for this config, including approval status, activation state, and the addresses each template is enabled for.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | WhatsApp business-account config ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
limit | integer | Page size (default 100, max 200) |
offset | integer | Pagination offset (default 0) |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | WhatsAppTemplateResponse[] | Templates with name, language, category, Meta status, components, activation state, and allowed_address_ids |
total* | integer | Total templates for the config |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/whatsapp/templates \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"id": "77e3a9b2-1234-4cde-9f00-aabbccddeeff",
"name": "order_update",
"language": "pt_BR",
"category": "UTILITY",
"status": "APPROVED",
"components": [],
"is_active": true,
"allowed_address_ids": ["a1d2e3f4-5566-7788-99aa-bbccddeeff00"],
"last_synced_at": "2026-04-03T14:22:00Z"
}
],
"total": 1
}/api/v1/channels/configs/{config_id}/whatsapp/templates/syncSync WhatsApp Templates
Fetch the current template catalog from Meta and reconcile the local copy: new templates are added, changed ones updated, and removed ones deactivated. Returns the refreshed list.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | WhatsApp business-account config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | WhatsAppTemplateResponse[] | The synchronized template list |
total* | integer | Total templates after the sync |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/whatsapp/templates/sync \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"id": "77e3a9b2-1234-4cde-9f00-aabbccddeeff",
"name": "order_update",
"language": "pt_BR",
"category": "UTILITY",
"status": "APPROVED",
"components": [],
"is_active": true,
"allowed_address_ids": [],
"last_synced_at": "2026-04-05T09:00:00Z"
}
],
"total": 1
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/templates/{template_id}Allow Template For Address
Enable one approved template for one address under the config. Agents and API callers can only send templates that are enabled for the sending address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | WhatsApp business-account config ID |
address_id* | string (UUID) | WhatsApp address under the config |
template_id* | string (UUID) | Synchronized template ID |
curl -X PUT https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/templates/{template_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentHTTP/1.1 204 No Content/api/v1/channels/configs/{config_id}/addresses/{address_id}/templates/{template_id}Disallow Template For Address
Disable one template for one address under the config. Subsequent sends of that template from the address are rejected.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | WhatsApp business-account config ID |
address_id* | string (UUID) | WhatsApp address under the config |
template_id* | string (UUID) | Synchronized template ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/templates/{template_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentHTTP/1.1 204 No ContentActivity
Inspect the channel type registry, paginated message activity (company-wide or per channel), single events, inbound attachment bytes, and ordered thread transcripts.
/api/v1/channels/channel-typesList Channel Types
Registry of channel implementations (slug, display name, icon, active flag).
Bearer token required.
Query Parameters
| Name | Type | Description |
|---|---|---|
include_inactive | boolean | Include types marked inactiveDefault: false |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | ChannelTypeItem[] | Channel types |
curl "https://platform.ergondata.ai/api/v1/channels/channel-types?include_inactive=false" \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"slug": "email",
"name": "Email",
"icon": "mail",
"is_active": true
}
]/api/v1/channels/companies/{company_id}/activityList Activity
Paginated, company-wide activity log filtered to channels where the caller has channels:activity:view. channels:addresses:receive controls routing eligibility, not activity visibility.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
company_id* | string (UUID) | Company ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
channel | string | Filter by channel slug |
direction | string | Filter by message direction |
status | string | Comma-separated status slugs |
correlation_id | string | Match a correlation ID |
event_type | string | Filter by event type slug |
search | string | Case-insensitive match on from_address or subject |
date_from | string (ISO 8601) | Inclusive lower bound on created_at |
date_to | string (ISO 8601) | Inclusive upper bound on created_at |
page | integer | Page number (1-based)Default: 1 |
limit | integer | Page size (1–100)Default: 50 |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | ActivityLogListItem[] | id, event_type, channel, direction, from_address, to_addresses, subject, status, actor_type, error, created_at, optional correlation_id and summary |
total* | integer | Total matching rows |
page* | integer | Current page |
limit* | integer | Page size |
curl "https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/activity?page=1&limit=50&channel=email" \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"event_type": "channels.email.sent",
"channel": "email",
"direction": "outbound",
"from_address": "Support <support@mail.example.com>",
"to_addresses": ["customer@example.com"],
"subject": "Your order has shipped",
"status": "queued",
"actor_type": "member",
"correlation_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"summary": null,
"error": null,
"created_at": "2026-04-06T15:22:11Z"
}
],
"total": 128,
"page": 1,
"limit": 50
}/api/v1/channels/companies/{company_id}/activity/{event_id}Get Activity Event
Full detail for one company activity row, including payload and provider identifiers. Requires channels:activity:view on the row's channel.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
company_id* | string (UUID) | Company ID |
event_id* | string (UUID) | Activity log row ID |
curl https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/activity/{event_id} \
-H "Authorization: Bearer {token}"Response
200 OK{
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"event_type": "channels.email.sent",
"channel": "email",
"direction": "outbound",
"from_address": "Support <support@mail.example.com>",
"to_addresses": ["customer@example.com"],
"subject": "Your order has shipped",
"status": "delivered",
"actor_type": "member",
"actor_id": "9a000000-0000-4000-8000-000000000001",
"correlation_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"summary": null,
"error": null,
"payload": {
"html": "<p>Tracking: <b>1Z999...</b></p>",
"text": "Tracking: 1Z999..."
},
"provider_id": "resend",
"provider_message_id": "<msg_01hqabc@mail.example.com>",
"created_at": "2026-04-06T15:22:11Z"
}/api/v1/channels/configs/{config_id}/activityList Channel Activity
Paginated immutable activity log scoped to a single channel config. Inbound rows require only channels:activity:view on the channel; subscription delivery state is exposed separately by the deliveries and claim APIs.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
direction | string | Filter by message direction |
status | string | Comma-separated status slugs |
correlation_id | string | Match a correlation ID |
event_type | string | Filter by event type slug |
search | string | Case-insensitive match on from_address or subject |
date_from | string (ISO 8601) | Inclusive lower bound on created_at |
date_to | string (ISO 8601) | Inclusive upper bound on created_at |
page | integer | Page number (1-based)Default: 1 |
limit | integer | Page size (1–100)Default: 50 |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | ActivityLogListItem[] | Activity rows for this channel |
total* | integer | Total matching rows |
page* | integer | Current page |
limit* | integer | Page size |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity?page=1&limit=50" \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"event_type": "channels.email.received",
"channel": "email",
"direction": "inbound",
"from_address": "customer@example.com",
"to_addresses": ["support@mail.example.com"],
"subject": "Question about order #1042",
"status": "delivered",
"actor_type": null,
"correlation_id": null,
"summary": "When will it ship?",
"error": null,
"created_at": "2026-04-06T14:00:00Z"
}
],
"total": 12,
"page": 1,
"limit": 50
}/api/v1/channels/configs/{config_id}/activity/consumptionsList Channel Deliveries
Paginated subscription-scoped delivery history joined to immutable event summaries. Filter by subscription or delivery status to observe ACK/NACK outcomes. Requires channels:activity:view and never returns lease tokens.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
subscription_id | string (UUID) | Return deliveries for one stable subscription |
status | "pending" | "claimed" | "acked" | "failed" | Filter by delivery state |
direction | string | Filter the joined event by direction |
event_status | string | Filter the joined immutable event status |
search | string | Match event type, sender, or subject |
page | integer | Page number (1-based)Default: 1 |
limit | integer | Page size (1–100)Default: 50 |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | ActivityConsumptionListItem[] | Event summary plus subscription, status, attempts, consumer, and delivery timestamps |
total* | integer | Total matching rows |
page* | integer | Current page |
limit* | integer | Page size |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/consumptions?status=acked&page=1&limit=50" \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [{
"event": {
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"event_type": "channels.email.received",
"direction": "inbound",
"subject": "Question about order #1042",
"status": "received",
"created_at": "2026-08-15T15:00:00Z"
},
"subscription_id": "11111111-1111-4111-8111-111111111111",
"status": "acked",
"acked_at": "2026-08-15T15:01:00Z",
"available_at": null,
"lease_expires_at": null,
"consumer_id": "inbox-worker-1",
"attempt_count": 1,
"created_at": "2026-08-15T15:00:01Z",
"updated_at": "2026-08-15T15:01:00Z"
}],
"total": 1,
"page": 1,
"limit": 50
}/api/v1/channels/configs/{config_id}/activity/{event_id}Get Channel Activity Event
Full detail for one activity row scoped to a channel config, including payload and provider identifiers. Requires channels:activity:view on the channel.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
event_id* | string (UUID) | Activity log row ID |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/{event_id} \
-H "Authorization: Bearer {token}"Response
200 OK{
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"event_type": "channels.email.sent",
"channel": "email",
"direction": "outbound",
"from_address": "Support <support@mail.example.com>",
"to_addresses": ["customer@example.com"],
"subject": "Your order has shipped",
"status": "delivered",
"actor_type": "member",
"actor_id": "9a000000-0000-4000-8000-000000000001",
"correlation_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"summary": null,
"error": null,
"payload": { "html": "<p>Tracking: 1Z999...</p>" },
"provider_id": "resend",
"provider_message_id": "<msg_01hqabc@mail.example.com>",
"thread_id": "c3d4e5f6-7788-99aa-bbcc-ddeeff001122",
"in_reply_to": null,
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"created_at": "2026-04-06T15:22:11Z"
}/api/v1/channels/configs/{config_id}/activity/claimsClaim Inbound Channel Deliveries
Atomically leases canonical channels.email.received deliveries for one inbox address and a stable subscription. Requires both consume and view. Replicas sharing a subscription compete; independent subscriptions each receive the event.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Request Body
| Name | Type | Description |
|---|---|---|
subscription_id* | string (UUID) | Stable connector subscription identity |
address_id* | string (UUID) | Inbox address on this channel whose deliveries to claim |
consumer_id* | string | Current worker or replica identifier |
limit | integer | Maximum deliveries to claim (1–100)Default: 10 |
visibility_timeout_seconds | integer | Lease duration before redelivery (1–3600)Default: 60 |
cursor | string | null | Opaque keyset cursor for continuing the current scan; omit it on a new polling pass |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | ActivityClaimedItem[] | Immutable event plus subscription delivery lease |
next_cursor* | string | null | Cursor after the last claimed immutable event |
idempotent_replay* | boolean | True when Idempotency-Key matched a prior claim and the original batch was returned |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/claims \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: claim-batch-1" \
-d '{"subscription_id":"11111111-1111-4111-8111-111111111111","address_id":"a1d2e3f4-5566-7788-99aa-bbccddeeff00","consumer_id":"inbox-worker-1"}'Response
200 OK{
"items": [{
"event": {"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011", "event_type": "channels.email.received", "address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00"},
"delivery": {
"event_id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"config_id": "8f2c1a00-1111-4222-8333-444455556666",
"subscription_id": "11111111-1111-4111-8111-111111111111",
"status": "claimed",
"lease_token": "22222222-2222-4222-8222-222222222222",
"lease_expires_at": "2026-08-15T16:00:00Z",
"attempt_count": 1
}
}],
"next_cursor": "opaque",
"idempotent_replay": false
}/api/v1/channels/configs/{config_id}/activity/{event_id}/attachments/{attachment_id}/fileDownload Channel Activity Attachment
Stream one inbound email attachment as raw bytes with a bounded size and RFC 6266 filename. Requires channels:activity:view on the channel. attachment_id is payload.attachments[].resend_attachment_id. Unknown-length bodies are buffered up to the limit so oversized files still return 413. Binary transport — not an agent tool.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
event_id* | string (UUID) | Activity log row ID |
attachment_id* | string | Provider attachment id (resend_attachment_id) |
Response Fields
| Name | Type | Description |
|---|---|---|
(body)* | application/octet-stream | … | Raw attachment content |
curl -L -o invoice.pdf \
https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/{event_id}/attachments/{attachment_id}/file \
-H "Authorization: Bearer {token}"Response
200 OK/api/v1/channels/configs/{config_id}/activity/{event_id}/ackAcknowledge Channel Activity Event
Acknowledges one claimed inbound delivery for a subscription using its active lease token. Repeating the same acknowledgement is idempotent.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
event_id* | string (UUID) | Activity event ID |
Request Body
| Name | Type | Description |
|---|---|---|
subscription_id* | string (UUID) | Subscription that owns the delivery |
lease_token* | string (UUID) | Active token returned by the claim |
Response Fields
| Name | Type | Description |
|---|---|---|
event_id* | string (UUID) | Event ID |
config_id* | string (UUID) | Channel config ID |
status* | "acked" | Consumption status |
acked_at* | string (ISO 8601) | First acknowledgement time |
idempotent_replay* | boolean | True when already acknowledged |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/{event_id}/ack \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"subscription_id":"11111111-1111-4111-8111-111111111111","lease_token":"22222222-2222-4222-8222-222222222222"}'Response
200 OK{
"event_id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"config_id": "8f2c1a00-1111-4222-8333-444455556666",
"subscription_id": "11111111-1111-4111-8111-111111111111",
"status": "acked",
"acked_at": "2026-08-14T05:00:00Z",
"available_at": null,
"consumer_id": "inbox-worker-1",
"attempt_count": 0,
"idempotent_replay": false
}/api/v1/channels/configs/{config_id}/activity/{event_id}/nackNegatively Acknowledge Channel Activity Event
Requeues or fails one claimed subscription delivery. The body must include the active subscription and lease token. Repeating the same token after a successful nack is an idempotent replay.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
event_id* | string (UUID) | Activity event ID |
Request Body
| Name | Type | Description |
|---|---|---|
subscription_id* | string (UUID) | Subscription that owns the delivery |
lease_token* | string (UUID) | Active token returned by the claim |
requeue | boolean | Return to pending instead of marking failedDefault: true |
delay_seconds | integer | Delay before a requeued event is available (0–86400)Default: 0 |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/activity/{event_id}/nack \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"subscription_id":"11111111-1111-4111-8111-111111111111","lease_token":"22222222-2222-4222-8222-222222222222","requeue":true,"delay_seconds":30}'Response
200 OK{
"event_id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"config_id": "8f2c1a00-1111-4222-8333-444455556666",
"subscription_id": "11111111-1111-4111-8111-111111111111",
"status": "pending",
"acked_at": null,
"available_at": "2026-08-14T05:00:30Z",
"consumer_id": "inbox-worker-1",
"attempt_count": 1,
"idempotent_replay": false
}/api/v1/channels/threads/{thread_id}/messagesList Thread Messages
Chronological transcript of a conversation thread, used for automation and agent context. Full inbound message bodies require channels:addresses:receive on each destination address represented in the thread.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
thread_id* | string (UUID) | Conversation thread ID |
Response Fields
| Name | Type | Description |
|---|---|---|
messages* | ThreadMessageItem[] | id, direction, from_address, to_addresses, subject, status, actor_type, html, text, created_at |
curl https://platform.ergondata.ai/api/v1/channels/threads/{thread_id}/messages \
-H "Authorization: Bearer {token}"Response
200 OK{
"messages": [
{
"id": "b2c3d4e5-6677-8899-aabb-ccddeeff0011",
"direction": "inbound",
"from_address": "customer@example.com",
"to_addresses": ["support@mail.example.com"],
"subject": "Question about order #1042",
"status": "delivered",
"actor_type": null,
"html": "<p>When will it ship?</p>",
"text": null,
"created_at": "2026-04-06T14:00:00Z"
},
{
"id": "c3d4e5f6-7788-9900-bbcc-ddeeff002233",
"direction": "outbound",
"from_address": "Support <support@mail.example.com>",
"to_addresses": ["customer@example.com"],
"subject": "Re: Question about order #1042",
"status": "delivered",
"actor_type": "member",
"html": "<p>It ships tomorrow morning.</p>",
"text": null,
"created_at": "2026-04-06T14:05:22Z"
}
]
}Service grants
Service grants let another service (for example workflows) send from a specific address when its service_name and resource_id match. They are distinct from address ACL grants and from channel-zone access grants.
/api/v1/channels/addresses/grantedList Granted Addresses
Addresses the caller may use for a given service (and optional resource), typically when configuring a template in another product.
Bearer token required. Company context from the member token or x-company-id header.
Query Parameters
| Name | Type | Description |
|---|---|---|
service* | string | Service slug to match stored grants |
resource_id | string | Further narrow to one external resource |
sendable | boolean | When true, restrict to addresses eligible to sendDefault: false |
channel_type | string | Filter by underlying config channel type |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | GrantedAddressResponse[] | id, channel_config_id, address, display_name, direction, status, channel_type, channel_name, timestamps |
curl "https://platform.ergondata.ai/api/v1/channels/addresses/granted?service=workflows&resource_id=f47ac10b-58cc-4372-a567-0e02b2c3d479" \
-H "Authorization: Bearer {token}" \
-H "x-company-id: {company_id}"Response
200 OK[
{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "hello@mail.example.com",
"display_name": "Support",
"direction": "send",
"status": "active",
"channel_type": "email",
"channel_name": "Primary email",
"created_at": "2026-04-02T10:00:00Z",
"updated_at": "2026-04-02T10:00:00Z"
}
]/api/v1/channels/configs/{config_id}/addresses/{address_id}/grantsList Grants
Return the service grants attached to an address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | GrantResponse[] | id, address_id, company_id, service_name, resource_id, resource_label, label, created_by, created_at |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/grants \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "a7c9e1d2-3344-4566-8788-99aabbccddee",
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"service_name": "workflows",
"resource_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"resource_label": "Order notifications",
"label": "Production",
"created_by": "9a000000-0000-4000-8000-000000000001",
"created_at": "2026-04-05T12:00:00Z"
}
]/api/v1/channels/configs/{config_id}/addresses/{address_id}/grantsCreate Grant
Record that an external service may send using this address for a given resource scope.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Request Body
| Name | Type | Description |
|---|---|---|
service_name* | string | Calling service slug (1–50 characters) |
resource_id | string | null | Scoped resource in the calling service |
resource_label | string | null | Human-readable resource label |
label | string | null | Optional note for operators |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/grants \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"service_name": "workflows",
"resource_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"resource_label": "Order notifications",
"label": "Production"
}'Response
201 Created{
"id": "a7c9e1d2-3344-4566-8788-99aabbccddee",
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"service_name": "workflows",
"resource_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"resource_label": "Order notifications",
"label": "Production",
"created_by": "9a000000-0000-4000-8000-000000000001",
"created_at": "2026-04-05T12:00:00Z"
}/api/v1/channels/grants/{grant_id}Revoke Grant
Revoke a service grant by ID.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
grant_id* | string (UUID) | Grant ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/grants/{grant_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentAddress ACL
Per-address ACL grants control which IAM principals or roles may send from a specific address or view inbound messages received at it. Receive grants authorize visibility; they do not enable, disable, deliver, or route inbound mail.
/api/v1/channels/configs/{config_id}/addresses/{address_id}/aclList Address ACL
List ACL grants for a specific address — the permission grants that control who can use this address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | GrantResponse[] | id, principal_type, principal_id, principal_label, permission_name, resource, effect, granted_at |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/acl \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"principal_label": "Jane Doe",
"permission_name": "channels:addresses:send",
"resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666/address/a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"effect": "allow",
"granted_at": "2026-04-05T10:00:00Z"
}
]/api/v1/channels/configs/{config_id}/addresses/{address_id}/aclGrant Address ACL
Grant a principal an address permission. Send maps to channels:addresses:send. Receive maps to channels:addresses:receive and makes the principal eligible as an inbound route target; activity visibility remains governed by channels:activity:view.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Request Body
| Name | Type | Description |
|---|---|---|
principal_type* | string | Principal kind: member, api_key, or agent |
principal_id* | string | Principal identifier |
capability | string | send or receiveDefault: send |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string | Grant ID |
principal_type* | string | Principal kind |
principal_id* | string | Principal identifier |
principal_label* | string | Resolved display name |
permission_name* | string | Permission slug granted |
resource* | string | Scoped resource URN |
effect* | string | Grant effect (allow) |
granted_at* | string (ISO 8601) | When the grant was created |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/acl \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"capability": "send"
}'Response
201 Created{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"principal_label": "Jane Doe",
"permission_name": "channels:addresses:send",
"resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666/address/a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"effect": "allow",
"granted_at": "2026-04-05T10:00:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/acl/{grant_id}Revoke Address ACL
Revoke a permission grant on this address.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
grant_id* | string (UUID) | ACL grant ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/acl/{grant_id} \
-H "Authorization: Bearer {token}"Response
204 No Content/api/v1/channels/configs/{config_id}/addresses/{address_id}/eligible-principalsList Eligible Principals
List principals that can be granted ACL on this address, for building a grant picker.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
address_id* | string (UUID) | Address ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | EligiblePrincipal[] | principal_type, principal_id, label |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/eligible-principals \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"label": "Jane Doe"
}
]/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/eligibleList Address Access Eligibility
List principals eligible on the concrete address. Requires channels:permissions:manage and forwards the optional permission filter to IAM.
Bearer token required.
Query Parameters
| Name | Type | Description |
|---|---|---|
permission | string | Filter to principals eligible for this permission, such as channels:addresses:receive or channels:addresses:send |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | EligiblePrincipal[] | principal_type, principal_id, label |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/eligible?permission=channels%3Aaddresses%3Areceive" -H "Authorization: Bearer {token}"Response
200 OK[
{
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"label": "Jane Doe"
}
]/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/resource-typesList Address Access Resource Types
List grantable address permissions and resource types. Directional send/receive permissions are filtered to the address direction.
Bearer token with channels:permissions:manage on the address.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Parent channel config ID |
address_id* | string (UUID) | Channel address ID |
Response Fields
| Name | Type | Description |
|---|---|---|
resource_types* | ResourceTypeNode[] | Channels resource-type tree |
permissions* | PermissionOption[] | Permissions valid for this address |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/resource-types \
-H "Authorization: Bearer {token}"Response
200 OK{
"resource_types": [],
"permissions": [{
"id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:addresses:receive",
"scope_anchor": "instance",
"display_order": 0
}]
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grantsList Address Access Grants
List paginated IAM grants scoped to one channel address.
Bearer token with channels:permissions:manage on the address.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Parent channel config ID |
address_id* | string (UUID) | Channel address ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
page | integer | Page number (1-based)Default: 1 |
limit | integer | Page size (1–500)Default: 100 |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | GrantEntry[] | Address-scoped grants |
total* | integer | Total grants |
page* | integer | Current page |
limit* | integer | Page size |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grants?page=1&limit=100" \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [],
"total": 0,
"page": 1,
"limit": 100
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grantsCreate Address Access Grant
Grant one catalog permission on the concrete address. Send and receive permissions must match the address direction.
Bearer token with channels:permissions:manage on the address.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Parent channel config ID |
address_id* | string (UUID) | Channel address ID |
Request Body
| Name | Type | Description |
|---|---|---|
principal_type* | "member" | "api_key" | "agent" | "role" | "team" | IAM principal kind |
principal_id* | string (UUID) | IAM principal ID |
permission_id* | string (UUID) | Permission UUID from this address's resource-types response |
resource | string | null | Must equal this address resource when provided |
effect | string | Grant effectDefault: allow |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grants \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"principal_type":"agent","principal_id":"{principal_id}","permission_id":"{permission_id}"}'Response
201 Created{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"permission_id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:addresses:receive",
"resource": "org/{company_id}/channel/{config_id}/address/{address_id}",
"effect": "allow",
"is_system": false,
"granted_at": "2026-08-06T12:00:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grants/{grant_id}Delete Address Access Grant
Revoke one IAM grant scoped to the channel address.
Bearer token with channels:permissions:manage on the address.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Parent channel config ID |
address_id* | string (UUID) | Channel address ID |
grant_id* | string (UUID) | IAM grant ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/access/grants/{grant_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentInbound Routes
Route inbound email or WhatsApp into one Workflows process entry phase, to observer participants, one automatic-reply agent, and optionally one legacy human-assignment queue. Conversations binds exactly one conversation per external thread and requests process intake only when a new episode is created.
/api/v1/channels/configs/{config_id}/inbound-routesList Config Routes
List all inbound routes under a config. Requires channels:channels:manage on the channel.
Bearer token required.
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | InboundRouteResponse[] | Routes ordered by creation time |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/inbound-routes -H "Authorization: Bearer {token}"Response
200 OK[{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}]/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routesList Address Routes
List routes for an address. Requires channels:addresses:manage on the address.
Bearer token required.
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | InboundRouteResponse[] | Routes ordered by creation time |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes -H "Authorization: Bearer {token}"Response
200 OK[{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}]/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routesCreate Address Route
Create a workflow_phase process route or user/team notify route. Process routes require Workflows items:create on the entry phase. auto-reply creation through this address-owned path returns 403.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Process accepts workflow_phase; notify accepts user/team |
target_id* | string (UUID) | Target entity/principal ID |
mode* | "notify" | "process" | "auto-reply" | Must be notify or process on this path |
reply_address_id | string (UUID) | null | Must be null for notify or process |
status | "active" | "paused" | Route stateDefault: active |
policy | object | Must be empty for notify or processDefault: {} |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string (UUID) | Route ID |
company_id* | string (UUID) | Owning company |
channel_address_id* | string (UUID) | Receiving address |
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Route target kind |
target_id* | string (UUID) | Canonical principal or workflow entry-phase ID |
mode* | "notify" | "auto-reply" | "process" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify, assign, and process |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify, assign, and process use {}; auto-reply supports max_auto_replies_per_thread (1–100, default 10) |
created_at* | string (ISO 8601) | Creation time |
updated_at* | string (ISO 8601) | Last update time |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes -H "Authorization: Bearer {token}" -H "Content-Type: application/json" -d '{"target_principal_type":"user","target_id":"{principal_id}","mode":"notify"}'Response
201 Created{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id}Get Address Route
Get one address route. Requires channels:addresses:manage on the address.
Bearer token required.
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string (UUID) | Route ID |
company_id* | string (UUID) | Owning company |
channel_address_id* | string (UUID) | Receiving address |
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Route target kind |
target_id* | string (UUID) | Canonical principal or workflow entry-phase ID |
mode* | "notify" | "auto-reply" | "process" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify, assign, and process |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify, assign, and process use {}; auto-reply supports max_auto_replies_per_thread (1–100, default 10) |
created_at* | string (ISO 8601) | Creation time |
updated_at* | string (ISO 8601) | Last update time |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id} -H "Authorization: Bearer {token}"Response
200 OK{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id}Update Address Route
Update a process or notify route with channels:addresses:manage. Process activation revalidates Workflows access. For an agent-owned auto-reply route, the only accepted body is address_status.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
target_principal_type | "user" | "team" | "agent" | "workflow_phase" | null | Notify target kind |
target_id | string (UUID) | null | Notify target |
mode | "notify" | "process" | "auto-reply" | null | Cannot convert to auto-reply through this path |
reply_address_id | string (UUID) | null | Notify routes cannot use a reply address |
status | "active" | "paused" | null | Notify route state |
address_status | "allowed" | "blocked" | null | Only field address managers may change on auto-reply |
policy | object | null | Notify policy must be empty |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string (UUID) | Route ID |
company_id* | string (UUID) | Owning company |
channel_address_id* | string (UUID) | Receiving address |
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Route target kind |
target_id* | string (UUID) | Canonical principal or workflow entry-phase ID |
mode* | "notify" | "auto-reply" | "process" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify, assign, and process |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify, assign, and process use {}; auto-reply supports max_auto_replies_per_thread (1–100, default 10) |
created_at* | string (ISO 8601) | Creation time |
updated_at* | string (ISO 8601) | Last update time |
curl -X PATCH https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id} -H "Authorization: Bearer {token}" -H "Content-Type: application/json" -d '{"address_status":"blocked"}'Response
200 OK{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id}Delete Address Route
Delete a process or notify route with channels:addresses:manage. Deleting an auto-reply through the address path returns 403; block it or use agent settings.
Bearer token required.
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/addresses/{address_id}/inbound-routes/{route_id} -H "Authorization: Bearer {token}"Response
204 No Content/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routesList Agent Route Settings
List active receive-capable addresses eligible for this agent, with all routes and send-capability reply candidates. Requires agents:agents:channels:manage on the agent; address visibility remains row-filtered.
Bearer token required.
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | AgentInboundAddressResponse[] | Agent route settings per visible address |
curl https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes -H "Authorization: Bearer {token}"Response
200 OK[
{
"address": {"id":"a1d2e3f4-5566-7788-99aa-bbccddeeff00","channel_config_id":"8f2c1a00-1111-4222-8333-444455556666","address":"support@example.com","display_name":"Support","direction":"both","status":"active"},
"routes": [{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}],
"reply_addresses": [{"id":"a1d2e3f4-5566-7788-99aa-bbccddeeff00","channel_config_id":"8f2c1a00-1111-4222-8333-444455556666","address":"support@example.com","display_name":"Support","direction":"both","status":"active","can_send":true}]
}
]/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id}Create Agent Auto-Reply
Create this agent's auto-reply route. Requires agents:agents:channels:manage on the agent plus the agent's receive grant on the source and send grant on the reply address. Only one active auto-reply may exist per address.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
reply_address_id | string (UUID) | null | Reply sender; defaults to the source address |
status | "active" | "paused" | Agent-owned route stateDefault: active |
policy | object | max_auto_replies_per_thread must be 1–100Default: {"max_auto_replies_per_thread":10} |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string (UUID) | Route ID |
company_id* | string (UUID) | Owning company |
channel_address_id* | string (UUID) | Receiving address |
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Route target kind |
target_id* | string (UUID) | Canonical principal or workflow entry-phase ID |
mode* | "notify" | "auto-reply" | "process" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify, assign, and process |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify, assign, and process use {}; auto-reply supports max_auto_replies_per_thread (1–100, default 10) |
created_at* | string (ISO 8601) | Creation time |
updated_at* | string (ISO 8601) | Last update time |
curl -X POST https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id} -H "Authorization: Bearer {token}" -H "Content-Type: application/json" -d '{"policy":{"max_auto_replies_per_thread":10}}'Response
201 Created{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id}/{route_id}Update Agent Auto-Reply
Reconfigure or pause/resume this agent's owned auto-reply route. Requires agents:agents:channels:manage; address_status is not agent-controlled.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
reply_address_id | string (UUID) | null | Reply sender |
status | "active" | "paused" | null | Agent-owned route state |
policy | object | null | max_auto_replies_per_thread must be 1–100 |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string (UUID) | Route ID |
company_id* | string (UUID) | Owning company |
channel_address_id* | string (UUID) | Receiving address |
target_principal_type* | "user" | "team" | "agent" | "workflow_phase" | Route target kind |
target_id* | string (UUID) | Canonical principal or workflow entry-phase ID |
mode* | "notify" | "auto-reply" | "process" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify, assign, and process |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify, assign, and process use {}; auto-reply supports max_auto_replies_per_thread (1–100, default 10) |
created_at* | string (ISO 8601) | Creation time |
updated_at* | string (ISO 8601) | Last update time |
curl -X PATCH https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id}/{route_id} -H "Authorization: Bearer {token}" -H "Content-Type: application/json" -d '{"status":"paused"}'Response
200 OK{
"id": "70000000-0000-4000-8000-000000000001",
"company_id": "c0ffee00-cafe-babe-dead-beefcafebabe",
"channel_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"target_principal_type": "agent",
"target_id": "90000000-0000-4000-8000-000000000001",
"mode": "auto-reply",
"reply_address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"status": "active",
"address_status": "allowed",
"policy": {"max_auto_replies_per_thread": 10},
"created_at": "2026-07-30T12:00:00Z",
"updated_at": "2026-07-30T12:00:00Z"
}/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id}/{route_id}Delete Agent Auto-Reply
Delete this agent's owned auto-reply route. Requires agents:agents:channels:manage on the agent.
Bearer token required.
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/companies/{company_id}/agents/{agent_id}/inbound-routes/{address_id}/{route_id} -H "Authorization: Bearer {token}"Response
204 No ContentChannel zone access
Govern the zero-trust channel zone rooted at a config: enumerate resource types and permissions, manage zone-level access grants, list principals eligible for access, and approve, reject, or sever inbound connection requests from other principals.
/api/v1/channels/configs/{config_id}/access/grantsList Access Grants
Paginated list of access grants on this channel zone.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
page | integer | Page number (1-based)Default: 1 |
limit | integer | Page size (1–500)Default: 100 |
Response Fields
| Name | Type | Description |
|---|---|---|
items* | GrantResponse[] | id, permission_id, name, resource, effect, is_system, granted_at |
total | integer | Total matching rows |
page | integer | Current page |
limit | integer | Page size |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/grants?page=1&limit=100" \
-H "Authorization: Bearer {token}"Response
200 OK{
"items": [
{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"permission_id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:channels:manage",
"resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"effect": "allow",
"is_system": false,
"granted_at": "2026-04-05T10:00:00Z"
}
],
"total": 3,
"page": 1,
"limit": 100
}/api/v1/channels/configs/{config_id}/access/grantsCreate Access Grant
Grant a permission on this channel zone (or a nested resource) to a principal.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Request Body
| Name | Type | Description |
|---|---|---|
principal_type* | string | Principal kind: member, api_key, agent, or role |
principal_id* | string | Principal identifier |
permission_id* | string | Permission to grant (from List Channel Permissions) |
resource | string | null | Resource URN to scope the grant to; defaults to the channel zone |
effect | string | Grant effectDefault: allow |
Response Fields
| Name | Type | Description |
|---|---|---|
id* | string | Grant ID |
permission_id* | string | Permission granted |
name* | string | Permission slug |
resource* | string | Scoped resource URN |
effect* | string | Grant effect |
is_system* | boolean | Whether the grant is system-managed |
granted_at* | string (ISO 8601) | When the grant was created |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/grants \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"permission_id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"effect": "allow"
}'Response
201 Created{
"id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"permission_id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:channels:manage",
"resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"effect": "allow",
"is_system": false,
"granted_at": "2026-04-05T10:00:00Z"
}/api/v1/channels/configs/{config_id}/access/grants/{grant_id}Delete Access Grant
Revoke an access grant on this channel zone by ID.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
grant_id* | string (UUID) | Access grant ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/grants/{grant_id} \
-H "Authorization: Bearer {token}"Response
204 No Content/api/v1/channels/configs/{config_id}/access/permissionsList Channel Permissions
Permissions that can be granted on this channel zone and its resources.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | PermissionOption[] | id, name, friendly_name, description, scope_anchor, display_order, resource_type_id, parent_resource_type_slug |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/permissions \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:addresses:send",
"friendly_name": "Send",
"friendly_name_singular": "Send",
"description": "Send messages from this address",
"scope_anchor": "instance",
"display_order": 10,
"resource_type_id": "2b1c0d9e-8f7a-4b6c-9d5e-4f3a2b1c0d9e",
"parent_resource_type_slug": "channel"
}
]/api/v1/channels/configs/{config_id}/access/resource-typesList Resource Types
Resource-type tree for the channel zone plus the permissions available at each level, for building an access editor.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
resource_types* | ResourceTypeNode[] | Nested resource types (id, name, slug, parent_id, children) |
permissions* | PermissionOption[] | Permissions available across the tree |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/resource-types \
-H "Authorization: Bearer {token}"Response
200 OK{
"resource_types": [
{
"id": "2b1c0d9e-8f7a-4b6c-9d5e-4f3a2b1c0d9e",
"name": "Channel",
"slug": "channel",
"parent_id": null,
"children": [
{
"id": "3c2d1e0f-9a8b-4c7d-8e6f-5a4b3c2d1e0f",
"name": "Address",
"slug": "address",
"parent_id": "2b1c0d9e-8f7a-4b6c-9d5e-4f3a2b1c0d9e",
"children": []
}
]
}
],
"permissions": [
{
"id": "7e5d6c4b-3a21-4f09-8e7d-6c5b4a392817",
"name": "channels:addresses:send",
"friendly_name": "Send",
"scope_anchor": "instance"
}
]
}/api/v1/channels/configs/{config_id}/access/eligibleList Eligible Principals
Principals eligible to receive access on this channel zone, for building a grant picker.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | EligiblePrincipal[] | principal_type, principal_id, label |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/eligible \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"principal_type": "member",
"principal_id": "9a000000-0000-4000-8000-000000000001",
"label": "Jane Doe"
}
]/api/v1/channels/configs/{config_id}/access/connection-requestsList Connection Requests
List requests from other principals asking to connect to this channel zone.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Query Parameters
| Name | Type | Description |
|---|---|---|
status | string | Filter by request statusDefault: pending |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | ConnectionRequestEntry[] | id, principal_id, target_service, target_resource, status, created_at, plus optional connection_id, requested_by, requested_permissions, message, decided_at, decided_by |
curl "https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/connection-requests?status=pending" \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "11112222-3333-4444-5555-666677778888",
"principal_id": "9a000000-0000-4000-8000-000000000002",
"target_service": "workflows",
"target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"status": "pending",
"requested_by": "9a000000-0000-4000-8000-000000000002",
"requested_permissions": ["channels:addresses:send"],
"message": "Need to send order notifications",
"connection_id": null,
"decided_at": null,
"decided_by": null,
"created_at": "2026-04-05T09:00:00Z"
}
]/api/v1/channels/configs/{config_id}/access/connection-requests/{request_id}/approveApprove Connection Request
Approve a pending connection request, optionally granting a specific set of permissions.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
request_id* | string (UUID) | Connection request ID |
Request Body
| Name | Type | Description |
|---|---|---|
grant | boolean | Whether to grant access on approvalDefault: true |
permissions | string[] | null | Permission slugs to grant; defaults to the requested permissions |
label | string | null | Optional label for the resulting connection |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/connection-requests/{request_id}/approve \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"grant": true,
"permissions": ["channels:addresses:send"],
"label": "Order notifications"
}'Response
200 OK{
"id": "11112222-3333-4444-5555-666677778888",
"principal_id": "9a000000-0000-4000-8000-000000000002",
"target_service": "workflows",
"target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"status": "approved",
"requested_by": "9a000000-0000-4000-8000-000000000002",
"requested_permissions": ["channels:addresses:send"],
"message": "Need to send order notifications",
"connection_id": "aaaa1111-2222-4333-8444-555566667777",
"decided_at": "2026-04-05T09:30:00Z",
"decided_by": "9a000000-0000-4000-8000-000000000001",
"created_at": "2026-04-05T09:00:00Z"
}/api/v1/channels/configs/{config_id}/access/connection-requests/{request_id}/rejectReject Connection Request
Reject a pending connection request with an optional reason.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
request_id* | string (UUID) | Connection request ID |
Request Body
| Name | Type | Description |
|---|---|---|
reason | string | null | Optional rejection reason |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/connection-requests/{request_id}/reject \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{"reason": "Not needed"}'Response
200 OK{
"id": "11112222-3333-4444-5555-666677778888",
"principal_id": "9a000000-0000-4000-8000-000000000002",
"target_service": "workflows",
"target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"status": "rejected",
"requested_by": "9a000000-0000-4000-8000-000000000002",
"requested_permissions": ["channels:addresses:send"],
"message": "Need to send order notifications",
"connection_id": null,
"decided_at": "2026-04-05T09:30:00Z",
"decided_by": "9a000000-0000-4000-8000-000000000001",
"created_at": "2026-04-05T09:00:00Z"
}/api/v1/channels/configs/{config_id}/access/connectionsList Inbound Connections
List active connections where another principal connects to this channel zone.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
Response Fields
| Name | Type | Description |
|---|---|---|
[]* | InboundConnectionEntry[] | id, principal_id, target_service, target_resource, created_at, plus optional principal_type, principal_label, label, created_by, created_by_label, requested_by, requested_by_label, system_managed_by |
curl https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/connections \
-H "Authorization: Bearer {token}"Response
200 OK[
{
"id": "aaaa1111-2222-4333-8444-555566667777",
"principal_id": "9a000000-0000-4000-8000-000000000002",
"principal_type": "automation",
"principal_label": "Order notifier",
"target_service": "workflows",
"target_resource": "org/c0ffee00-cafe-babe-dead-beefcafebabe/channel/8f2c1a00-1111-4222-8333-444455556666",
"label": "Order notifications",
"created_by": "9a000000-0000-4000-8000-000000000001",
"created_by_label": "Jane Doe",
"requested_by": "9a000000-0000-4000-8000-000000000002",
"requested_by_label": "Order notifier",
"system_managed_by": null,
"created_at": "2026-04-05T09:30:00Z"
}
]/api/v1/channels/configs/{config_id}/access/connections/{connection_id}Revoke Inbound Connection
Sever an inbound connection to this channel, cutting the principal's runtime access.
Bearer token required.
Path Parameters
| Name | Type | Description |
|---|---|---|
config_id* | string (UUID) | Channel config ID |
connection_id* | string (UUID) | Connection ID |
curl -X DELETE https://platform.ergondata.ai/api/v1/channels/configs/{config_id}/access/connections/{connection_id} \
-H "Authorization: Bearer {token}"Response
204 No ContentWebhooks
Inbound provider callback. This endpoint is called by the email provider when it delivers an inbound message; it is not invoked directly by API consumers.
/api/v1/channels/webhooks/emailReceive Email
Provider webhook for inbound email. The email provider posts delivery and inbound-message events here; the body is provider-specific and verified by signature. Inbound messages route to the matching receive/both address and may emit channel events. IAM receive grants are not evaluated for provider delivery or routing; they govern subsequent message visibility.
Called by the email provider. Authenticated by provider webhook signature, not a bearer token.
Request Body
| Name | Type | Description |
|---|---|---|
<provider payload>* | object | Provider-specific event envelope (e.g. message, headers, recipients) |
curl -X POST https://platform.ergondata.ai/api/v1/channels/webhooks/email \
-H "Content-Type: application/json" \
-H "svix-signature: {provider_signature}" \
-d '{
"type": "email.received",
"data": {
"from": "customer@example.com",
"to": ["support@mail.example.com"],
"subject": "Question about order #1042"
}
}'Response
200 OK{ "ok": true }/api/v1/channels/webhooks/whatsapp/{webhook_token}Verify WhatsApp Webhook
Meta's webhook subscription handshake. Meta calls this endpoint with hub.mode, hub.challenge, and hub.verify_token; when the verify token matches the Vault-stored secret for the config, the challenge is echoed back as plain text. Not invoked by API consumers.
Authenticated by the per-config webhook token in the path plus the Vault-stored verify token; no bearer token.
Path Parameters
| Name | Type | Description |
|---|---|---|
webhook_token* | string | Per-config opaque webhook token issued during WhatsApp setup |
Query Parameters
| Name | Type | Description |
|---|---|---|
hub.mode* | string | Must be "subscribe" |
hub.challenge* | string | Random challenge Meta expects echoed back |
hub.verify_token* | string | Verify token compared against the Vault-stored secret |
curl "https://platform.ergondata.ai/api/v1/channels/webhooks/whatsapp/{webhook_token}?hub.mode=subscribe&hub.challenge=12345&hub.verify_token={verify_token}"Response
200 OK12345/api/v1/channels/webhooks/whatsapp/{webhook_token}Receive WhatsApp Webhook
Meta Cloud API callback for inbound messages, delivery statuses, account updates, and template status changes. The body is verified with the X-Hub-Signature-256 HMAC computed from the Vault-stored app secret. Inbound messages route to the matching WhatsApp address and drive episodic conversations. Not invoked by API consumers.
Authenticated by the per-config webhook token in the path plus the X-Hub-Signature-256 HMAC signature; no bearer token.
Path Parameters
| Name | Type | Description |
|---|---|---|
webhook_token* | string | Per-config opaque webhook token issued during WhatsApp setup |
Request Body
| Name | Type | Description |
|---|---|---|
<Meta payload>* | object | Meta Cloud API event envelope (entry, changes, messages, statuses) |
curl -X POST https://platform.ergondata.ai/api/v1/channels/webhooks/whatsapp/{webhook_token} \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: sha256={signature}" \
-d '{"object":"whatsapp_business_account","entry":[]}'Response
200 OK{ "ok": true }Batch Access Grants
Public batch grant routes accept BatchCreateGrantsRequest and return ordered BatchCreateGrantsResponse partial-success envelopes. Operations expand as resources × permission_ids with a maximum of 200 expanded grants. HTTP 200 may include failed items; `already_exists` is an idempotent success, so whole-request or failed-item retries are safe. Side-effect errors do not roll back successful grants and require separate reconciliation.
/api/v1/channels/configs/access/grants/batchBatch Create Channel Grants
Create grants across channel-config roots with independent per-item validation. Agent ToolDef slug: `channels.channel_access.create_grants_batch`.
Bearer token and company context required. IAM permission `channels:permissions:manage` on every concrete channel root.
Request Body
| Name | Type | Description |
|---|---|---|
operations* | BatchGrantOperation[] | One or more grouped operations; maximum 200 expanded grants |
Response Fields
| Name | Type | Description |
|---|---|---|
results* | BatchGrantResult[] | Ordered results with index, client_ref, status, principal, permission_id, canonical resource, effect, grant, error_status/error_detail, and side_effect_error_status/side_effect_error_detail |
summary* | object | created, already_exists, and failed counts |
curl -X POST https://platform.ergondata.ai/api/v1/channels/configs/access/grants/batch \
-H "Authorization: Bearer {token}" \
-H "X-Company-Id: {company_id}" \
-H "Content-Type: application/json" \
-d '{"operations":[{"client_ref":"channel-access","principal_type":"member","principal_id":"{principal_id}","resources":["org/{company_id}/channel/{config_id}"],"permission_ids":["{permission_id}"],"effect":"allow"}]}'Response
200 OK{
"results": [{
"index": 0, "client_ref": "channel-access", "status": "created",
"principal_type": "member", "principal_id": "{principal_id}",
"permission_id": "{permission_id}", "resource": "org/{company_id}/channel/{config_id}",
"effect": "allow", "grant": {}, "error_status": null, "error_detail": null,
"side_effect_error_status": null, "side_effect_error_detail": null
}],
"summary": { "created": 1, "already_exists": 0, "failed": 0 }
}/api/v1/channels/addresses/access/grants/batchBatch Create Address Grants
Create grants across address roots. Address resources must end at the address root, and directional permissions must match the address's send/receive/both direction. Agent ToolDef slug: `channels.address_access.create_grants_batch`.
Bearer token and company context required. IAM permission `channels:permissions:manage` on every concrete address root.
Request Body
| Name | Type | Description |
|---|---|---|
operations* | BatchGrantOperation[] | BatchCreateGrantsRequest operations (client_ref, principal_type/id, resources, permission_ids, effect); maximum 200 expanded grants |
Response Fields
| Name | Type | Description |
|---|---|---|
results* | BatchGrantResult[] | Ordered partial-success results with primary and side-effect error fields |
summary* | object | created, already_exists, and failed counts |
curl -X POST https://platform.ergondata.ai/api/v1/channels/addresses/access/grants/batch \
-H "Authorization: Bearer {token}" \
-H "X-Company-Id: {company_id}" \
-H "Content-Type: application/json" \
-d '{"operations":[{"principal_type":"agent","principal_id":"{principal_id}","resources":["org/{company_id}/channel/{config_id}/address/{address_id}"],"permission_ids":["{permission_id}"]}]}'Response
200 OK{
"results": [{
"index": 0, "client_ref": null, "status": "already_exists",
"principal_type": "agent", "principal_id": "{principal_id}",
"permission_id": "{permission_id}", "resource": "org/{company_id}/channel/{config_id}/address/{address_id}",
"effect": "allow", "grant": {}, "error_status": null, "error_detail": null,
"side_effect_error_status": null, "side_effect_error_detail": null
}],
"summary": { "created": 0, "already_exists": 1, "failed": 0 }
}