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 and invoke the effective auto-reply agent; Automations may independently fan out from the same events. 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" | Email setup model. Vendor selection is an internal implementation detail. |
name* | string | Display name |
domain* | string | null | Configured domain |
status* | string | Lifecycle status (e.g. pending_dns, verifying, verified) |
provider_ref* | object | null | Transport metadata such as DNS records or the Platform Domain mail namespace. Account-level webhook configuration is not tenant-managed. |
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",
"provider_ref": {
"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",
"provider_ref": { "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",
"provider_ref": {
"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",
"provider_ref": { "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",
"provider_ref": { "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}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": "[email protected]",
"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 address under a config. For email, the address must use the config domain. Receive/both addresses require inbound to be available and may enable inbound on the config.
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. [email protected] (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": "[email protected]",
"display_name": "Support",
"direction": "send"
}'Response
201 Created{
"id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"channel_config_id": "8f2c1a00-1111-4222-8333-444455556666",
"address": "[email protected]",
"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": "[email protected]",
"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}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": "[email protected]",
"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: 7c1f4e0a-2b3c-4d5e-8f90-112233445566" \
-d '{
"channel": "email",
"address_id": "a1d2e3f4-5566-7788-99aa-bbccddeeff00",
"config": {
"to": ["[email protected]"],
"subject": "Your order has shipped",
"html": "<p>Thanks for your purchase!</p>",
"reply_to": "[email protected]",
"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": "<[email protected]>",
"thread_id": "d4e5f6a7-b8c9-4012-d345-6789abcdef01",
"idempotent_replay": false
}Activity
Inspect the channel type registry, paginated message activity (company-wide or per channel), single events, 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 the channels the caller may audit. Inbound message rows are additionally filtered by channels:addresses:receive on their destination address. That permission controls visibility only; it does not affect provider delivery or routing.
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 <[email protected]>",
"to_addresses": ["[email protected]"],
"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. Reading an inbound message event also requires channels:addresses:receive on its destination address.
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 <[email protected]>",
"to_addresses": ["[email protected]"],
"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": "<[email protected]>",
"created_at": "2026-04-06T15:22:11Z"
}/api/v1/channels/configs/{config_id}/activityList Channel Activity
Paginated activity log scoped to a single channel config. Inbound message rows are visible only when the caller has channels:addresses:receive on their destination address.
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": "[email protected]",
"to_addresses": ["[email protected]"],
"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/{event_id}Get Channel Activity Event
Full detail for one activity row scoped to a channel config, including payload and provider identifiers. Reading an inbound message event also requires channels:addresses:receive on its destination address.
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 <[email protected]>",
"to_addresses": ["[email protected]"],
"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": "<[email protected]>",
"created_at": "2026-04-06T15:22:11Z"
}/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": "[email protected]",
"to_addresses": ["[email protected]"],
"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 <[email protected]>",
"to_addresses": ["[email protected]"],
"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": "[email protected]",
"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 authorizes viewing inbound messages at the address; it does not control delivery or routing.
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 to human participants or one automatic-reply agent. Receive permission controls inbound visibility and route-target eligibility, not delivery. Active user/team notify routes determine human participants; Conversations binds exactly one conversation per external thread.
/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 Notify Route
Create a user/team notify route with channels:addresses:manage. The target must hold channels:addresses:receive. auto-reply creation through this address-owned path returns 403.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
target_principal_type* | "user" | "team" | "agent" | Notify accepts only user or team |
target_id* | string (UUID) | Target entity/principal ID |
mode* | "notify" | "auto-reply" | Must be notify on this path |
reply_address_id | string (UUID) | null | Must be null for notify |
status | "active" | "paused" | Route stateDefault: active |
policy | object | Must be empty for notifyDefault: {} |
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" | Route target kind |
target_id* | string (UUID) | Canonical IAM principal ID |
mode* | "notify" | "auto-reply" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify uses {}; 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" | Route target kind |
target_id* | string (UUID) | Canonical IAM principal ID |
mode* | "notify" | "auto-reply" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify uses {}; 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 notify route with channels:addresses:manage. For an agent-owned auto-reply route, the only accepted body is address_status; reconfiguration or pause/resume returns 403.
Bearer token required.
Request Body
| Name | Type | Description |
|---|---|---|
target_principal_type | "user" | "team" | "agent" | null | Notify target kind |
target_id | string (UUID) | null | Notify target |
mode | "notify" | "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" | Route target kind |
target_id* | string (UUID) | Canonical IAM principal ID |
mode* | "notify" | "auto-reply" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify uses {}; 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 Notify Route
Delete a 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: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":"[email protected]","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":"[email protected]","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: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" | Route target kind |
target_id* | string (UUID) | Canonical IAM principal ID |
mode* | "notify" | "auto-reply" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify uses {}; 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: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" | Route target kind |
target_id* | string (UUID) | Canonical IAM principal ID |
mode* | "notify" | "auto-reply" | Route behavior |
reply_address_id* | string (UUID) | null | Auto-reply sender; null for notify |
status* | "active" | "paused" | Route owner's desired state |
address_status* | "allowed" | "blocked" | Address owner's auto-reply gate |
policy* | object | Notify uses {}; 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: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": "[email protected]",
"to": ["[email protected]"],
"subject": "Question about order #1042"
}
}'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 }
}