Skip to main content

Inbound connector webhook authentication model

When you connect a provider to Orbit — HubSpot, Salesforce, Shopify, Calendly, Segment, Slack, Intercom, or anything under the Nango umbrella — events travel inbound to Orbit as webhooks. Those deliveries reach Orbit before any session auth is checked, so a single question decides whether each one is processed: does its cryptographic signature verify against the secret for that connection? This page documents that shared pipeline so you know what to configure, what Orbit enforces, and what happens when something is wrong. For the CRM-specific mapping and transport guarantees, see the CRM integration model; for outcomes once an event is verified, see the CDP event model and Webhook delivery semantics.

1. Why inbound receivers mount before session auth

Orbit’s connector webhook endpoints are reachable without an Orbit account session. Interactive Orbit sessions (your dashboard login) are the wrong credential for a provider datacenter: HubSpot’s or Calendly’s servers will never hold one. Instead, the endpoint’s credential is the HMAC signature on each request — the provider signs the payload with a shared secret, and Orbit verifies it before touching the payload. This is the same authentication model as signing outbound webhooks to your own endpoints, just in the opposite direction: for inbound connector events the provider is the sender and Orbit is the receiving party. The check runs before anything touches tenant state, so an unsigned or mis-signed delivery is rejected with no side effects. One practical consequence: you complete the connect flow from within your Orbit account, but the inbound event path afterwards requires no session — the signature secret provisioned at connect time is all that matters.

2. Per-provider signature schemes, with the HubSpot v3 worked example

All schemes are symmetric HMAC over the raw request content, but the details differ per provider. Getting any piece wrong — the wrong field ordering, the wrong encoding, a proxy that re-serialized the JSON — produces a 401, so it helps to see one full example. HubSpot (v3). HubSpot’s header X-HubSpot-Signature-v3 carries a base64 digest of an HMAC-SHA256 over four concatenated inputs:
  • method — the uppercase HTTP method (POST).
  • uri — the absolute URL you configured in your HubSpot app settings, exactly as HubSpot signed it; Orbit reconstructs this from the protocol and host headers on the incoming request.
  • body — the raw request bytes, not a re-parsed JSON object.
  • timestamp — the value of the X-HubSpot-Request-Timestamp header.
Orbit also enforces a 5-minute replay window on that timestamp and compares digests in constant time. The secret comes from the HubSpot app’s client secret; you register it once when you connect HubSpot to Orbit. Salesforce. A tenant-provisioned HMAC key rather than a provider-issued secret:
Because Orbit provisions this key for your tenant at connect time, you can rotate it without any provider-side coordination. The receiver accepts Salesforce Outbound Messages (SOAP envelopes translated to JSON by your Apex or Flow) as well as direct Apex callout or Flow HTTP actions — all three use the same signature over the same formula. Shopify. Shopify signs with a per-tenant HMAC over the raw body in the X-Shopify-Hmac-Sha256 header, base64-encoded. Calendly. Calendly’s header Calendly-Webhook-Signature carries two values, t=<unix_timestamp>,v1=<hex_digest>, where the digest is HMAC-SHA256 over t + "." + raw_body with a 3-minute replay window. The signing key is provisioned at connect time and stored against your tenant’s connection state, so the receiver resolves it per tenant on every delivery. Segment. A plain x-signature header carries an HMAC-SHA1 hex digest of the raw body, signed with the source secret you set up on the Segment side during connect. Slack, Intercom, and the Nango umbrella. Slack and Intercom receive their events through the shared Nango webhook receiver, as do a number of other providers Orbit connects through Nango (including HubSpot, Salesforce, Calendly, and Shopify lifecycle events when routed that way). The Nango receiver performs the same pre-auth HMAC check before processing auth (connection lifecycle) and sync (data refresh) events. The rule across all schemes: signature math runs over the raw body. Anything that re-serializes the payload (an intermediate proxy rewriting JSON whitespace, a body parser the request passed through) breaks verification. If a receiver returns 401 to your provider’s test delivery, check the raw-body path before anything else.

3. Fail-closed secret posture

A receiver treats a missing secret as “receiver disabled,” not “signature optional.” When the required secret is unset — for example, a deployment-time operator hasn’t pasted the HubSpot client secret — the endpoint answers every delivery with 503 and logs the configuration gap until it’s fixed. A missing secret is not a reason to skip verification; it is a reason to reject. When a secret is present, any delivery whose signature does not verify is rejected with 401. Both failure modes close the gate, but the distinct status codes let operator tooling tell the difference between “we are misconfigured” (503) and “the sender sent a bad signature” (401).
The same fail-closed rule applies to every connector receiver. A 503 on a provider’s first test delivery means the connect flow — for that provider — hasn’t finished; it answers only once the secret is provisioned.

4. Org resolution: from a delivery to a tenant

