What you will build

A service with three Voiceflow-facing endpoints and a verified provider-event receiver. It opens a support conversation, forwards customer messages, and sends human replies back to Voiceflow.

Two-way conversation through your connection
VoiceflowCustomer conversation
Then
Your connection serviceTranslate requests and authenticated events
Then
Support platformHuman support inbox

Messages travel in both directions through the same connection. Your service owns the mapping between the two conversation IDs.

Before you begin

Use a developer test account, a teammate who can answer, Node.js 22 or later, and HTTPS hosting. You need API access and event delivery for your support platform. Confirm Custom Handoff is available in your Voiceflow workspace. Choose a platform guide.

The downloadable learning server is runnable in mock mode and includes a text-only Chatwoot pilot. Other platform guides describe the provider implementation you must add. It is a single-process example with in-memory state, not a production deployment.

Build and connect the service

1

Download and test the starter

Save server.mjs, protocol.mjs, chatwoot.mjs, and test.mjs in one directory. Run:

Tests run against local fixtures, without provider accounts.

2

Configure a local test

Set HANDOFF_TOKEN for Voiceflow-to-service authentication, a different EVENT_TOKEN for your normalized event receiver, WEBHOOK_SECRET with at least 32 random characters, VOICEFLOW_PROJECT_ID, and VOICEFLOW_WEBHOOK_URL. Store them outside source control.

Mock mode exercises the connection contract but does not contact a support platform. The server binds to localhost; put it behind your HTTPS proxy for Voiceflow testing.

3

Implement the provider operations

Implement create(request, connectionId), message(providerConversationId, message), and end(providerConversationId). create must return the provider conversation ID. Use the provided connection ID as provider metadata when supported. Persist customer identity and queue mapping in your implementation. The connection reference defines all inputs. Set files: true only after implementing attachment handling; the starter rejects files otherwise.

4

Verify and translate provider events

Build a provider receiver using the vendor’s documented authentication or signature check. Reject untrusted events before mapping IDs. Translate only human-facing events; exclude internal notes and customer echoes. Send normalized events to the starter’s /events route with Authorization: Bearer EVENT_TOKEN. This is a private service-to-service route, not the vendor webhook URL.

Store provider-event IDs for deduplication. Buffer events arriving before creation completes. Event reference defines the normalized shape and Voiceflow signatures.

5

Connect Voiceflow

In Settings → Integrations → Custom Handoff, set Base URL to your HTTPS service, Auth header name to Authorization, Auth header value to Bearer followed by your HANDOFF_TOKEN, and Webhook secret to WEBHOOK_SECRET. Complete handoff setup.

6

Harden before production

Replace the example Maps with durable, tenant-scoped storage and atomic idempotency records. Use a persistent outbox with bounded retries and operational alerts. Reconcile ambiguous provider timeouts before creating duplicates. Apply retention to customer data, enforce file limits, and test credential rotation. Deploy a provider-authenticated webhook receiver; do not expose /events using a public shared token in client code.

Verify the whole conversation

Create a test escalation; inspect the receiving inbox; send a customer reply and a human reply; close the conversation; verify the configured return path. Repeat creation with the same idempotency key and replay a message/event ID: each should create one visible effect. Test invalid credentials, missing IDs, a provider timeout, and a callback delivered before create completes. These checks require your provider account; local fixture tests do not prove them.

Next steps

Choose a platform guide · Connection API · Events


Use the up and down arrow keys to select a result, Enter to open it, and Escape to close the search.