# @kody/hubspot ## Intent Provide reusable, account-agnostic HubSpot CRM helpers so Kody agents can read contacts, companies, deals, tickets, and other CRM objects through a saved `hubspot` / `hubspot-*` OAuth integration or a private-app token — without hand-rolling REST. Mutations are previewable with `dryRun: true` and only run live after `confirm: true`. This listing is meant to be forked. After you fork, connect **your** HubSpot portal. Do not treat the live `@kody/hubspot` package storage as yours. ## What it does - List, get, or search contacts, companies, deals, and tickets - Read any other CRM object type through the generic object helpers - Preview or apply contact / company / deal / ticket writes after confirmation - Call an unwrapped HubSpot REST path through `./request` - Connect more than one HubSpot portal via `integrationName` / `account` ## Prerequisites / setup HubSpot has **no built-in Kody OAuth app**. Choose one lane: | Lane | When to use | Credential | | --- | --- | --- | | **OAuth** (recommended) | Multi-account, refresh tokens, shared helpers | Saved integration `hubspot` or `hubspot-` | | **Private app token** | Fastest for a single portal | User secret `hubspotPrivateAppToken` (or `hubspotPrivateAppToken-`) | Both lanes send `Authorization: Bearer …`. Required API hosts: **`api.hubapi.com`** and **`api.hubspot.com`**. Approve them in the account secrets UI. ### Lane A — BYO OAuth 1. Create an OAuth app from https://developers.hubspot.com/docs/apps/developer-platform/build-apps/create-an-app 2. Set the redirect URI **exactly** to `https://kody.codes/connect/oauth` 3. Enable the required CRM scopes listed below (`oauth` is required on every HubSpot OAuth app). Add `crm.objects.custom.read` as an **optional** scope if you need custom objects on Enterprise portals. 4. Connect while signed in to Kody: https://kody.codes/connect/oauth?provider=hubspot&authorizeUrl=https%3A%2F%2Fapp.hubspot.com%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fapi.hubapi.com%2Foauth%2Fv3%2Ftoken&apiBaseUrl=https%3A%2F%2Fapi.hubapi.com&scopes=oauth%20crm.objects.contacts.read%20crm.objects.contacts.write%20crm.objects.companies.read%20crm.objects.companies.write%20crm.objects.deals.read%20crm.objects.deals.write%20tickets&flow=confidential&pkce=false&allowedHosts=api.hubapi.com%2Capi.hubspot.com&dashboardUrl=https%3A%2F%2Fdevelopers.hubspot.com%2Fdocs%2Fapps%2Fdeveloper-platform%2Fbuild-apps%2Fcreate-an-app&extraAuthorizeParams=optional_scope%3Dcrm.objects.custom.read 5. Paste the HubSpot client id and client secret into the Kody wizard (never into chat). Approve hosts `api.hubapi.com` and `api.hubspot.com`. 6. Reconnect later with https://kody.codes/connect/oauth?provider=hubspot OAuth authorize URL: `https://app.hubspot.com/oauth/authorize`. Token URL: `https://api.hubapi.com/oauth/v3/token`. Flow: confidential (client secret). HubSpot scopes are **space-separated**. To connect a second portal, change `provider` (for example `provider=hubspot-work`) and pass `integrationName: 'hubspot-work'` on every call. ### Lane B — Private app token 1. Create a private app from https://developers.hubspot.com/docs/apps/legacy-apps/private-apps/overview (Development → Legacy apps) and grant the same CRM scopes. 2. Save the access token (do not paste the value in chat): https://kody.codes/account/secrets/new?name=hubspotPrivateAppToken&description=HubSpot%20private%20app%20access%20token&allowedHosts=api.hubapi.com%2Capi.hubspot.com&scope=user For a second portal/token, use a distinct secret name such as `hubspotPrivateAppToken-work` and pass `secretName: 'hubspotPrivateAppToken-work'` (or `account: 'work'`, which resolves to `hubspot-work` / `hubspotPrivateAppToken-work`). ### Scopes | Scope | Needed for | | --- | --- | | `oauth` | Required on every HubSpot OAuth app; `./account`, `./smoke-test` | | `crm.objects.contacts.read` | `./list-contacts`, `./get-contact`, `./search-contacts` | | `crm.objects.contacts.write` | `./create-contact`, `./update-contact` | | `crm.objects.companies.read` | `./list-companies`, `./get-company`, `./search-companies` | | `crm.objects.companies.write` | `./create-company`, `./update-company` | | `crm.objects.deals.read` | `./list-deals`, `./get-deal`, `./search-deals` | | `crm.objects.deals.write` | `./create-deal`, `./update-deal` | | `tickets` | Ticket reads and writes | | `crm.objects.custom.read` | Generic custom-object reads (Enterprise, optional) | If HubSpot returns 401/403 or a missing-scope error, helpers throw a message that names the missing scope and the next setup URL (reconnect OAuth with that scope, or save a private-app token). Agents: see [`AGENTS.md`](./AGENTS.md) for import paths, smoke checks, and mutation guards. ## Done when - OAuth `hubspot` is connected or `hubspotPrivateAppToken` is saved; hosts `api.hubapi.com` and `api.hubspot.com` are approved - Smoke test returns `ok: true` (live portal id when credentials exist; no email) - Mutating helpers refuse unless `confirm: true`; `dryRun: true` never calls HubSpot ## Branding The community icon is HubSpot's official orange sprocket (`#FF7A59`) from the [HubSpot](https://www.hubspot.com/) brand mark as published in Simple Icons. Paths are unmodified. HubSpot® is a trademark of HubSpot, Inc. This package is not affiliated with or endorsed by HubSpot, Inc. Share this listing at https://kody.codes/@kody/hubspot ## Docs - [HubSpot CRM object APIs](https://developers.hubspot.com/docs/guides/crm/using-object-apis) - [Contacts](https://developers.hubspot.com/docs/api-reference/latest/crm/objects/contacts/guide) - [OAuth](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/authentication/oauth/working-with-oauth) - [Scopes](https://developers.hubspot.com/docs/apps/developer-platform/build-apps/authentication/scopes) - [Private apps](https://developers.hubspot.com/docs/apps/legacy-apps/private-apps/overview)