Verification answers “did the right provider send this?” The next question is “which Orbit organization owns this connection?” — because every receiver is multi-tenant and every event must land in exactly one tenant’s data. HubSpot portal lookup. HubSpot deliveries carry a portalId (the HubSpot account id). At connect time Orbit stamps a reverse map from portal id to tenant, so the receiver resolves the tenant with a single indexed lookup. For connections that predate the reverse map, a batched scan across provisioned tenants remains as the correctness floor; the scan never back-fills the reverse map (only the OAuth connect flow does). Calendly’s ?org= hint. When Calendly’s subscription was registered, the webhook URL captured your organization id as a query parameter (?org=<orgId>). Calendly preserves query strings on delivery, so the receiver can resolve the tenant from the URL itself instead of searching. Nango’s org-id recovery ladder. The Nango receiver handles auth and sync events for many providers, and each delivery names a connectionId. Resolution proceeds down a ladder:
  1. Cached resolution. The first successful resolution for a connection is cached in memory, so later deliveries on the same connection resolve without any lookup or network round trip.
  2. Legacy id match. The connectionId is looked up directly against organizations — for connections created before Nango Connect UI, the connection id is the org id.
  3. End-user hint from the envelope. Orbit passes your organization id as Nango’s end_user.id when it creates the connection, and Nango echoes it back on the webhook envelope. The receiver tries that hint before any network call.
  4. Live getConnection retry. If all the above fail, the receiver queries Nango for the connection record, reads its end-user id, and retries the organization lookup with that value.
A delivery that survives verification but resolves no tenant (an abandoned OAuth attempt, a since-deleted connection) is acknowledged without side effects so the provider stops retrying — dropping it entirely would only postpone the same outcome.

5. Where verified events land

Once signature and tenant resolution both pass, events are written into your tenant’s environment — never a shared, cross-tenant table:
  • CRM events (HubSpot, Salesforce) mirror contacts, deals, and lifecycle changes into your Orbit contact book — creating, updating, or soft-deleting contact rows keyed on the provider’s external id.
  • Scheduling events (Calendly) match invitees to contacts by email or phone and persist a typed event row for triggers.
  • Commerce events (Shopify), profile events (Segment), and messaging events (Slack, Intercom) land in their corresponding tenant pipelines.
Every event also persists a deduplicated event row keyed on the provider’s event identifiers, so provider retries (HubSpot retries up to 10 times over 24 hours; Calendly for up to 24 hours on 5xx) are absorbed idempotently. Campaign and flow triggers read from these mirrored rows — see the CDP event model for how verified events become actionable within your org.

6. Which providers ship receivers

Orbit ships pre-auth inbound receivers for:
  • HubSpot — CRM contact, deal, and ticket events (HMAC-SHA256 v3).
  • Salesforce — CRM object and task events via Outbound Messages, Apex callout, or Flow HTTP actions (tenant-provisioned HMAC).
  • Shopify — commerce events (X-Shopify-Hmac-Sha256).
  • Calendly — scheduling events (Calendly-Webhook-Signature, 3-minute window).
  • Segment — profile and audience events (x-signature HMAC-SHA1).
  • Slack — workspace events via the Nango receiver.
  • Intercom — conversation and contact events via the Nango receiver.
  • Nango umbrella — shared receiver for auth (connection lifecycle) and sync (data refresh) events across Nango-routed providers.
New receivers follow this same shape: mount pre-auth, verify HMAC over the raw body, fail closed on missing secrets, resolve the tenant, write typed rows, and dedupe deliveries.

7. Operational guards in every receiver

All receivers share the same hardening rules:
  • Constant-time comparison. Signature comparison uses a constant-time digest compare, so response time never reveals how much of a forged digest was correct.
  • Raw-body capture before parsing. The raw request bytes are captured before any JSON parsing, and signature math runs against those exact bytes. Parsing happens only after verification passes.
  • Replay windows. Providers that timestamp their signatures (HubSpot’s 5 minutes, Calendly’s 3 minutes) have that window enforced against Orbit’s clock; a re-sent delivery with a stale timestamp is rejected like a bad signature.
  • Idempotent persistence. Every event row is keyed by the provider’s event identifiers and inserted with conflict-no-op semantics, so provider retry storms replay harmlessly.
  • Retry-friendly status codes. A transient internal failure returns a 5xx so the provider retries; a definitive rejection (bad signature, unconfigured receiver, unknown tenant) returns a 4xx or a clean acknowledgement so retries stop.
  • CRM integration model — sync directions, object mapping, and per-provider delivery guarantees for HubSpot and Salesforce.
  • Webhook delivery semantics — Orbit’s outbound event delivery, retries, and ordering (the mirror image of this page).
  • CDP event model — how verified inbound events become contact and event state in your organization.