HubSpot
What the HubSpot connector reads, with which permissions, what it never touches, how it syncs, and the facts it produces.
Last changed Markdown versionllms.txt
Source module: app/connectors/hubspot.py. Kind: both (declared; claims are not produced yet — see limitations). Display name: "HubSpot".
Purpose
Reads ticket pipeline-stage history, meetings and deals as facts so that resolution, meeting-booked and lead-qualified outcomes can be checked against HubSpot. Intended to also ingest Breeze Customer Agent resolutions as claims when an export is available.
Auth and scopes
| Item | Value |
|---|---|
| Method | Access token: a service key (Settings → Integrations → Service keys, the replacement for private apps on newer accounts) or a private app token, with read scopes only, sent as Authorization: Bearer, against https://api.hubapi.com |
| Credentials stored (encrypted) | access_token; optional base_url |
| Least-privilege scopes | tickets (read), crm.objects.deals.read, crm.objects.meetings.read, crm.objects.contacts.read (declared for email hashing; see limitations). No write scopes. |
| Connection test | GET /crm/v3/objects/tickets?limit=1 |
| Non-secret config | none |
Fields pulled and why
| Object / endpoint | Properties | Used for |
|---|---|---|
POST /crm/v3/objects/tickets/search (filter hs_lastmodifieddate GT since) |
hs_pipeline_stage, createdate, hs_lastmodifieddate, closed_date, hs_ticket_priority, source_type |
Subject id, watermark, channel |
GET /crm/v3/objects/tickets/{id}?propertiesWithHistory=hs_pipeline_stage |
stage history (value, timestamp) |
Status-change and reopen facts |
POST /crm/v3/objects/meetings/search |
hs_meeting_outcome, hs_meeting_start_time, hs_timestamp |
Meeting facts |
POST /crm/v3/objects/deals/search |
dealstage, closedate, hs_lastmodifieddate |
Opportunity-stage facts |
Ticket subject/content, notes, emails, calls, contact names and any other properties are not requested.
What is hashed / never stored
- No raw identifiers are stored. The connector declares the contacts read scope for hashing contact emails, but the current implementation does not fetch contact records; facts from HubSpot therefore carry no
customer_hidand link to other sources only by exact subject id. - The access token is stored only as ciphertext.
Incremental sync and watermark
- All three searches filter on
hs_lastmodifieddate > <watermark in epoch ms>(0 on first sync), page size 100, cursor viapaging.next.after. - One additional request per ticket fetches the pipeline-stage history.
- Watermark = maximum ticket
hs_lastmodifieddate(meetings and deals do not advance it). - Upserts are idempotent.
Rate-limit handling
Shared HttpClient (Retry-After, exponential backoff on 429/5xx, 6 attempts, immediate reauth failure on 401/403). HubSpot private apps have per-10-second and daily request limits; the per-ticket history request dominates.
Fact types produced
fact_type |
Subject / kind | When | Attributes | raw_ref |
|---|---|---|---|---|
status_change |
hubspot_ticket_{id} / ticket |
Each pipeline-stage history entry, in timestamp order | from (previous stage or null), to (stage id or name, lower-cased), actor: "agent", channel: <source_type> |
hubspot:ticket:{id}:stage:{i} |
reopen |
hubspot_ticket_{id} / ticket |
Stage moves from closed or 4 (default closed stage id) to another stage |
— | hubspot:ticket:{id}:reopen:{i} |
meeting_event |
hubspot_meeting_{id} / customer |
Each meeting | status: occurred when hs_meeting_outcome == completed, otherwise the outcome value, or scheduled |
hubspot:meeting:{id} |
opportunity_stage |
hubspot_deal_{id} / opportunity |
Each deal (current stage) | stage: <dealstage lower-cased> |
hubspot:deal:{id}:{dealstage} |
Claims produced
None yet. Breeze Customer Agent resolutions must currently be uploaded via CSV mapped to hubspot_breeze_customer_agent_resolution, with subject_id values of the form hubspot_ticket_{id} so they match the facts above.
Subject id format
hubspot_ticket_{ticketId}, hubspot_meeting_{meetingId}, hubspot_deal_{dealId}.
Known limitations
- No claims. The connector is declared
kind = both, but Breeze resolution export ingestion is not implemented. - No
customer_hid. Contact emails are not fetched, so HubSpot facts cannot be linked to other sources by hashed email; they link by exact subject id only. - Pipeline stage values are HubSpot stage ids unless the portal uses labels; contracts that test
record_status_in: [closed, …]need the closed stage to be literallyclosedor4. Map stages through a CSV upload if the portal uses custom ids. - Meeting facts are keyed by meeting id, not by the associated contact or ticket; associations are not fetched, so a meeting cannot be linked to a lead claim without an explicit subject link.
- Deal stage facts record the current stage at sync time, not the full stage history; the
occurred_atis the deal'shs_lastmodifieddate. - No
customer_message,human_reply,escalationorcsat_responsefacts.