> ## Documentation Index
> Fetch the complete documentation index at: https://docs.open.cx/llms.txt
> Use this file to discover all available pages before exploring further.

# HubSpot troubleshooting

> Debug HubSpot OAuth, reconnect prompts, ticket creation, reply sync, and legacy Private App issues.

Before debugging, have this ready:

* **Connection method** — is HubSpot connected with **OAuth Public App** or **Private App (legacy)** in [Settings → Integrations](https://platform.open.cx/settings/integrations)?
* **Session ID** — find it in the [OpenCX inbox](https://platform.open.cx/inbox) for the conversation in question.
* **HubSpot conversation or ticket link** — open the exact thread your rep is testing.

<Tip>
  If the modal says **Reconnect required**, reconnect with **OAuth Public App** first. HubSpot may have rejected the refresh token after the app was removed or permissions changed.
</Tip>

## Common scenarios

### **OAuth connect or reconnect fails**

<Tooltip tip="The OAuth install did not complete, the HubSpot user chose the wrong portal, or HubSpot rejected the app approval.">Likely cause</Tooltip>: wrong HubSpot portal, missing HubSpot admin access, canceled consent, or revoked app install.

**Fix:**

1. In OpenCX, open [**Settings → Integrations → HubSpot**](https://platform.open.cx/settings/integrations).
2. Choose **OAuth Public App** and click **Connect with HubSpot** or **Reconnect**.
3. In HubSpot, confirm you are approving the correct portal.
4. If HubSpot blocks the install, ask a HubSpot super admin to approve connected apps for the portal.
5. If the redirect lands back on an error toast, retry once and share the error text with OpenCX support.

### **Private App token save fails**

<Tooltip tip="The legacy token may be revoked, pasted into the wrong field, or missing required scopes.">Likely cause</Tooltip>: expired or revoked Private App token, wrong token format, or missing scopes.

**Fix:**

1. Use OAuth if your workspace allows it; the Private App path is legacy.
2. If you must use legacy, confirm the token starts with `pat-`.
3. Confirm the Private App includes the scopes listed in [Advanced: Private App (legacy)](/integrations/hubspot/connect#advanced-private-app-legacy).
4. Paste the token into **Private App Access Token**, enter the numeric **Default User ID**, and save.

### **Handoff runs but no ticket appears**

<Tooltip tip="The test channel isn't HubSpot-owned, ticket creation is disabled, or the contact couldn't be matched in HubSpot.">Likely cause</Tooltip>: the conversation didn't originate from a channel HubSpot owns (most common), ticket creation is disabled, or the contact has no email for HubSpot to match.

**Fix:**

1. **Check the channel.** Tickets appear automatically only when the conversation starts from a channel HubSpot owns — a HubSpot chat widget, or an email routed through a HubSpot inbox. Messages sent to OpenCX's `temporary+...@instant.cx` address never reach HubSpot, so no ticket is created.
2. **For non-HubSpot channels** (OpenCX email, widget, WhatsApp, SMS, phone), use the `create-hubspot-ticket-from-session` workflow action on handoff.
3. Check with your OpenCX admin whether ticket creation is enabled for HubSpot.
4. Confirm the contact in the OpenCX session has an email address — HubSpot needs it to associate the ticket with a contact.
5. If all of the above are correct, check that the webhook is still registered in HubSpot (see below).

### **Rep replies don't reach the customer**

<Tooltip tip="The webhook may not be registered, or the wrong events are subscribed.">Likely cause</Tooltip>: webhook not registered in HubSpot, wrong event subscriptions, uncommitted subscription changes, or stale webhook URL.

**Fix:**

1. Confirm HubSpot still shows **Connected via OAuth** in OpenCX. Reconnect if the modal shows **Reconnect required**.
2. Confirm the rep replied **publicly**, not as an internal note. Internal notes sync to OpenCX as private agent comments and are not delivered to customers.
3. If you use the legacy Private App path, confirm the webhook subscriptions are committed in HubSpot and the target URL matches the URL shown in OpenCX.
4. Check the customer's channel is still reachable (email valid, widget session open, phone number active).

### **AI stopped replying mid-thread**

<Tooltip tip="A HubSpot rep or bot posted a reply, which reassigned the conversation owner away from the configured AI user. The AI stops replying when the conversation is owned by someone else.">Likely cause</Tooltip>: the conversation owner is not the configured AI user.

**Fix:**

1. In HubSpot, open the conversation and check the **Assigned to** field.
2. Reassign to the user whose ID you configured as the **Default User ID** in OpenCX.
3. If you want the AI to keep drafting while reps own the conversation, enable [Assist Mode](https://platform.open.cx/settings/autopilot) instead.

### **Legacy webhook shows delivered in HubSpot but nothing happens**

<Tooltip tip="The webhook URL includes a signed token. If the token is stale or from a different organization, the endpoint still returns 200 OK — HubSpot's delivery dashboard will look healthy even though events aren't being processed.">Likely cause</Tooltip>: the webhook URL in HubSpot is stale or was copied from a different org.

**Fix:**

1. In OpenCX, choose **Private App (legacy)** and re-copy the webhook URL.
2. In HubSpot, open your Legacy App (**Settings → Integrations → Private Apps → Legacy Apps**) → **Webhooks** and replace the target URL.
3. Trigger a test conversation to confirm events are now processed.

### **Email reaches HubSpot, threads appear, but no OpenCX session is created**

<Tooltip tip="OpenCX calls HubSpot's owners API to verify the AI user is the conversation owner. Without crm.objects.owners.read, that call returns 403 and the inbound message is silently dropped.">Likely cause</Tooltip>: the legacy Private App is missing the `crm.objects.owners.read` scope.

**How to confirm:**

1. In HubSpot, open your Legacy App → **Monitoring** → **API Calls**.
2. Look for `GET /crm/owners/v3/A-<number>` returning **403** with `MISSING_SCOPES` in the error body. This is the exact failure.

**Fix:**

1. Legacy App → **Scopes** tab → enable `crm.objects.owners.read`, or migrate to OAuth.
2. Click **Save** / commit scope changes.
3. In OpenCX [Settings → Integrations → HubSpot](https://platform.open.cx/settings/integrations), re-save to refresh the cached client.
4. Send a fresh test email and confirm the session now appears in the [OpenCX inbox](https://platform.open.cx/inbox).

### **CRM context panel is empty**

<Tooltip tip="The CRM integration is separate from the ticketing integration and requires its own connection.">Likely cause</Tooltip>: CRM integration not connected, or the contact's email doesn't match any HubSpot record.

**Fix:**

1. The CRM context panel is configured at [**Settings → CRMs**](https://platform.open.cx/settings/crms) — this is a separate connection from Settings → Integrations.
2. Confirm the contact's email in OpenCX matches a contact in your HubSpot portal.
3. Test the CRM connection from Settings → CRMs.

<Info>
  OpenCX returns 200 OK to HubSpot webhooks immediately and processes them in the background. A successful webhook delivery in HubSpot's logs does not guarantee processing succeeded on the OpenCX side.
</Info>

## Replies not syncing: full checklist

If handoff creates a ticket but replies do nothing:

1. Confirm the ticket has a handoff comment posted on the associated HubSpot conversation (AI summary, sentiment, language, OpenCX session link).
2. Confirm HubSpot is connected via OAuth, or re-check legacy webhook subscriptions if you are still on Private App auth.
3. Confirm the reply was sent as a **public** message, not an internal note.
4. Check the customer's channel is still reachable (email valid, phone active, widget session open).
5. Confirm Autopilot or Assist Mode settings match the behavior you expect for that channel.

## Limits & timing

|                              | Value                                                                        |
| ---------------------------- | ---------------------------------------------------------------------------- |
| **Webhook processing**       | Returns 200 OK immediately, async processing                                 |
| **Event delivery**           | At-most-once — failures are logged, not retried                              |
| **OAuth tokens**             | Refreshed automatically; reconnect required if HubSpot revokes the install   |
| **OAuth webhook setup**      | Registered automatically during install                                      |
| **Ticket close delay**       | \~15 seconds before closing tickets on resolution                            |
| **Transient failure retry**  | HubSpot API calls retry up to 3 times on error                               |
| **Contact creation failure** | Non-blocking — handoff proceeds even if the HubSpot contact can't be created |
| **Email channel delay**      | \~5 seconds on email events to let concurrent workflows finish               |

<Note>
  OpenCX retries transient HubSpot API failures automatically but does not retry indefinitely past rate limits. If tickets are not appearing during a high-volume period, wait a few minutes and check again.
</Note>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Connect HubSpot" icon="plug" href="/integrations/hubspot/connect">
    Re-check OAuth, AI sender, legacy fallback.
  </Card>

  <Card title="Handoff & Sync" icon="arrow-right-arrow-left" href="/integrations/hubspot/handoff">
    Re-check handoff behavior, ticket creation, and contact sync.
  </Card>

  <Card title="Webhook Reference" icon="webhook" href="/integrations/hubspot/webhooks">
    Event payloads, skip rules, and outbound HubSpot API calls.
  </Card>

  <Card title="Human Handoff" icon="user-group" href="/handoff/introduction">
    Global handoff settings and escalation rules.
  </Card>
</CardGroup>
