- Real-time sync from Mighty to ActiveCampaign. When a member joins, leaves, updates their profile, gets tagged, buys a plan, cancels, or completes a course, a Mighty webhook calls your server, and your server updates the matching ActiveCampaign contact.
- A one-time backfill. A script that pages through your existing members with the Mighty API and adds them to ActiveCampaign.
- Optional sync from ActiveCampaign back to Mighty. An ActiveCampaign automation that tags the member in your Network, for example when a lead finishes a nurture sequence.
Prerequisites
- A Mighty Network on the Scale plan or above. You need it for OAuth applications and webhooks.
- A Network Host account on that Network. You authorize the integration as this Host.
- An ActiveCampaign account with permission to view API settings.
- A server that can receive HTTPS requests from the public internet. The examples use Node.js 18 or later with Express, but any language works.
Step 1: Get your ActiveCampaign API credentials
- In ActiveCampaign, go to Settings > Developer.
- Copy your API URL (for example,
https://youraccount.api-us1.com) and your API Key. - Create the list you want members added to, then note its numeric ID. The ID appears in the list’s URL in ActiveCampaign, and
GET /api/3/listsreturns it too.
Step 2: Create an OAuth application in Mighty
The integration calls the Mighty API as a Network Host, so it needs an OAuth application and a Host’s authorization.- In your Network, go to Network Admin > Integrations > OAuth Applications and click New OAuth Application.
- Choose the Confidential client type, because the integration runs on your server.
-
Register the redirect URI your server handles, for example
https://your-server.example.com/oauth/callback. -
Select these scopes:
- Save the application, then copy the Client ID and Client Secret.
Step 3: Build the webhook receiver
Mighty delivers each webhook as an HTTPSPOST with a JSON body:
event_type is the event name with a Hook suffix, for example MemberJoinedHook. When you register the webhook with an API key, Mighty sends that key in an Authorization: Bearer header on every delivery. Check it before you trust the request.
ActiveCampaign helpers
Start with a small module that wraps the ActiveCampaign endpoints the integration uses. It queues requests to stay under ActiveCampaign’s rate limit of 5 requests per second.activecampaign.js
The webhook endpoint
The server maps each Mighty event to ActiveCampaign updates. Adjust the tag names to fit how you segment contacts.server.js
WEBHOOK_SECRET, for example with openssl rand -hex 32. You register the same value with Mighty in the next step.
Mighty expects a
2xx response within 10 seconds. The example calls ActiveCampaign before it responds, which works for most Networks. But the queue in activecampaign.js spaces requests 200 ms apart, so a handler that makes several ActiveCampaign calls takes about a second to finish. If several events arrive at once, they queue behind each other and can add up to more than 10 seconds. If you expect bursts of activity, such as a large import or a launch, put incoming events on a queue, respond 200 right away, and process the queue in a background worker.Step 4: Register the webhook
Deploy the receiver, then register its URL with thecreateWebhookCallback mutation. You can run it in the GraphiQL explorer at https://your-subdomain.mn.co/admin/headless-api/explorer, or send it with any GraphQL client and a Host access token.
includedEvents, the webhook receives every event type, including posts, comments, and reactions.
To confirm it works, join the Network with a test account. A contact tagged Mighty: Member should appear in ActiveCampaign within a minute or so.
Step 5: Backfill existing members
Webhooks only cover changes from now on. To bring over the members you already have, run a one-time script that pages through the roster with the Mighty API. The backfill and the optional reverse sync in Step 6 both need a Mighty access token. Each refresh returns a new refresh token and invalidates the old one, so a shared helper needs to persist the refresh token it gets back and reuse it next time, not the one you started with. This one stores it in a JSON file and caches the access token in memory until shortly before it expires.mighty.js
A JSON file is fine for a single-server script. In production, store the refresh token in a database or secret store instead.
backfill.js
RESOURCE_ID returns each member exactly once, even if members visit or join while the script runs. Always page from pageInfo.endCursor. See Query cost limits for how page size affects a query’s cost.
Run the backfill after you register the webhook. Otherwise you can miss members who join between the two steps. Running it again is safe, because contact/sync updates existing contacts rather than creating duplicates.
Step 6 (optional): Sync tags from ActiveCampaign back to Mighty
You can also act on your Network from ActiveCampaign. For example, when a lead finishes a nurture sequence, tag them in Mighty so a Mighty automation can welcome them to a Space.-
In Mighty, create the tag you want to apply, then find its ID with this query:
-
Add an endpoint to your server that looks up the member by email and applies the tag. ActiveCampaign’s automation webhooks send form-encoded contact data and can’t set an authorization header, so put a secret in the URL instead.
Failedserver.js
memberByEmaillookups are rate limited per Network, so point the ActiveCampaign automation only at contacts you know are members, for example ones taggedMighty: Member, rather than your whole list. Past the limit, the query returns aTHROTTLEDerror. -
In ActiveCampaign, open the automation and add a Webhook action pointing at
https://your-server.example.com/webhooks/activecampaign?secret=YOUR_AC_WEBHOOK_SECRET.
Troubleshooting
Contacts aren't being created
Contacts aren't being created
Check your server logs for A rising
401 responses. A 401 means the apiKey you registered doesn’t match WEBHOOK_SECRET. Then check the health of the webhook in Mighty:consecutiveFailures count means your endpoint is returning errors or timing out. Mighty retries failed deliveries, and pauses a webhook that keeps failing. See Circuit breaker.Some members are skipped
Some members are skipped
The integration skips members whose email it can’t read. A webhook payload leaves out the email of a member who hasn’t agreed to share it, and masks it (
a***@***.***) when your plan doesn’t include member email visibility. The GraphQL email field is also obfuscated unless your token has the read:userinfo scope and belongs to a Network Host.A member who changed their email has two contacts
A member who changed their email has two contacts
contact/sync matches contacts by email, so a new address creates a new contact. To keep one contact per member, store the ActiveCampaign contact ID against the Mighty member ID (payload.member.id). On MemberUpdatedHook, update that contact’s email through PUT /api/3/contacts/{id}.ActiveCampaign returns 429 errors
ActiveCampaign returns 429 errors
ActiveCampaign allows 5 requests per second per account. The queue in
activecampaign.js enforces that limit within one process only, and the backfill script runs as a separate process from server.js. If you run the backfill while the webhook receiver is live, each enforces the limit on its own requests, and their combined traffic can still exceed 5 requests per second. Run the backfill during a maintenance window, or add a shared rate limiter, such as one backed by Redis, if you run several servers or workers.Related
Authentication
Run the OAuth flow and refresh access tokens.
Webhooks
See delivery behavior, retries, and the payload for every event.
Mighty API
Explore the GraphQL endpoint, rate limits, and errors.
OAuth Applications
Configure client types, redirect URIs, and scopes.