Recurse docs / 21

HubSpot tools and approvals

Connect your own HubSpot account to read one selected deal. The meeting tool can also apply an exact, separately authorized next step, note and task. These are deterministic Python tools: the caller's LLM interprets the meeting outside the tool.

Connection and write approval currently require an account-owner API client. The website's normal agent setup does not create a HubSpot connection or meeting authorization. ChatGPT or another LLM harness can prepare the reviewed proposal, but must pause for an owner-side handoff when it cannot complete that flow. A linked Tools key, a chat approval and a spending cap do not grant CRM write authority.

Connect the selected account

Use an authenticated owner application with the owner's existing Nhost account session. Keep that session and the provider credential in its protected credential handling, outside chat, tool inputs, source, logs and shell arguments. The account owner chooses the HubSpot account and grants the required scopes. This guide does not grant access.

  1. Store the HubSpot token through POST /v1/runtime-secrets on the selected Control origin. Its JSON fields are name, value and idempotency_key. The response contains metadata, including secret_id; it does not return the value. Use a distinct secret name for each selected account.
  2. On the matching Tools origin, send POST /v1/provider-connections with exactly provider: "hubspot", the expected numeric external_account_id as a string, a label and the owned secret_id. Do not include the token. The service checks the actual HubSpot portal ID and pins the encrypted credential version.
  3. Retain the returned connection ID and verified account identity. GET /v1/provider-connections lists owned metadata; DELETE /v1/provider-connections/{id} revokes the selected connection. Its credential-available flag does not prove upstream permission or freshness.

Registration needs account-info.security.read; the selected deal read needs crm.objects.deals.read. The meeting workflow also needs crm.objects.deals.write and crm.objects.owners.read. Have the owner verify HubSpot's current permission requirements before granting access. Rotation requires a newly verified credential version and new approval; completed action identities remain retained.

Use matching production or TEST origins throughout. Discover the current service origins through the connected client's configuration; do not send TEST credentials to production. No connection-management or authorization operation belongs inside the isolated Python tool.

Read one deal

Inspect recurse.hubspot.deal.read through apis_get before building. Its input is exactly connection_id (lowercase UUID) and deal_id (numeric string). The fixed read returns these properties:

dealname, hs_next_step, amount, closedate, dealstage, hubspot_owner_id, hs_lastmodifieddate, deal_currency_code.

Preserve actual string/null values. The read does not discover contacts, company domains, associations or a pipeline. Ask the owner for any additional identity or source material explicitly. Python cannot choose an arbitrary provider route or obtain the provider credential.

Preview the meeting

Download the source project, which includes meeting_crm.py, tools.yaml, pyproject.toml and uv.lock. The synthetic review example shows the complete shape; replace its placeholder IDs and use the actual current deal values. It grants no approval.

Create and upload the ordinary private source archive using a capable harness and the private Tools flow. Inspect the current quote and obtain an accepted total spending cap before chargeable preparation or calls. The native HubSpot provider basis is zero; preparation and execution compute remain chargeable at 4×.

Call preview_meeting with {"review": review} and a stable request key. The review contains:

  • connection_id, verified external_account_id, exact deal_id, stable meeting_id and UTC meeting_at.
  • expected: exactly the current hs_next_step, amount, deal_currency_code, closedate, hubspot_owner_id and dealstage.
  • transcript: unique timestamp/speaker locations and their text; seller_owner_id: an explicitly reviewed active owner mapping.
  • next_step: value and evidence; note: text and evidence.
  • task: subject, owner_id matching the seller, explicit UTC due_at, reviewed due_time_basis and evidence.

Each evidence item has timestamp, speaker and an exact quote at that transcript location. Quotation matching proves presence. The owner still reviews meaning, identity, commitments, seller mapping and the chosen due time. Dates cannot be relative or precede the meeting. Stop on missing evidence or conflicts; do not silently rewrite the proposal.

Preview reads the exact deal and returns old/new values, evidence and conflicts. It creates neither a mutation nor an authorization.

Authorize and apply

Show the entire preview to the owner. Through the separate owner application/session, submit POST /v1/hubspot-meeting-authorizations on the matching Tools origin. Its body is exactly request_id (UUID), expires_at (UTC ending in Z, at most one hour ahead) and the exact review. A stable identical request replays the retained approval; changed content or expiry conflicts. An application holding the owner session has this authority; the API does not attest a physical human click.

Retain the returned authorization ID. The owner can inspect GET /v1/hubspot-meeting-authorizations/{id} and revoke it with DELETE at that URL. Revoked/expired approvals remain auditable and cannot be reactivated by replay. Linked Tools credentials cannot create, inspect or revoke these approvals.

Call apply_meeting with only {"authorization_id": "RETURNED_UUID"}, a stable Tools request key and the accepted cap. It calls, in order:

  1. recurse.hubspot.deal.next-step.update: only the approved hs_next_step.
  2. recurse.hubspot.note.create: the approved note associated with the exact deal.
  3. recurse.hubspot.task.create: the approved task, active owner, explicit due time and exact deal association.

Each native write accepts only the authorization ID. Source cannot replace its target or content. The service rechecks authority and current protected values before sending; it preserves amount, currency, close date, owner and stage. The read-before-write check is not an atomic compare-and-swap. Stop on conflict and obtain fresh owner review.

Recover partial or uncertain work

Inspect the durable receipt until execution and billing are terminal. Report complete, partial, rejected, conflict or unresolved status, provider IDs, failures and unattempted actions. Closed billing is separate from CRM success.

Completed actions replay their retained IDs without another provider request. An uncertain transmitted action must not be blindly retried. After its original call ends, the owner can inspect GET /v1/hubspot-meeting-authorizations/{id}/actions, inspect the actual provider records and submit POST /v1/hubspot-meeting-authorizations/{id}/reconcile with exactly action (next_step, note or task) and the numeric provider_record_id as a string.

Reconciliation uses a fixed read to check exact approved content and association. It does not resend a mutation. Missing evidence is not proof that another creation is safe. A mismatch or provider read failure leaves the action unresolved. Do not claim provider-wide exactly-once behavior.

Validation and manual UAT

The meeting project passed synthetic HubSpot TEST UAT through the SDK and ordinary stdio MCP: preview, approved next-step/note/task application, unchanged protected fields, replay and partial recovery were checked. Production rejection guards were checked without CRM effects. A separate ChatGPT web-UI acceptance test has not been performed. Other catalog combinations are specifications unless their page states otherwise.

To repeat UAT, use a dedicated TEST account, a synthetic target and a second deal for the same company. Run preview, review and authorize the exact proposal, then apply. Verify only the intended next step changed, exactly one note/task has the correct deal/owner/due time, protected fields and the second deal stayed unchanged, and replay returns the same IDs without extra records. Record actual receipts and provider evidence separately from this illustrative procedure.