Skip to main content
This guide walks through building a HubSpot integration on the Mighty API. When you’re done, you’ll have a small backend service that:
  • Creates or updates a HubSpot contact whenever someone joins your Mighty Network, buys a plan, or is tagged
  • Loads your existing members into HubSpot
  • Reacts to HubSpot activity by tagging members or inviting new people to your Network
The examples use Node.js 18+ and Express, but every step is plain HTTP and GraphQL, so you can port it to any language.

How it works

  • Mighty → HubSpot: You register a webhook with the createWebhookCallback mutation. Mighty sends member events to your service, and your service writes them to HubSpot.
  • HubSpot → Mighty: A HubSpot workflow calls your service, and your service calls the Mighty API to tag or invite the person.
Your service calls the Mighty API with an OAuth token that a Network Host grants once, when they connect the integration.

Before you begin

You need:
  • A Mighty Network on the Scale Plan or above, and a Host account on it. OAuth applications and webhooks are plan-gated features.
  • A HubSpot account with permission to create a private app. The HubSpot → Mighty direction also needs workflows that can Send a webhook, which depends on your HubSpot subscription.
  • A server with a public https:// URL to run the integration service.

Member emails

HubSpot matches contacts by email, so check how your Network exposes member emails before you start:
  • Webhook payloads return an empty email when the member hasn’t consented to commercial email, and a masked email (a***@***.***) unless your Network’s plan includes member-email visibility.
  • The Mighty API returns plain email addresses only to a Host token that carries the read:userinfo scope, on a plan that includes member-email visibility. Otherwise, addresses come back obfuscated.
Your integration should skip members without a usable email rather than create broken contacts. The examples below do this with an isUsableEmail check.

Step 1: Set up HubSpot

  1. In HubSpot, create a private app for the integration.
  2. On the Scopes tab, add crm.objects.contacts.read and crm.objects.contacts.write.
  3. Create the app and copy its access token. Store it on your server as HUBSPOT_TOKEN.
  4. Create custom contact properties for the Mighty data you want to keep. This guide uses:

Step 2: Create an OAuth application

  1. In your Network, go to Network Admin > Integrations > OAuth Applications and click New OAuth Application.
  2. Choose client type Confidential. Your integration runs on a server, so it can keep a client secret. See Backend web apps.
  3. Register your service’s callback URL as the redirect URI, for example https://hubspot-sync.example.com/oauth/callback.
  4. Select these scopes:
  1. Save the application and store the Client ID and Client Secret on your server as MIGHTY_CLIENT_ID and MIGHTY_CLIENT_SECRET.
Because this application requests host: scopes, only Hosts of the Network can complete the sign-in. That’s what you want here: a Host connects the integration once, and it acts with that Host’s permissions.
For every option on this form, see OAuth Applications.

Step 3: Connect the Network and call the API

A Host connects the integration by going through the Authorization Code flow once. Your service redirects them to https://YOUR_SUBDOMAIN.mn.co/oauth/authorize with the scopes from Step 2, validates state on the callback, and exchanges the code for an access token and a refresh token. Store the refresh token encrypted on your server. Access tokens expire after one hour, so wrap every Mighty API call in a helper that refreshes the token when it needs to:
mighty.js
Every request to api.mn.co needs a non-empty User-Agent header. Requests without one are blocked and return an HTML page with HTTP 403.
Confirm the connection works by asking who you’re authenticated as:

Step 4: Write contacts to HubSpot

Add a helper that creates or updates HubSpot contacts, matched on email. Sending contacts in batches of up to 100 keeps you well inside HubSpot’s API limits.
hubspot.js
Because every write matches on email, sending the same member twice updates the existing contact instead of creating a duplicate.

Step 5: Register a webhook

Now tell your Network to send member events to your service. Generate a long random secret, store it as MIGHTY_WEBHOOK_SECRET, and register the webhook with createWebhookCallback. Mighty sends the secret as a Bearer token on every delivery so your service can verify it.
register-webhook.js
Run this once. To change the URL, secret, or events later, use updateWebhookCallback. To list the webhooks already registered on your Network, query network { webhookCallbacks { nodes { id url includedEvents disabled } } }.
Only subscribe to the events you handle. If you omit includedEvents, the webhook receives every event type, including posts, comments, and polls.

