https://app.evoriqa.com/api/v1/channelsConnect a channel
Connects one of the seven channel types to a chatbot. Every type except `email` and `slack` requires a populated `config` carrying that transport's credentials — see the variants below. `sms`, `voice` and `whatsapp` also require `config.provider`, and 422 with "Pick a provider for this channel." when it is absent. The response carries the channel's inbound webhook secret exactly once — store it immediately, it is never shown again. On an Infobip channel that same secret doubles as the `webhookSecret` in the inbound webhook URL, because Infobip does not sign its webhooks. In production, Meta credentials (`messenger`, `instagram`, and `whatsapp` on `whatsapp_cloud`) are verified against the Graph API before the channel is created, so wrong or expired credentials 422 here rather than failing silently on the first inbound message.
Requires scope channels:write
Access is gated — enable it before your first call
The API is off by default. A request succeeds only when all three switches are on: the platform master switch (off by default), your organisation’s API toggle, and your plan or client entitlement. Any one off returns 403 API access is not enabled for this workspace.
Request body
Content type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
| type | string one of email · whatsapp · messenger · instagram · slack · sms · voice | Required | Channel type. |
| chatbotId | string uuid | Required | The chatbot to attach. |
| config | object | Optional | The transport's credentials and settings — send the variant matching type (and, for the phone-flavoured types, config.provider). messenger, instagram, sms, voice and whatsapp are rejected without theirs. slack and email are not: their configs are accepted as-is, so a Slack channel missing its credentials connects successfully and then fails on its first webhook. Unrecognised extra keys are stored unchanged. The whole object is encrypted at rest and is never returned by any read endpoint — losing it means reconnecting the channel. |
Slack — type: slack | |||
| config.signingSecret | string at least 1 chars | Required | Slack Basic Information → App Credentials → Signing Secret, used to verify inbound events. Not enforced at connect: a channel without it connects and then rejects Slack's first webhook. |
| config.botToken | string at least 1 chars | Required | The Bot User OAuth token (xoxb-…) used to post replies. Not enforced at connect; without it replies cannot be sent. |
Email — type: email | |||
| config.fromName | string | Optional | Display name on outbound replies. Falls back to the workspace's configured sender name. |
| config.subject | string | Optional | Subject line on outbound replies. Defaults to "Reply from support". |
Messenger — type: messenger | |||
| config.appSecret | string at least 1 chars | Required | The Meta app secret, used to verify the X-Hub-Signature-256 on inbound webhooks. |
| config.verifyToken | string at least 1 chars | Required | The token you enter in Meta's webhook setup; Meta echoes it back on the subscription handshake. |
| config.pageAccessToken | string at least 1 chars | Required | The Page access token used to send replies. Checked against the Graph API at connect time in production. |
| config.graphVersion | string | Optional | Pins the Graph API version for this channel (e.g. v21.0). Omit to use the platform default. |
Instagram — type: instagram | |||
| config.appSecret | string at least 1 chars | Required | The Meta app secret, used to verify inbound webhook signatures. |
| config.verifyToken | string at least 1 chars | Required | The token Meta echoes back on the webhook subscription handshake. |
| config.accessToken | string at least 1 chars | Required | A long-lived Instagram user token from the Instagram Login API. Evoriqa refreshes it before its 60-day expiry, and resolves the IG user id from it at connect. |
| config.igUserId | string | Optional | The Instagram account id. In production the connect probe resolves it from accessToken, so send it only when that resolution is unavailable — without it, outbound replies cannot be addressed. |
| config.graphVersion | string | Optional | Pins the Graph API version for this channel. Omit to use the platform default. |
WhatsApp Cloud API — type: whatsapp, provider: whatsapp_cloud | |||
| config.provider | string the literal whatsapp_cloud | Required | Selects Meta's own WhatsApp Cloud API as the transport. |
| config.appSecret | string at least 1 chars | Required | The Meta app secret, used to verify inbound webhook signatures. |
| config.verifyToken | string at least 1 chars | Required | The token Meta echoes back on the webhook subscription handshake. |
| config.accessToken | string at least 1 chars | Required | The WhatsApp Business access token used to send messages. |
| config.phoneNumberId | string at least 1 chars | Required | The Meta phone-number id (not the phone number). It is this channel's identity for the shared-number conflict check. |
| config.graphVersion | string | Optional | Pins the Graph API version for this channel. Omit to use the platform default. |
Telnyx — type: sms · voice · whatsapp, provider: telnyx | |||
| config.provider | string the literal telnyx | Required | Selects Telnyx as the transport. |
| config.apiKey | string at least 1 chars | Required | The Telnyx API key used for outbound messages and calls. |
| config.publicKey | string at least 1 chars | Required | The Telnyx public key that signs inbound webhooks; Evoriqa rejects unsigned or mis-signed deliveries. |
| config.fromNumber | string at least 1 chars | Required | The sending number in E.164. Its digits are this channel's identity for the shared-number conflict check. |
| config.voice | string | Optional | voice channels only — the TTS voice id, one of the Telnyx catalog (Amazon Polly standard and neural ids such as Polly.Joanna, plus the basic man · woman · alice). Omit or send an empty string for the server default; an unsupported id 422s with "Unsupported voice. Pick one from the voice list." |
| config.language | string | Optional | voice channels only — the speech locale (e.g. en-US), which must be one a Telnyx catalog voice speaks. Omit for the server default; an unsupported locale 422s. |
| config.greeting | string | Optional | voice channels only — the line spoken when the call is answered. Falls back to the chatbot's greeting message, then to a generated one. |
| config.forwardNumber | string | Optional | voice channels only — the number a human handoff dials. Without it, the call cannot be transferred. |
| config.transferMessage | string | Optional | voice channels only — spoken just before dialing forwardNumber. Defaults to "Sure, please hold while I connect you with a member of our team." |
| config.dialTimeout | integer 5–60 | Optional | voice channels only — seconds to ring forwardNumber before giving up. Clamped to 5–60; defaults to 20. |
Infobip — type: sms · voice · whatsapp, provider: infobip | |||
| config.provider | string the literal infobip | Required | Selects Infobip as the transport. |
| config.apiKey | string at least 1 chars | Required | The Infobip API key. |
| config.baseUrl | string matches ^https://[a-z0-9-]+\.api\.infobip\.com$ | Required | Your account's Infobip host, exactly as shown in the Infobip portal. Anything else is rejected — the value is used to build outbound calls, so it is pinned to the Infobip domain. |
| config.fromNumber | string at least 1 chars | Required | The Infobip sender number or sender id. Its digits are this channel's identity for the shared-number conflict check. |
| config.voice | string | Optional | voice channels only — Infobip picks the voice from language, so the only accepted ids are the per-locale defaults infobip-default-<locale> (for example infobip-default-en-US). Omit for the server default. |
| config.language | string | Optional | voice channels only — one of en-US · es-ES · fr-FR · de-DE · pt-BR · it-IT · nl-NL. Omit for the server default; anything else 422s. |
| config.greeting | string | Optional | voice channels only — the line spoken when the call is answered. Falls back to the chatbot's greeting message, then to a generated one. |
| config.forwardNumber | string | Optional | voice channels only — the number a human handoff dials. Without it, the call cannot be transferred. |
| config.transferMessage | string | Optional | voice channels only — spoken just before dialing forwardNumber. Defaults to "Sure, please hold while I connect you with a member of our team." |
| config.dialTimeout | integer 5–60 | Optional | voice channels only — seconds to ring forwardNumber before giving up. Clamped to 5–60; defaults to 20. |
Request
curl -X POST "https://app.evoriqa.com/api/v1/channels" \
-H "x-api-key: $EVORIQA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "whatsapp", "chatbotId": "3f2504e0-4f89-41d3-9a0c-0305e82c3301", "config": { "provider": "whatsapp_cloud", "appSecret": "8f1c…", "verifyToken": "my-verify-token", "accessToken": "EAAG…", "phoneNumberId": "109876543210987" } }'const res = await fetch("https://app.evoriqa.com/api/v1/channels", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.EVORIQA_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"type": "whatsapp",
"chatbotId": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"config": {
"provider": "whatsapp_cloud",
"appSecret": "8f1c…",
"verifyToken": "my-verify-token",
"accessToken": "EAAG…",
"phoneNumberId": "109876543210987"
}
}),
});
const responseBody = await res.json();import os
import requests
res = requests.post(
"https://app.evoriqa.com/api/v1/channels",
headers={"Authorization": f"Bearer {os.environ['EVORIQA_API_KEY']}"},
json={
"type": "whatsapp",
"chatbotId": "3f2504e0-4f89-41d3-9a0c-0305e82c3301",
"config": {
"provider": "whatsapp_cloud",
"appSecret": "8f1c…",
"verifyToken": "my-verify-token",
"accessToken": "EAAG…",
"phoneNumberId": "109876543210987"
}
},
)
body = res.json()Response
{
"success": true,
"data": {
"id": "0b8de9f2-4c11-4f7e-9a34-5c6d7e8f9a0b",
"type": "whatsapp",
"inboundSecret": "chs_1f4a…shown-once"
}
}