Skip to main content
The HubSpot template (apps/hubspot-clone, name hubspot) is an API-only clone of the HubSpot CRM API: a NestJS backend on Postgres that models the CRM the way HubSpot does — every object (contacts, companies, deals, tickets) is a generic record carrying a free-form properties map, wired together by an associations graph, with properties metadata, pipelines + stages, and owners on the side. It’s faithful at the path + wire-format level: HubSpot’s CRM API is REST with stable routes, so the clone matches GET /crm/v3/objects/contacts path-for-path, uses HubSpot’s { results, paging: { next: { after } } } collection envelope, the { total, results } search envelope, the { status, message, correlationId, category } error envelope, and returns numeric-string ids. Associations are on the v4 surface (/crm/v4/…), and requests are metered by a HubSpot-accurate rate limiter (see below).

What’s inside

Modes

This is an API-only template — there is no frontend.

Authentication — private-app tokens

Real HubSpot apps authenticate with a private-app access token (pat-na1-…) in the Authorization header. The clone mirrors that: the token is the canonical credential, sha256-hashed and resolved to its owning portal (tenant). Every spin applies the acme fixture, which seeds a deterministic token:
Use it as a bearer token against the REST API — no signup/login step:
The clone also implements HubSpot’s real OAuth token-exchange route, POST /api/oauth/v1/token, and a parity POST /api/auth/login (admin@acme.test / password123) that issues a portal-scoped JWT so the web/CLI path works — HubSpot itself has no email/password login route. Mint additional private-app tokens via POST /api/account-info/v3/api-keys (plaintext shown once).

Rate limiting

Requests pass through a HubSpot-accurate limiter (a global interceptor behind the auth guard). Successful responses carry the exact five HubSpot headers:
Tiers match HubSpot’s published limits: private-app 100 / 190 / 250 requests per 10 s (Free·Starter / Pro·Enterprise / API-add-on), public OAuth 110 / 10 s, with daily caps of 250k / 625k / 1M. Tripping the window returns a real 429 whose body uses HubSpot’s documented policyName values (TEN_SECONDLY_ROLLING, DAILY):

Seeding

AI seeding generates contacts, companies, and deals (the template’s declared entities) through real CRM v3 create calls. See Seeding.

The object model — read this before pointing an agent at it

Everything in HubSpot’s CRM is a record with a property bag. The clone keeps that shape exactly:
Beyond plain CRUD, objects also expose batch/{read,create,update,archive,upsert}, merge, and gdpr-delete. Associations are the full v4 surface — default and labeled PUT (the label body array is honored), DELETE, the four batch/{create,read,archive,labels/archive} endpoints, and GET …/labels. Properties carry CRUD plus batch/{read,create,archive} and property groups CRUD; pipelines and their stages have full read and write paths.

Fidelity

The template ships an API_PARITY.md re-audited 2026-06-28 against HubSpot’s live docs. Scope is the CRM resource groups the clone targets (objects, associations, properties, pipelines, owners) plus the OAuth token endpoint — 55 endpoints: That’s 91% (50/55) on both capability and shape — they’re equal because every implemented endpoint is also shape-exact. The 5 missing are narrow: association label-definition writes (POST / PUT / DELETE …/associations/{ft}/{tt}/labels) and the two property-group batch endpoints. Seven extra routes are clone-local control-plane (/auth/*, /account-info/v3/api-keys, /health); an eighth is a deprecated v3 association-read alias retained for back-compat. On the strict dimensions the audit grades: id-format passes (numeric-string record ids, plus HubSpot’s own mixed string-id / numeric-toObjectId convention inside association payloads) and rate-limits passes (the limiter above). Webhooks/events and an MCP server are unimplemented, so those two dimensions are N/A — the clone never claims to emit events or expose MCP. Whole HubSpot families outside the core — engagements/timeline, workflows, marketing, CMS, conversations, files, quotes, custom object schemas — are unimplemented by design. See apps/hubspot-clone/API_PARITY.md for the per-endpoint breakdown.
The verify command will fold this kind of live fidelity scoring into the CLI. Until then, API_PARITY.md and the /verify-api workflow are how fidelity is tracked.

Inspect a running clone

The schema (crm_objects, property_defs, property_groups, pipelines, pipeline_stages, associations, owners, …) comes straight from 001_initial_schema.sql — read it to know what’s queryable.