Skip to main content
This guide is for teams that use HubSpot as their CRM and want a self-hosted way to add Text conversation summaries to contact timelines without sending chat transcripts to a separate AI provider. By the end of this guide, the service receives summaries directly from Text, creates or updates HubSpot contacts by customer email, and adds the chat summary to the matching contact timeline.

Prerequisites

  • A Text account with API access permission.
  • A HubSpot account with permission to create and install an app.
  • Docker with Docker Compose v2.
  • cloudflared to expose the local service through a Cloudflare Quick Tunnel. You don’t need it if the service already has a public HTTPS address.
  • Git to clone the sample repository.
livechat/text-hubspot-contact-integration
Loading repository data...

Set up the integration

This guide runs a webhook service between Text and HubSpot. When a conversation closes, Text sends a chat_deactivated webhook. The service retrieves the customer and Text-generated summary, creates or updates the matching HubSpot contact by email, then adds the summary to its timeline.
1

Create the Text API access

In Text, go to Settings → API access → Personal access tokens. Create a personal access token with the following scopes:
  • chats--all:rw — to read chats and request summaries in any group, or chats--access:rw to limit access to groups that the token owner is a member of.
  • customers:ro — to read the customer’s email and name.
  • webhooks.configuration:rw — to register the webhook.
Copy the Base64-encoded token value that Text displays — this is your combined account_id:personal_access_token.Go to Settings → API access → OAuth clients, create an OAuth client for the integration, and copy its client ID. You will register the webhooks for this OAuth client.The personal access token authorizes the Text API calls used by the service and webhook setup. The OAuth client ID identifies the integration that owns the registered webhook.
Treat the personal access token like a password. Store it in a secrets manager for a deployed service and never publicly commit it.
2

Create the HubSpot API access

Follow HubSpot’s app creation guide to create and upload an app. Choose private distribution and static authentication, then configure these scopes:
  • crm.objects.contacts.read to find a contact by email.
  • crm.objects.contacts.write to create or update the contact.
  • crm.objects.notes.write to create the associated note.
After uploading the app, install it with a static token in the HubSpot account you want to connect. Copy the generated access token. You will set it as HUBSPOT_ACCESS_TOKEN when configuring the service.Static authentication connects the sample to one HubSpot account. Use OAuth instead when your app needs to connect multiple HubSpot accounts.The service uses the HubSpot contacts API for contact management and the HubSpot notes API to add summaries to contact timelines.
3

Clone and configure the service

Clone the repository and enter its directory:
Create a .env file with the following values:
Generate a webhook secret with a command such as:
Set the generated value as TEXT_WEBHOOK_SECRET.The service listens locally at http://localhost:8080, but Text needs a public HTTPS address to deliver webhook events. For local testing, a free Cloudflare Quick Tunnel gives the local service a temporary public address.To start the tunnel, run cloudflared in a separate terminal:
The command prints a temporary https://<random-name>.trycloudflare.com address. Keep the tunnel running while you test. If its address changes after you register the webhook, unregister the old webhook before registering it again.Set WEBHOOK_PUBLIC_URL to the tunnel address without a trailing slash. For a deployed service, skip the tunnel and use the service’s public HTTPS address instead.The repository excludes .env from Git. Keep the file private because it contains credentials for both systems.
4

Register the Text webhook

Load the values from .env into your terminal session:
Register a license-level chat_deactivated webhook with the register_webhook method:
The response contains the webhook ID.Run the registration once. To check the registrations owned by a specific OAuth client ID, use List webhooks.
After you register the webhook, the service copies customer identity and conversation summaries to HubSpot. Confirm that this data flow meets your privacy, consent, retention, and deletion requirements before you activate it for customer conversations.
5

Start the service

Build and start the container:
Confirm that the service is healthy:
A healthy service returns HTTP 204.Follow its logs while you test the integration:
6

Verify the HubSpot contact and note

The service matches HubSpot contacts by customer email and skips chats without one. It maps the Text customer name to HubSpot firstname and lastname by splitting at the first whitespace.To test the service, start a chat as a customer with an email address, exchange at least one message, then close the chat.The service log should contain synced Text chat with the Text chat ID, thread ID, and HubSpot contact ID. In HubSpot, open the contact with the same email address. Its activity timeline should contain a note with the summary title and bullet points and the chat details.

Troubleshooting

Prepare the design for production

The sample demonstrates the integration flow, but it does not protect every sync from service restarts, temporary API failures, or repeated webhook deliveries. Before deploying the service, adapt the sample in three areas.
The sample confirms receipt of a webhook before the sync finishes. It does not save unfinished work or remember which threads it has processed, so a restart can lose a sync and a repeated webhook can create a duplicate note.Before deploying:
  • Save each sync job in a durable queue before confirming receipt of the webhook.
  • Retry temporary Text and HubSpot failures, and alert your team when a job still fails.
  • Record processed Text thread IDs so repeated webhook deliveries do not create another note.
  • Continue delayed summary work after receiving the thread_summary_set webhook instead of relying on the sample’s 60-second polling window.
The sample matches contacts by email, updates name fields from Text, and creates one note for every closed thread. Those choices may not match how your team manages customer records in HubSpot.Before deploying:
  • Decide whether Text or HubSpot owns each contact field.
  • Store a Text customer ID to HubSpot contact ID mapping if email addresses can change.
  • Decide how to handle customers without an email address or with duplicate HubSpot contacts.
  • Choose whether HubSpot receives one note per thread or one note per chat.
The sample exposes a webhook endpoint and copies customer identity and conversation summaries from Text to HubSpot. It does not define how the copied data is retained or deleted.Before deploying:
  • Run the service behind a stable HTTPS endpoint with health checks and monitoring.
  • Store credentials in a secrets manager and rotate the webhook secret.
  • Copy only the customer data you need and restrict access to it.
  • Define retention and deletion behavior for the copied data in both Text and HubSpot.