Running syncs
There are three ways data moves from Stripe into HubSpot. Together they keep your portal current without you babysitting it.
| Mode | Trigger | What it does |
|---|---|---|
| Backfill | You start it | Walks all existing Stripe data and upserts it into HubSpot. |
| Real-time | Stripe webhooks | A single inbound Stripe event syncs one record as it changes. |
| Reconcile | Nightly (and on demand) | Re-upserts everything and detects deletions. |
Real-time syncing depends on inbound Stripe webhooks — see Webhooks. Everything below routes records using the rules in What syncs to what.
Starting a backfill or reconcile #
Open the Sync screen:
- Backfill — click Backfill customers to walk customers (and the companies/contacts, subscriptions, and invoices that hang off them).
- Reconcile — click Run full reconcile to re-sync everything and archive records whose Stripe source is gone.
- Preview counts shows how many records a full backfill would touch, and the Dry-run preview maps the first few Stripe records and shows the exact HubSpot properties that would be written — without touching HubSpot. Use it to sanity-check field rules and routing first.
Re-running is safe: records update in place rather than duplicating, because the local id mapping is the source of truth.
Via the API #
Both start the same way — POST /v1/sync-runs:
POST /v1/sync-runs
{ "type": "backfill", "object": "customer" }
POST /v1/sync-runs
{ "type": "reconcile" }
object is required for a backfill and omitted for a reconcile (it covers all
reconcilable objects). Related endpoints:
POST /v1/sync-runs/preview # dry-run a few records
POST /v1/sync-runs/plan # count what a backfill would touch
GET /v1/sync-runs # list recent runs
GET /v1/sync-runs/:id # one run
GET /v1/sync-runs/:id/records # per-record results
The async model: 202 → running → worker #
Sync runs don’t execute in the request. POST /v1/sync-runs creates the run,
enqueues a background job, and returns 202 with the run already in running
status. A polling worker then claims the job and executes it. The Sync screen
returns immediately, so poll GET /v1/sync-runs/:id (or refresh the screen) to
watch progress.
Reading runs and per-record results #
Sync history lists recent runs with their type, object, status, and created / updated / failed counts. Click a run to expand its per-record results — one row per record with its Stripe ID, HubSpot ID, action, and any message.
Run statuses:
- running — created and enqueued, or actively executing.
- completed — the worker finished.
- failed — the run errored out; the
errormessage explains why.
Per-record actions:
| Action | Meaning |
|---|---|
create |
A new HubSpot record was created. |
update |
An existing record was updated (matched via id mapping, search, or natural key). |
skip |
Nothing written — e.g. a rollup whose company isn’t synced yet, or a record archived by deletion detection. |
error |
That record failed; the message has the detail. Other records still proceed. |
Deletion detection (reconcile) #
Reconcile can do more than re-upsert, but only when you ask it to. What happens to a HubSpot record whose Stripe source has disappeared is controlled by the per-object When deleted in Stripe policy (see Sync behavior):
- Keep (the default) — nothing is pruned. Reconcile skips the deletion scan entirely and leaves the HubSpot record and its mapping untouched.
- Archive — for customers, products, and subscriptions, reconcile tracks
which Stripe ids it saw in the live list, then archives any HubSpot record
that’s still in the local id mapping but no longer in Stripe. Those show up as
skiprecords with the message archived — no longer in Stripe. - Mark — instead of archiving, the record is tombstoned in place. Those show
up as
skiprecords with the message marked deleted — no longer in Stripe.
Backfill and real-time syncs never delete anything — only reconcile does, and only when the policy is set to Archive or Mark.
The nightly schedule #
A reconcile runs automatically every night at 03:00 for every organization with both Stripe and HubSpot connected (and not suspended). You don’t need to schedule anything. The nightly run and the on-demand Run full reconcile button aren’t identical, though: the nightly run is an incremental catch-up that replays Stripe events since the last cursor and skips the full prune scan, while the button forces a full reconcile — re-upserting everything and running the deletion scan (subject to your per-object delete policy).
Where to next #
- Webhooks — wire up the inbound Stripe events that power real-time sync.
- What syncs to what — how each record is routed and matched.