Walkthrough for the live session with Nilesh / DevOps / Zach / John: the real state of the Intercom ↔ RingCX (Engage Digital) bridge, what's confirmed with real calls, how it becomes yours to run and maintain, and what's fully on your side.
The original assumption was RingEX/MVP (OAuth Client ID/Secret). The real product is RingCX → Engage Digital, with its own request/response protocol (Channel SDK) — not a simple "notify and move on" webhook. Any doc or env var based on RingEX/OAuth/Validation-Token no longer applies.
A service that sits between Intercom and RingCX. When Fin escalates to a human, the bridge translates messages between both systems so the customer sees one continuous conversation.
RingCX doesn't passively notify: it asks, and our backend has to answer on the spot in the exact shape it expects.
| Exchange | Direction | What our backend does |
|---|---|---|
implementation.info | RingCX → us | Declares supported objects/actions (messages, threads · create, show, list, reply). Fires when the channel config is saved, then roughly every ~1 min on its own. |
messages.create | RingCX → us | Agent replied in RingCX → forward to Intercom → respond with {id, body}. |
*.list / *.show | RingCX → us | Sync request. "Real Time only" mode → we respond [] / {}. |
| Send API | us → RingCX | POST with action: messages.create and author = customer (avoids the cant_reply_to_agent error from the old REST API, now abandoned). |
| Channel | Mechanism |
|---|---|
| Intercom → bridge | HMAC-SHA1 · INTERCOM_CLIENT_SECRET · header X-Hub-Signature |
Intercom Workflow → bridge (/internal/escalate) | Shared secret · INTERNAL_HANDOFF_SECRET |
| RingCX ↔ bridge (Channel SDK, both directions) | HMAC-SHA512 · RINGCENTRAL_ENGAGE_SOURCE_SECRET · header X-SMCCSDK-SIGNATURE |
| pk | Content | Purpose |
|---|---|---|
conv:<intercom_conversation_id> | { ringcentral_thread_id } | New customer message in Intercom → which RingCX thread to forward it to |
rc:<ringcx_thread_id> | { intercom_conversation_id } | Agent replied in RingCX → which Intercom conversation to inject it into |
evt:<intercom_event_id> | { ttl } | Duplicate protection for Intercom webhook retries (24h TTL) |
Runs on DynamoDB Local for dev (Matías's machine) and points to real DynamoDB on AWS just by changing env vars — no code changes needed.
Confirmed with real tests: we generate the thread_id with crypto.randomUUID(), send it to RingCX as if it already existed, and RingCX creates it automatically the first time it sees it. No need to parse any ID out of RingCX's response. This significantly simplified escalation.js.
We already created the escalateops-bridge-bot identity with users.create and puppetizable: true. For a real agent to reply, John / Unicity needs to do this in their admin panel:
Nothing gets "transferred running." Unicity rebuilds the exact same thing on its own infrastructure, following this repo plus the checklist below — from that point on, Matías is no longer a dependency for keeping it alive.
server.js, the full src/ folder, package.json, package-lock.json, the Dockerfile, and this documentation. Skip node_modules (rebuilt with npm install) and skip .env — never shared as a file. The local test-*.js scripts are dev-only and optional to include.Dockerfile into an image and runs it on Unicity's own infrastructure (ECS/Fargate or equivalent), with its own permanent URL. No more ngrok.Customer writes in Intercom → lands as a real message in a RingCX thread (the email actually arrived) · Agent replies in RingCX → lands in the real Intercom conversation with zero errors · Brand-new thread created from scratch with a self-generated ID · All 3 security layers working · Persistent store in DynamoDB with duplicate protection.
Header: Authorization (INTERNAL_HANDOFF_SECRET, stored as an Authentication Token in the Data Connector) Action: escalation.js generates a new thread_id, creates the thread in RingCX, saves the mapping
Verification: X-SMCCSDK-SIGNATURE (HMAC-SHA512)
Mode: Real Time only → *.list responds [], *.show responds {}
100% on John/Unicity's side — see pillar 06 above
| Variable | Status |
|---|---|
INTERCOM_CLIENT_SECRET | in use |
INTERCOM_ACCESS_TOKEN | in use |
INTERNAL_HANDOFF_SECRET | in use |
RINGCENTRAL_ENGAGE_SEND_URL | in use — Send API URL, includes source_id |
RINGCENTRAL_ENGAGE_SOURCE_SECRET | in use — HMAC-SHA512 signing |
RINGCENTRAL_VERIFICATION_TOKEN, CLIENT_ID/SECRET, JWT, API_TOKEN, SERVER_URL, SOURCE_ID, AUTHOR_ID | dead — delete in cleanup — leftovers from RingEX/OAuth and the abandoned REST API |