Step 6: Handle webhook deliveries

Each delivery is an HTTP POST with a JSON body:
The event_type is the event name followed by Hook, such as MemberJoinedHook or MemberPurchasedHook. Payload fields use snake_case. This endpoint verifies the secret, acknowledges the delivery right away, and then writes to HubSpot:
server.js
Write appendTag to fit your CRM. For example, read the contact’s current mighty_tags value from HubSpot and append the new tag, or add the contact to a HubSpot list named after the tag. Before you rely on the payload shape for a new event, check it in the webhook reference. Webhooks registered through the Mighty API and through Network Admin use the same delivery format.

Step 7: Backfill existing members

Webhooks only cover events from now on. To load everyone who joined before you registered the webhook, page through the member roster once and send each page to HubSpot:
backfill.js
Sort by RESOURCE_ID for a backfill. Other sort keys, such as the default LAST_VISIT, can change while you page, so a member can be skipped or returned twice. Always page from pageInfo.endCursor until hasNextPage is false. See Query cost limits for how page size affects cost.

Step 8: Send HubSpot changes to Mighty

Now go the other way. When something happens in HubSpot, like a deal closing or a contact joining a list, a HubSpot workflow calls your service and your service updates the Network.

Set up the HubSpot workflow

  1. In HubSpot, create a contact-based workflow with the enrollment trigger you want, such as Lifecycle stage is Customer.
  2. Add a Send a webhook action with method POST and the URL https://hubspot-sync.example.com/webhooks/hubspot.
  3. Include the contact’s Email, First name, and Last name in the request body.
  4. Add authentication so your service can verify the request. Send a long random secret in an X-Sync-Secret header and store it as HUBSPOT_WEBHOOK_SECRET. If you use HubSpot’s request signature instead, verify that in place of the header check below.

Tag the member, or invite them if they’re new

Your service looks up the contact in your Network by email. If they’re already a member, it adds a tag. If not, it sends them an invite.
server.js
To find the tag’s ID, query your Network’s tags once and save the one you want:
createInvites can also invite people to a specific Space with spaceId, or to a paid or free plan with planId. For example, you could invite a contact straight to your premium plan when their HubSpot deal closes.
memberByEmail returns null both when no member has that email and when your Host token can’t see the member’s email, for example because of the member’s email-sharing consent. It’s also rate limited for lookups that don’t find anyone. If an invite is ignoredRecipients, the person is already a member or already has a pending invite.

Run it in production

  • Respond fast. Return a 2xx response before doing any HubSpot work. Deliveries time out after 10 seconds and are retried with backoff for about two hours. If a webhook has 5 consecutive failed deliveries and the first failure is at least 3 days old, it’s automatically disabled. Once disabled, no more deliveries are attempted and its disabled field is true. To re-enable it, fix your endpoint, then call updateWebhookCallback.
  • Ignore duplicates. Retries can deliver the same event more than once. Store each event_id you’ve processed in a database, not in memory.
  • Don’t lose failed events. Your endpoint acknowledges each delivery before it writes to HubSpot, so Mighty doesn’t retry an event that fails afterward. Put deliveries on a durable queue, or store failed events, and replay them once HubSpot is reachable again.
  • Check every GraphQL response. The Mighty API returns HTTP 200 for most errors, and mutations also return an errors array in their payload. See Errors.
  • Handle a disconnected Host. If a token refresh returns invalid_grant, the Host revoked access, changed their password, or the application was deleted. Alert your team so a Host can reconnect the integration.
  • Watch your quotas. Mighty API usage counts against your Network’s quota (see Rate Limits), and HubSpot enforces its own limits. Batch writes where you can.
  • Track schema changes. Subscribe to the changelog so you hear about new fields and deprecations before they affect your integration.

Next steps

Authentication

Implement the OAuth flow the Host uses to connect the integration.

GraphQL Schema Explorer

Explore member, tag, and invite fields to sync more data to HubSpot.

OAuth Client Architectures

Keep tokens on your server and avoid the token proxy anti-pattern.

Webhook reference

See every webhook event and its payload.