Loading…

Star4.1kBook a meeting

Channel Integrations

Connect external channels to the inbox: Facebook, Instagram, mail, Discord, Call, and Call Pro, plus the integration lifecycle and webhook routes.

Backend: backend/plugins/frontline_api/src/modules/integrations/<kind>/ holds one runtime per kind; integrations/trpc is the in-plugin tRPC router. Frontend: frontend/plugins/frontline_ui/src/modules/{integrations,integrations-config}.

Concepts

Integration kinds

Every Integration record has a kind. inbox.getIntegrationKinds (modules/inbox/utils.ts) returns the registered map: messenger (Messenger), lead (Popups & forms), webhook (Webhook, a generic inbound webhook with an auto-generated token), booking, callpro (Callpro), mail (Email), facebook-messenger, facebook-post, instagram-messenger, instagram-post, discord-messenger (Discord), calls (Phone call), client (Client Portal), and vendor (Vendor Portal). Creation code also accepts cloudflarecalls as a service kind.

An integration is always attached to one channel. integrationsCreateExternalIntegration refuses channelId values that point at another user's personal channel; when no channelId is given, the integration lands in the connecting user's own personal channel.

Warning

integrationsCreateExternalIntegration fails with Channel … not found for an unknown channelId (create the channel first) and with Cannot create an integration on another user's personal channel when the target is someone else's scope: personal channel (omit channelId to use your own).

Lifecycle operations

Mutations live in resolvers/mutations/integrations.ts.

Operation Purpose
integrationsCreateExternalIntegration(data, channelId, brandId, accountId, kind, name, …) Create a channel integration; forwards to the per-kind service over tRPC
integrationsCreateMessengerOnboarding / integrationsEditMessengerOnboarding / integrationsCreateMessengerIntegration / integrationsEditMessengerIntegration / integrationsSaveMessengerConfigs / integrationsSaveMessengerAppearanceData / integrationsSaveMessengerColorTheme / integrationsSaveMessengerTicketData erxes messenger integration + widget config
integrationsCreateLeadIntegration / integrationsEditLeadIntegration / integrationsCopyLeadIntegration Lead (form) integrations
integrationsEditCommonFields(_id, name, details, channelId, brandId) Rename, re-channel, or update details; pushes sendUpdateIntegration to the kind's service
integrationsRepair(_id, kind) Recreate the service-side resources for an integration
integrationsArchive(_id, status) Archive/unarchive a conversation stream
integrationsRemove(_id) Remove the integration and its conversations/messages
integrationsRemoveAccount(_id, kind) Remove an OAuth account and all its integrations
integrationsSendSms(integrationId, content, to) Send an SMS through a supported integration

Queries: integrations, integrationDetail, allLeadIntegrations, integrationsGetUsedTypes, integrationsGetUsedTypesByChannel, integrationGetLineWebhookUrl, integrationsTotalCount, and integrationsGetMessengerColorThemes, plus per-kind lists.

Webhook routes

src/routes.ts mounts routers on the plugin's Express app:

Mount Purpose
/facebook Meta webhook: GET verification against FACEBOOK_VERIFY_TOKEN config, POST Messenger/feed/comment events
/instagram Meta webhook for Instagram events
/mail POST /mail/receive: HMAC-signed email payloads from the Cloudflare Email Routing worker
/callpro POST /callpro/receive: Call Pro PBX events; mounted only when CALLPRO_ENABLED=true

Inbound payloads flow into receiveInboxMessage, which creates/reuses the customer, conversation, and message and publishes conversationClientMessageInserted.

Facebook and Instagram (Meta)

App credentials come from getConfig: per-workspace config records first, environment variables as fallback; environment-only when VERSION=saas.

Env var Purpose
FACEBOOK_APP_ID, FACEBOOK_APP_SECRET Main Meta app for messenger/post integrations
FACEBOOK_POST_APP_ID, FACEBOOK_POST_APP_SECRET Separate app for comment/feed captures
FACEBOOK_VERIFY_TOKEN Webhook GET verification token
FACEBOOK_PERMISSIONS OAuth permission list
FACEBOOK_LOGIN_REDIRECT_URL OAuth redirect URL
FACEBOOK_GRAPH_URL Graph API base URL
INSTAGRAM_APP_ID, INSTAGRAM_APP_SECRET, INSTAGRAM_PERMISSIONS, INSTAGRAM_LOGIN_REDIRECT_URL, INSTAGRAM_VERIFY_TOKEN Instagram equivalents

