> ## 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.

# Webhook Reference

> HubSpot events OpenCX receives through the OAuth app and the HubSpot API calls OpenCX makes on handoff, reply, and close.

Inbound events HubSpot sends to OpenCX through the HubSpot app, plus the HubSpot API calls OpenCX makes back out. Shapes match the current implementation.

<Info>
  OAuth installs configure webhook delivery automatically. The legacy Private App path still uses an organization-specific webhook URL you copy from OpenCX.
</Info>

<Tabs>
  <Tab title="Inbound (HubSpot to OpenCX)">
    HubSpot POSTs an array of events to OpenCX. OpenCX returns `200 OK` immediately and processes in the background.

    <CodeGroup>
      ```json Envelope theme={"dark"}
      [
        {
          "eventId": 1234567890,
          "subscriptionId": 987654,
          "portalId": 12345678,
          "appId": 2345678,
          "occurredAt": 1713790000000,
          "subscriptionType": "conversation.newMessage",
          "attemptNumber": 0,
          "objectId": "9598272090",
          "changeSource": "CRM",

          "messageId": "abc-123",
          "messageType": "MESSAGE",
          "changeFlag": "NEW_MESSAGE",

          "propertyName": "hs_pipeline_stage",
          "propertyValue": "2"
        }
      ]
      ```
    </CodeGroup>

    <ParamField path="subscriptionType" type="string" required>
      Event type. OpenCX acts on supported HubSpot conversation, ticket, and note events. Everything else is ignored.
    </ParamField>

    <ParamField path="objectId" type="string" required>
      Thread ID (conversation events) or ticket ID (ticket events).
    </ParamField>

    <ParamField path="messageId" type="string">
      On conversation events, OpenCX re-fetches the message via `GET /conversations/v3/conversations/threads/{threadId}/messages/{messageId}` — the webhook envelope does **not** carry the message body.
    </ParamField>

    <ParamField path="messageType" type="'MESSAGE' | 'COMMENT'">
      `COMMENT` events are skipped (internal notes aren't customer messages).
    </ParamField>

    <ParamField path="propertyName / propertyValue" type="string">
      Set on `ticket.propertyChange`. Empty values are ignored.
    </ParamField>

    <AccordionGroup>
      <Accordion title="conversation.newMessage" icon="message">
        Re-fetches the message from HubSpot, then routes it through the AI if it passes filters.

        **Skipped when:** the sender is automated, a bot, or OpenCX's own AI marker. HubSpot agent replies and internal notes are stored on the OpenCX session instead of being sent back to the AI.

        **Email only:** a 5-second delay lets other OpenCX workflows (drafting, signatures) finish first.

        **Dedup key:** message ID, scoped to the OpenCX organization.
      </Accordion>

      <Accordion title="conversation.propertyChange" icon="user-gear">
        Handles ownership changes. If the conversation is assigned away from the configured AI user, OpenCX marks the session as handed off unless Assist Mode is enabled.
      </Accordion>

      <Accordion title="ticket.propertyChange" icon="pen-to-square">
        Syncs the changed property onto the associated OpenCX session's custom data.

        **Skipped when:** ticketing is disabled in settings, or `propertyValue` is null / empty string.
      </Accordion>

      <Accordion title="object.creation for help-desk notes" icon="note-sticky">
        Mirrors HubSpot help-desk notes attached to a synced ticket into the OpenCX timeline as internal agent comments.
      </Accordion>
    </AccordionGroup>
  </Tab>

  <Tab title="Outbound (OpenCX to HubSpot)">
    On handoff and during the session lifecycle, OpenCX writes back to HubSpot through the OAuth connection.

    <AccordionGroup>
      <Accordion title="Find or create contact" icon="user">
        Looks up the contact by email before creating a ticket. Creates one if missing.

        ```http theme={"dark"}
        POST /crm/v3/objects/contacts/search
        POST /crm/v3/objects/contacts
        ```
      </Accordion>

      <Accordion title="Create handoff ticket" icon="ticket">
        Opens a ticket associated with the contact. Subject, content (conversation summary), pipeline/stage, priority, owner, and any session `custom_data` / `editable_custom_data` are written as ticket properties.

        ```http theme={"dark"}
        POST /crm/v3/objects/tickets
        ```
      </Accordion>

      <Accordion title="Post handoff comment" icon="clipboard-list">
        Posts an internal `COMMENT` on the HubSpot conversation thread with the AI summary, sentiment, language, and a link back to the OpenCX session.

        ```http theme={"dark"}
        POST /conversations/v3/conversations/threads/{threadId}/messages
        ```
      </Accordion>

      <Accordion title="Reply to customer" icon="reply">
        AI and agent-assist drafts are posted as public `MESSAGE` on the same conversation thread — email replies get the matching domain signature appended.

        ```http theme={"dark"}
        POST /conversations/v3/conversations/threads/{threadId}/messages
        ```
      </Accordion>

      <Accordion title="Close ticket on resolution" icon="circle-check">
        When the OpenCX session resolves, the associated ticket is moved to the pipeline's closed stage. Delayed \~15s to stay within rate limits.

        ```http theme={"dark"}
        PATCH /crm/v3/objects/tickets/{ticketId}
        ```
      </Accordion>
    </AccordionGroup>

    <Note>
      Transient HubSpot API errors retry up to 3 times. Contact creation failures are non-blocking — handoff still proceeds. OpenCX only writes properties that exist in your HubSpot schema; unknown fields are skipped silently.
    </Note>
  </Tab>
</Tabs>

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Connect HubSpot" icon="plug" href="/integrations/hubspot/connect">
    OAuth setup, AI sender, workflow actions.
  </Card>

  <Card title="Handoff & Sync" icon="arrow-right-arrow-left" href="/integrations/hubspot/handoff">
    Day-to-day handoff flow, rep replies, CRM context, contact sync.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/integrations/hubspot/troubleshooting">
    Connection, webhook, ticket, and reply sync debugging.
  </Card>

  <Card title="HubSpot Overview" icon="hubspot" href="/integrations/hubspot/overview">
    Capabilities and supported channels.
  </Card>
</CardGroup>
