Skip to main content
This guide is for teams that define their own customer properties in Text — plan tier, renewal date, or something else that you want tracked — and want them, along with chat summaries, usable in HubSpot segments and workflow automations. By the end of this guide, the service creates or updates the matching HubSpot contact, syncing the Text customer properties you map and each chat’s summary onto it whenever a chat closes.

Prerequisites

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, their Text-generated summary, and any customer properties you’ve mapped. It then creates or updates the matching HubSpot contact by email, writes the mapped properties onto it, and 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, and customer properties.
  • 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 webhook 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 data and its properties.
  • crm.objects.notes.write to create the associated note.
The properties themselves must already exist on the HubSpot object — the service writes values to them but doesn’t create them.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:
To sync Text customer properties to HubSpot, build a JSON object that pairs each Text customer property’s name with the internal name of its matching HubSpot contact property, then set it as TEXT_TO_HUBSPOT_PROPERTY_MAP. Wrap the JSON in single quotes to avoid escaping the double quotes:
Get each key from Text’s List customer property definitions response — its name field is the property’s name as defined in Text.Get each value from HubSpot’s matching contact property — a HubSpot property has both an internal name and a display label, and the map needs the internal name, not the label. Find it in HubSpot under Settings → Properties, or read the name field from HubSpot’s Get all properties response (GET /crm/v3/properties/contacts).The service checks this map on every sync. Text properties that aren’t in the map are skipped, and each HubSpot property in the map must already exist. Leave the variable empty, or omit it, to sync only chat summaries.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, conversation summaries, and any mapped customer properties 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. If you set TEXT_TO_HUBSPOT_PROPERTY_MAP, the mapped contact properties should also match the customer’s property values in Text.

Use synced properties in HubSpot

In our example, you mapped Text’s Company size property to HubSpot’s company_size. If a customer’s company size is set to Enterprise, this value syncs onto their HubSpot contact the moment their chat closes. From there, you can filter a segment on company_size to send a custom mailing campaign, or set a workflow enrollment trigger for every enterprise-tier contact to be routed into a different communication track than your regular outreach. The same pattern works for any property you map, because Text customer properties are whatever your team defines, no matter what you’re tracking. A property marking a commercial detail, like a plan or contract status, can drive a workflow the moment it changes. A property flagging risk, like a support escalation or usage drop, can route or prioritize a contact differently. A property used for segmentation, like team size or industry, can filter a list for a specific campaign. Whatever the property is, once it’s synced, it’s just data HubSpot can act on. If none of this applies yet, there may be a distinction your team already makes in conversation — just not as a property yet. Treat the properties you map here as a starting point. Which ones are worth defining, and what HubSpot does with them, is up to your team.

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.
  • Limit TEXT_TO_HUBSPOT_PROPERTY_MAP to the Text customer properties your HubSpot segments, campaigns, or workflows actually use.
  • 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.