The facebook/instagram modules store per-integration tokens and page/account state, mirror comments/messages into conversations, and expose GraphQL login/reply/account helpers. Facebook and Instagram automation triggers/actions (e.g., comment events) are registered from meta/automations, and the Facebook comment outbox worker starts at plugin init (main.ts).

Mail

Inbound and outbound mail run through Cloudflare.

  1. A Cloudflare Email Routing worker posts inbound email to POST /mail/receive on this API, signed with MAIL_WEBHOOK_SECRET (HMAC). MAIL_RECEIVE_URL, MAIL_WORKER_URL, and MAIL_TENANT configure the worker side.
  2. Mail messages thread onto conversations by mailData/References/In-Reply-To headers; each mail integration maps to one inbox channel.
  3. Outbound mail uses Cloudflare Email Sending. A workspace connects its own Cloudflare account (mailCloudflareConnect, mailCloudflareProvision, mailCloudflareDisconnect); without one, the deployment's fallback account (MAIL_DOMAIN, MAIL_SENDING_ACCOUNT_ID, MAIL_SENDING_API_TOKEN, MAIL_SENDING_DAILY_LIMIT) is used.
  4. mailPipelineIntegration/mailPipelineConnect/mailPipelineUpdate/mailPipelineForwardVerified/mailPipelineDisconnect route mail into pipelines; mailSendMail, mailMessageRetry, mailConversationDetail, mailSendingReadiness, mailCloudflareConnection, mailCloudflareSendingQuota, mailCloudflareZones, mailCheckConnection cover sending, retry, and diagnostics.

Discord

initDiscord() runs at plugin startup (main.ts) and opens a Discord gateway client per configured integration; guild messages become conversations and agent replies post back through the Discord API. Discord automation entries are registered in meta/automations.

Call (SIP/CDR)

The call module stores CallCdrs and integrates a SIP provider via CALL_ENDPOINT_URL. CALL_WEBHOOK_REQUIRE_SIGNATURE=true enforces signed webhooks; CALL_SUBSCRIPTION_REQUIRE_AUTH=true requires auth on the call GraphQL subscription. CDR records join inbox search by phone number and feed the call report services.

Call Pro (webhook PBX)

Call Pro is gated per tenant (the subdomain a request belongs to):

  • CALLPRO_ENABLED=true turns the module on; CALLPRO_SUBDOMAINS is a comma-separated tenant allowlist on shared deployments.
  • Tenants outside the allowlist get a disabled config, a 404 from /callpro/receive, and rejected create/update operations.
  • POST /callpro/receive ingests PBX call events, which appear as conversations/CDR entries and feed call reports.

Bot automations

Conversation automation is coordinated through automatedReplyControl on each conversation (status, reason, pausedUntil) and the conversationSetAutomatedReplyControl mutation. A bot sets handoff_requested; an agent accepts with human_active. The automationStatus inbox filter exposes these states (standby, handoff, responded).

Environment variables

Variable Module Purpose
FACEBOOK_* / INSTAGRAM_* facebook, instagram Meta app credentials and OAuth settings
FACEBOOK_GRAPH_URL facebook Graph API base URL
MAIL_RECEIVE_URL, MAIL_WORKER_URL, MAIL_TENANT, MAIL_WEBHOOK_SECRET mail Inbound worker delivery
MAIL_DOMAIN, MAIL_SENDING_ACCOUNT_ID, MAIL_SENDING_API_TOKEN, MAIL_SENDING_DAILY_LIMIT mail Deployment-level Cloudflare Email Sending fallback
CALL_ENDPOINT_URL, CALL_WEBHOOK_REQUIRE_SIGNATURE, CALL_SUBSCRIPTION_REQUIRE_AUTH call SIP/CDR endpoint and auth toggles
CALLPRO_ENABLED, CALLPRO_SUBDOMAINS callpro Enable + tenant allowlist
DOMAIN, ENDPOINT_URL, JWT_TOKEN_SECRET, VERSION shared Platform URLs, token signing, saas mode

Operate on one system.

Talk to our team about consolidating your stack onto erxes. 30-minute walkthrough, custom to your org.