HubSpot Integration — Permissions and Scopes
FlowState requests 11 HubSpot OAuth scopes. This page explains each scope, why it is needed, and what FlowState does and does not do with the access it grants.
Scopes requested
oauth
Why it is needed: The base scope HubSpot requires for any OAuth app installation. It grants no data access on its own.
crm.objects.deals.read
Why it is needed: FlowState reads your deal records to build the pipeline snapshot that feeds AI analysis, the dashboard, and APN opportunity payloads. Without this scope, no pipeline data can be fetched.
What FlowState does with this access:
- Reads deal properties (name, stage, close date, amount, owner, and all custom properties including the 10 APN properties).
- Reads deal association metadata to find contacts linked to each deal.
What FlowState never does with this access:
- Reads deals from HubSpot portals not linked to your FlowState tenant.
- Stores deal data beyond the retention window of the pipeline snapshot (1 day) or deal AI summary (8 days), after which it is purged.
crm.objects.deals.write
Why it is needed: FlowState writes back to the 10 APN custom properties on each deal to reflect the current synchronisation status (apn_sync_status, apn_opportunity_id, and related fields). This allows your sales team to see APN sync state directly in HubSpot.
What FlowState does with this access:
- Updates only the 10 properties in the
flowstate_apnproperty group on deals that haveapn_sync_with_aws_enabled = true.
What FlowState never does with this access:
- Modifies core deal properties such as
dealname,dealstage,closedate,amount, orhubspot_owner_id. - Deletes deals.
- Creates deals as part of a live tenant’s pipeline sync.
- Modifies deals in pipelines that have no APN-enabled deals.
crm.objects.owners.read
Why it is needed: The deal analyzer resolves the HubSpot owner ID on each deal to a name, so pipeline summaries and Slack/email alerts can say who owns a deal instead of showing a raw ID.
What FlowState does with this access:
- Reads owner records (name, email) for owners assigned to deals in the connected portal.
What FlowState never does with this access:
- Creates, modifies, or deassigns owners.
crm.objects.appointments.read
Why it is needed: Win/loss analysis reads meetings associated with a deal (alongside notes, emails, calls, and tasks) as one of the activity signals used to detect stalled deals and summarise deal history.
What FlowState does with this access:
- Reads appointment/meeting records associated with deals for activity-recency and win/loss analysis.
What FlowState never does with this access:
- Reads appointments not associated with a deal, or modifies/creates appointments.
crm.schemas.deals.read
Why it is needed: Before creating or updating a property, the provisioner checks whether it (or the flowstate_apn property group) already exists, so it never has to guess and can safely no-op.
What FlowState does with this access:
- Reads the deal property schema and the list of existing property groups.
What FlowState never does with this access:
- Reads schemas for object types other than deals.
crm.schemas.deals.write
Why it is needed: FlowState creates the flowstate_apn property group and the 10 APN custom properties when you run the provisioner (Settings → Integrations → HubSpot → Provision properties, or the provision_hubspot_properties MCP tool/action). Without this scope, the provisioner cannot create the schema objects.
What FlowState does with this access:
- Creates or updates (idempotently) one property group (
flowstate_apn) and 10 deal properties under that group.
What FlowState never does with this access:
- Modifies or deletes properties not in the
flowstate_apngroup. - Changes the schema of existing properties your team has defined.
crm.objects.contacts.read
Why it is needed: APN opportunities require at least one contact record. FlowState reads contacts associated with deals to populate the Customer.Contacts[] field in the APN opportunity payload.
What FlowState does with this access:
- Reads the first name, last name, and job title of contacts associated with APN-enabled deals to construct APN payloads.
What FlowState never does with this access:
- Stores contact personal data in FlowState databases beyond the in-memory lifetime of a single pipeline worker invocation.
- Reads contacts not associated with a deal.
- Reads marketing contact properties (email opt-in status, lifecycle stage, form submissions, page views).
crm.objects.contacts.write
Why it is needed: When AWS adds members to your opportunity team (account owner, sales rep, partner sales manager, ISV success manager), FlowState mirrors each of them into HubSpot as a contact and associates it with the deal, so the AWS people working the co-sell are visible in HubSpot.
What FlowState does with this access:
- Upserts a contact by email (creates if absent, updates if present) for each AWS opportunity team member, setting
email,firstname,lastname, andjobtitle. - Associates each such contact with the corresponding deal (default contact-to-deal association).
What FlowState never does with this access:
- Creates or edits contacts unrelated to an AWS opportunity team.
- Writes marketing contact properties or sets lifecycle/opt-in state.
- Deletes contacts.
crm.objects.companies.read
Why it is needed: apn_client_country is no longer a HubSpot deal property — FlowState reads the deal’s associated company (name, website, country) live to fill the opportunity’s country field, and it’s the only source for that value. apn_client_industry is also no longer a HubSpot deal property, and the company’s industry is one of the values FlowState checks while filling it in automatically — so it rests on this scope too. The company’s industry is only used when it already matches one of AWS’s recognized industries, since HubSpot’s and AWS’s industry lists don’t match one-for-one.
What FlowState does with this access:
- Reads the company record associated with an APN-enabled deal (name, website, country, industry), read-only.
What FlowState never does with this access:
- Reads companies not associated with an APN-enabled deal.
crm.objects.companies.write
Why it is needed: This scope is requested but not currently used by any client-facing feature — it is reserved for future use.
What FlowState does with this access:
- Nothing, in normal operation — no code path creates or edits companies for a live tenant today.
What FlowState never does with this access:
- Creates or edits companies as part of a live tenant’s pipeline sync or APN write.
Webhooks
FlowState’s HubSpot app subscribes to deal-creation, deal-deletion, and a fixed set of deal property-change events at the app level (covering every portal that has authorized FlowState) — this subscription is configured in the app’s manifest, not gated by an OAuth scope. It is what makes APN sync fire within seconds of a relevant deal edit, instead of waiting for the next daily pipeline fetch. See Overview for exactly which properties are subscribed and which of those actually trigger a sync.
Token storage and security
- OAuth refresh tokens are stored encrypted at rest, scoped to your tenant, and access to them is restricted to your tenant.
- Access tokens are cached for 5 minutes. HubSpot’s own access tokens are valid for roughly 30 minutes; FlowState’s 5-minute cache is intentionally shorter so a revoked or rotated token is never used for long. Tokens are never written to application logs.
- The refresh token can be revoked at any time from HubSpot: Settings → Integrations → Connected apps → FlowState → Actions → Uninstall. FlowState detects this only reactively, the next time it tries to refresh the token, and the failure is logged. No status field is updated and no email is sent — the integration still shows
connectedin FlowState until you disconnect it yourself or a HubSpot API call surfaces the failure (for example, via thetest_hubspotMCP tool or the pipeline fetch failing).