Files
74db16158d feat: migrate dyte integration to cloudflare realtimekit (#14752)
Dyte is sunsetting its existing infrastructure after the Cloudflare
acquisition, so this migrates Chatwoot’s video call integration to
Cloudflare RealtimeKit.

The integration now uses Cloudflare Account ID, RealtimeKit App ID, and
a Cloudflare API token with Realtime Admin permissions. Meeting creation
and participant token generation now call Cloudflare’s RealtimeKit APIs,
while the existing Chatwoot call experience remains unchanged for agents
and customers.

This also adds setup-time credential validation, so admins get clearer
errors when the API token is invalid, the Cloudflare account or
permissions are incorrect, or the RealtimeKit App ID does not belong to
the selected account.

Fixes
https://linear.app/chatwoot/issue/PLA-176/migrate-dyte-integration-to-cloudflare-realtimekit

**How to test**

1. Go to Settings → Integrations → Cloudflare RealtimeKit.
2. Add a Cloudflare Account ID, RealtimeKit App ID, and API token with
Realtime Admin permissions.
3. Confirm the integration saves successfully with valid credentials.
4. Try invalid credentials and confirm the error identifies whether the
token, account/permissions, or app ID is wrong.
5. Start a video call from a conversation and confirm the RealtimeKit
meeting opens.

---------

Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com>
Co-authored-by: Sony Mathew <sony@chatwoot.com>
2026-06-24 11:04:08 +04:00

331 lines
10 KiB
YAML

###### Attributes Supported by Integration Apps #######
# id: Internal Id for the integrations, used by the hooks
# logo: place the image in /public/dashboard/images/integrations and reference here
# i18n_key: the key under which translations for the integration is placed in en.yml
# action: if integration requires external redirect url
# hook_type: ( account / inbox )
# feature_flag: (string) feature flag to enable/disable the integration
# allow_multiple_hooks: whether multiple hooks can be created for the integration
# visible_properties: hook setting keys safe to return in API responses and show in the UI
# settings_json_schema: the json schema used to validate the settings hash (https://json-schema.org/)
# settings_form_schema: the formulate schema used in frontend to render settings form (https://vueformulate.com/)
########################################################
webhooks:
id: webhook
logo: webhooks.png
i18n_key: webhooks
action: /webhook
hook_type: account
allow_multiple_hooks: true
dashboard_apps:
id: dashboard_apps
logo: dashboard_apps.png
i18n_key: dashboard_apps
hook_type: account
allow_multiple_hooks: true
openai:
id: openai
logo: openai.png
i18n_key: openai
action: /openai
hook_type: account
allow_multiple_hooks: false
settings_json_schema:
{
'type': 'object',
'properties':
{
'api_key': { 'type': 'string' },
'label_suggestion': { 'type': 'boolean' },
},
'required': ['api_key'],
'additionalProperties': false,
}
settings_form_schema:
[
{
'label': 'API Key',
'type': 'text',
'name': 'api_key',
'validation': 'required',
},
{
'label': 'Show label suggestions',
'type': 'checkbox',
'name': 'label_suggestion',
'validation': '',
},
]
visible_properties: ['label_suggestion']
linear:
id: linear
logo: linear.png
i18n_key: linear
action: https://linear.app/oauth/authorize
hook_type: account
allow_multiple_hooks: false
visible_properties: []
notion:
id: notion
logo: notion.png
i18n_key: notion
hook_type: account
allow_multiple_hooks: false
visible_properties: []
slack:
id: slack
logo: slack.png
i18n_key: slack
action: https://slack.com/oauth/v2/authorize?scope=commands,chat:write,channels:read,channels:manage,channels:join,groups:read,groups:write,im:write,mpim:write,users:read,users:read.email,chat:write.customize,channels:history,groups:history,mpim:history,im:history,files:read,files:write
hook_type: account
allow_multiple_hooks: false
visible_properties: ['channel_name']
dialogflow:
id: dialogflow
logo: dialogflow.png
i18n_key: dialogflow
action: /dialogflow
hook_type: inbox
allow_multiple_hooks: true
settings_json_schema:
{
'type': 'object',
'properties':
{
'project_id': { 'type': 'string' },
'credentials': { 'type': 'object' },
'region': { 'type': 'string' },
'language_code': { 'type': 'string' },
},
'required': ['project_id', 'credentials'],
'additionalProperties': false,
}
settings_form_schema:
[
{
'label': 'Dialogflow Project ID',
'type': 'text',
'name': 'project_id',
'validation': 'required',
'validationName': 'Project Id',
},
{
'label': 'Dialogflow Project Key File',
'type': 'textarea',
'name': 'credentials',
'validation': 'required|JSON',
'validationName': 'Credentials',
'validation-messages':
{ 'JSON': 'Invalid JSON', 'required': 'Credentials is required' },
},
{
'label': 'Dialogflow Region',
'type': 'select',
'name': 'region',
'default': 'global',
'options': [
{ 'label': 'Global - Default', 'value': 'global' },
{ 'label': 'AS-NE1 - Tokyo, Japan', 'value': 'asia-northeast1' },
{ 'label': 'AU-SE1 - Sydney, Australia', 'value': 'australia-southeast1' },
{ 'label': 'EU-W1 - St. Ghislain, Belgium', 'value': 'europe-west1' },
{ 'label': 'EU-W2 - London, England', 'value': 'europe-west2' },
],
},
{
'label': 'Language Code',
'type': 'select',
'name': 'language_code',
'default': 'en-US',
'help': 'Language code for Dialogflow agent. Use "auto" to detect from contact language.',
'options': [
{ 'label': 'Auto-detect from contact', 'value': 'auto' },
{ 'label': 'English (US)', 'value': 'en-US' },
{ 'label': 'English (UK)', 'value': 'en-GB' },
{ 'label': 'Spanish (Spain)', 'value': 'es-ES' },
{ 'label': 'Spanish (Latin America)', 'value': 'es-419' },
{ 'label': 'French', 'value': 'fr-FR' },
{ 'label': 'German', 'value': 'de-DE' },
{ 'label': 'Portuguese (Brazil)', 'value': 'pt-BR' },
{ 'label': 'Portuguese (Portugal)', 'value': 'pt-PT' },
{ 'label': 'Italian', 'value': 'it-IT' },
{ 'label': 'Japanese', 'value': 'ja-JP' },
{ 'label': 'Korean', 'value': 'ko-KR' },
{ 'label': 'Chinese (Simplified)', 'value': 'zh-CN' },
{ 'label': 'Chinese (Traditional)', 'value': 'zh-TW' },
{ 'label': 'Hindi', 'value': 'hi-IN' },
{ 'label': 'Arabic', 'value': 'ar' },
{ 'label': 'Russian', 'value': 'ru-RU' },
{ 'label': 'Dutch', 'value': 'nl-NL' },
{ 'label': 'Polish', 'value': 'pl-PL' },
{ 'label': 'Turkish', 'value': 'tr-TR' },
{ 'label': 'Thai', 'value': 'th-TH' },
{ 'label': 'Vietnamese', 'value': 'vi-VN' },
{ 'label': 'Indonesian', 'value': 'id-ID' },
],
},
]
visible_properties: ['project_id', 'region', 'language_code']
google_translate:
id: google_translate
logo: google-translate.png
i18n_key: google_translate
action: /google_translate
hook_type: account
allow_multiple_hooks: false
settings_json_schema:
{
'type': 'object',
'properties':
{
'project_id': { 'type': 'string' },
'credentials': { 'type': 'object' },
},
'required': ['project_id', 'credentials'],
'additionalProperties': false,
}
settings_form_schema:
[
{
'label': 'Google Cloud Project ID',
'type': 'text',
'name': 'project_id',
'validation': 'required',
'validationName': 'Project Id',
},
{
'label': 'Google Cloud Project Key File',
'type': 'textarea',
'name': 'credentials',
'validation': 'required|JSON',
'validationName': 'Credentials',
'validation-messages':
{ 'JSON': 'Invalid JSON', 'required': 'Credentials is required' },
},
]
visible_properties: ['project_id']
dyte:
id: dyte
logo: dyte.png
i18n_key: dyte
action: /dyte
hook_type: account
allow_multiple_hooks: false
settings_json_schema:
{
'type': 'object',
'properties':
{
'account_id': { 'type': 'string' },
'app_id': { 'type': 'string' },
'api_token': { 'type': 'string' },
},
'required': ['account_id', 'app_id', 'api_token'],
'additionalProperties': false,
}
settings_form_schema:
[
{
'label': 'Cloudflare Account ID',
'type': 'text',
'name': 'account_id',
'validation': 'required',
},
{
'label': 'RealtimeKit App ID',
'type': 'text',
'name': 'app_id',
'validation': 'required',
},
{
'label': 'Cloudflare API Token',
'type': 'text',
'name': 'api_token',
'validation': 'required',
},
]
visible_properties: ['account_id', 'app_id']
shopify:
id: shopify
logo: shopify.png
i18n_key: shopify
hook_type: account
allow_multiple_hooks: false
visible_properties: []
leadsquared:
id: leadsquared
feature_flag: crm_integration
logo: leadsquared.png
i18n_key: leadsquared
action: /leadsquared
hook_type: account
allow_multiple_hooks: false
settings_json_schema:
{
'type': 'object',
'properties':
{
'access_key': { 'type': 'string' },
'secret_key': { 'type': 'string' },
'endpoint_url': { 'type': 'string' },
'app_url': { 'type': 'string' },
'timezone': { 'type': 'string' },
'enable_conversation_activity': { 'type': 'boolean' },
'enable_transcript_activity': { 'type': 'boolean' },
'conversation_activity_score': { 'type': 'string' },
'transcript_activity_score': { 'type': 'string' },
'conversation_activity_code': { 'type': 'integer' },
'transcript_activity_code': { 'type': 'integer' },
},
'required': ['access_key', 'secret_key'],
'additionalProperties': false,
}
settings_form_schema:
[
{
'label': 'Access Key',
'type': 'text',
'name': 'access_key',
'validation': 'required',
},
{
'label': 'Secret Key',
'type': 'text',
'name': 'secret_key',
'validation': 'required',
},
{
'label': 'Push Conversation Activity',
'type': 'checkbox',
'name': 'enable_conversation_activity',
'help': 'Enable this option to push an activity when a conversation is created',
},
{
'label': 'Conversation Activity Score',
'type': 'number',
'name': 'conversation_activity_score',
'help': 'Score to assign to the conversation created activity, default is 0',
},
{
'label': 'Push Transcript Activity',
'type': 'checkbox',
'name': 'enable_transcript_activity',
'help': 'Enable this option to push an activity when a transcript is created',
},
{
'label': 'Transcript Activity Score',
'type': 'number',
'name': 'transcript_activity_score',
'help': 'Score to assign to the conversation transcript activity, default is 0',
},
]
visible_properties:
[
'endpoint_url',
'enable_conversation_activity',
'enable_transcript_activity',
'conversation_activity_score',
'transcript_activity_score',
]