Repository navigation
fix(hubspot): match dotted subscription types and gate qualified_lead on lifecycle stage - #119
Conversation
… on lifecycle stage HubSpotWebhookAdapter normalized subscriptionType with sanitize_key(), which strips the dot, so contact.propertyChange never matched and every HubSpot webhook was recorded as lead (#107). Fixing only the dot would have turned every property change into a qualified_lead. - Keep the dot when normalizing; read payload fields scalar-safely. - qualified_lead only when propertyName is lifecyclestage and propertyValue is marketingqualifiedlead or salesqualifiedlead, case-insensitive; the rule is filterable via clicutcl_hubspot_qualified_lead_rule (non-scalar or empty values from the filter are dropped; an empty propertyValue never qualifies). - Other contact.propertyChange payloads are ignored via is_ignored_event() (2xx, nothing recorded), like Calendly cancellations. - Qualified event IDs include the stage and HubSpot's eventId, so MQL then SQL, or a later re-entry, are separate events while retries dedupe. Non-qualified events keep the pre-fix ID basis so in-flight retries still dedupe. - Docs: INTEGRATIONS HubSpot mapping (incl. the behavior change for sites subscribed to property changes) and HOOKS-REFERENCE entry. Closes #107. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 46d9b7c690
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| - Every other property change is acknowledged (2xx, `ignored`) without recording an event. Before #107 the dot in | ||
| `contact.propertyChange` was stripped, so every HubSpot webhook, including every property change, was recorded as | ||
| `lead`; sites subscribed to property changes now record fewer, qualified events. |
There was a problem hiding this comment.
Update the canonical REST webhook contract
This behavior change is documented only in the integration guide: docs/reference/REST-API.md:79-100 still describes ignored webhook events only in terms of Calendly and does not tell route consumers that non-qualifying HubSpot property changes now return a successful ignored response instead of recording a lead. Update the REST route contract with the new HubSpot qualification and response behavior.
AGENTS.md reference: AGENTS.md:L58-L60
Useful? React with 👍 / 👎.
Closes #107.
Acceptance: a HubSpot
contact.propertyChangeis recorded asqualified_leadonly whenlifecyclestagemoves to MQL or SQL (filterable); other property changes are acknowledged and ignored;contact.creationstayslead.Bug:
sanitize_key()stripped the dot fromcontact.propertyChange, so the qualified branch never matched and every HubSpot webhook (every property change included) was recorded aslead.Change
qualified_leadrule:propertyName=lifecyclestage,propertyValueinmarketingqualifiedlead,salesqualifiedlead(case-insensitive), filterclicutcl_hubspot_qualified_lead_rule; non-scalar/empty filter values dropped, empty value never qualifies.is_ignored_event()(2xx, nothing recorded), same mechanism as Calendly cancellations.eventId(MQL then SQL, or re-entry, count; retries dedupe). Non-qualified IDs keep the pre-fix basis so in-flight retries still dedupe.Behavior change: sites subscribed to property changes record fewer, qualified events instead of a
leadper change. Documented in INTEGRATIONS.md.Evidence: PHPUnit 250/250 (php 8.4, E_ALL, no notices), PHPCS clean; the 5 new HubSpot tests fail on the original adapter. Independent review: 7 risks + 1 question raised, all addressed (scalar guards, filter hardening, ID stability, re-entry, docs).
node tools/qa/smoke.jspasses.🤖 Generated with Claude Code