Skip to main content
The integration is bound by three independent rate limits — HubSpot’s API limits on outbound calls Chert makes into your account, Chert’s own per-project send capacity, and HubSpot’s webhook delivery guarantees.

Before You Begin

ConceptDefinition
HubSpot daily limitThe 24-hour rolling cap on API calls to your HubSpot account, set by your HubSpot edition.
HubSpot burst limitThe 10-second-window cap that protects HubSpot from spikes; usually 100 to 190 calls per 10 seconds depending on edition.
Chert daily capThe per-project per-day cap on first-touch sends, configured in Settings → Auto-dial.
Idempotency keyA stable token that lets a retry of the same logical operation return the prior result instead of re-sending.

HubSpot API Calls Made by Chert

Each integration surface consumes a known number of HubSpot API calls.
SurfacePer eventEndpoints
Sidebar card load1GET /crm/v3/objects/contacts/{id}
Sidebar card send1GET /crm/v3/objects/contacts/{id}
Workflow custom action0The action callback delivers the data; Chert does not read back.
Contact creation auto-send1GET /crm/v3/objects/contacts/{id}
Reply push2POST /crm/v3/objects/communications, PUT /crm/v4/objects/communications/{id}/associations/default/contacts/{contactId}
OAuth token refresh1POST /oauth/v1/token (does not count against CRM daily limit)
A typical operator who opens 50 contact records, sends from 10 of them, and receives 10 replies consumes roughly 80 HubSpot API calls per day.

Chert Send Capacity

LimitDefaultConfigurable
Project daily capSet per project during onboardingYes, in the Chert console
Per-phone-line minimum gap10 minutes between first-touch sendsNo
Per-phone-line first-touch cap30 sends per phone line per dayNo
Sending windowPer project, in the project’s timezoneYes
Auto-dial enabledOff until configuredYes
When the daily cap is reached, the workflow action returns ok = false with error = "daily cap reached". The sidebar card returns the same shape and renders an inline notice. The contact creation webhook logs the event with status failed and skips the send. Every HubSpot-facing failure body now also carries a numeric code, a generic human message, a retryable boolean, and a trace_id alongside ok: false / error. The numeric code follows the shared Messaging API error scheme. All of these routes return HTTP 200 for logical failures — see Retry Semantics below.

Retry Semantics

From HubSpot to Chert

All four HubSpot-facing routes return HTTP 200 for every logical failure — including signature verification failures — so HubSpot’s retry-on-non-2xx behavior never fires on a per-event error. The failure is signalled in the body (ok: false with code / message / retryable / trace_id, or outputFields.ok: false for the workflow action). Branch on the body, not the HTTP status.
SurfaceHubSpot retry behaviorChert response
app.uninstalled webhookRetries on 5xx with exponential backoff, up to roughly 24 hours.Always 200 OK. Success and logical failures (including signature rejection) both return 200 with ok reflecting the outcome.
contact.creation webhookRetries on 5xx; one delivery per retryable failure.Always 200 OK to discourage retries on per-event failures. Per-event errors are logged with status failed and returned in the body with ok: false + code.
Workflow custom action (/send)Retries on 5xx; the workflow execution itself stalls until the action returns.Always 200 OK with outputFields.ok reflecting the actual outcome. The workflow author branches on ok / code, not on HTTP status. (Previously this route returned non-200 on some failures, which broke HubSpot’s contract — now fixed.)
Sidebar UI extensionNo retry — the operator clicks again.Always 200 OK with the ok flag plus code / message / retryable / trace_id on failure.

From Chert to HubSpot

PathRetry behavior
Reply pushOne inline retry on 401 after a forced token refresh. No further retries from this code path. The reply-notify cron re-runs every two minutes; transient HubSpot failures retry on the next tick.
Reply push circuit breakerFive consecutive failures trip the breaker for the tenant. Subsequent pushes are skipped until a successful push resets the counter.
OAuth token refreshOne attempt per call site. A persistent refresh failure surfaces to the caller.

Inside the Chert pipeline

PathRetry behavior
Outbound send dispatchHandled by the Chert delivery pipeline, transparent to the integration.
Lead resolveNo retry. Failure is returned to the caller as a structured error.

Idempotency

SourceKeyEffect on retry
Workflow custom actionHubSpot’s callbackIdSame callback always returns the prior response.
Sidebar card sendwidget:{tenantId}:{contactId}:{secondBucket}Double-clicks within the same second collapse to one send; the next second is a fresh attempt.
Contact creation webhookwebhook:contact_creation:{objectId}The same contact creation event never re-fires.
Chert internal pipeline(phone_line, recipient, message) for six hoursIdentical messages within six hours dedup at the dispatch layer.
A response carrying duplicate: true is a successful outcome and should be treated identically to duplicate: false by downstream workflow branches.

Sandbox versus Production

HubSpot’s developer sandbox accounts are first-class for this integration. The same install flow, scopes, and signature scheme apply. Differences to plan for:
ConcernSandboxProduction
Rate limitLower than productionEdition-dependent; see HubSpot docs
Webhook deliveryDelayed under loadReal-time
Phone lineUse a Chert test project with test phone linesUse the production project
Workflow executionManual triggering onlyTriggered by real contact events
Chert provisions a separate tenant per HubSpot account regardless of sandbox or production status. A sandbox install does not consume a production install slot.

See Also

  • Architecture — where each limit applies in the call graph.
  • Configuration — daily cap and sending window settings.
  • Security — what is logged for retried events.