# Guide to Mighty Networks Webhooks: Features and Best Practices

Mighty Networks webhooks tell your systems what is happening in your community: a member joins or leaves, buys a plan or cancels a subscription, finishes a course, posts, comments or RSVPs to an event. If you run a community, course or membership business on Mighty Networks, webhooks keep your CRM, email platform and analytics in step with it without polling the API.

This guide covers how Mighty Networks webhooks are configured and authenticated, the events and their envelope, how retries and the circuit breaker work, and the practices that keep a receiver reliable.

## What are Mighty Networks webhooks?

You configure a webhook endpoint in your Network settings, choose the events you want, and set an API key. When one of those events happens, Mighty Networks sends a JSON `POST` to your URL. Delivery happens in background jobs, so expect a short delay between the event and the request.

Requests are not signed. The API key you configure is sent back on every request as a bearer token, and Mighty Networks tells you to "always validate the `Authorization` header matches your configured key". A delivery looks like this:

```http
POST /your-webhook-endpoint
Host: your-domain.com
Content-Type: application/json
Accept: application/json
Authorization: Bearer YOUR_CONFIGURED_API_KEY

{
  "event_id": "abc123-uuid",
  "event_timestamp": "2024-01-15T10:30:00Z",
  "event_type": "PostCreatedHook",
  "payload": {
    "id": 12345,
    "title": "Example post title",
    "author": { "id": 67890, "email": "user@example.com", "first_name": "John" },
    "space_id": 111,
    "created_at": "2024-01-15T10:30:00Z"
  }
}

```

## Mighty Networks webhook features

| Feature | Details |
| --- | --- |
| Configuration | Your Network settings: endpoint URL, events and API key |
| Method | `POST`, JSON body |
| Authentication | `Authorization: Bearer <your API key>` |
| Signature | None |
| Envelope | `event_id`, `event_timestamp`, `event_type`, `payload` |
| Endpoint | HTTPS required in production |
| Success | Any `2xx` within 10 seconds |
| Retries | Up to 5 times over several hours on any non-`2xx` |
| Circuit breaker | Repeated consecutive failures pause delivery until a probe succeeds |
| Source IPs | Not published |

## Common events

Mighty Networks documents 48 events, each with its own payload schema:

| Area | Events |
| --- | --- |
| Membership | `MemberJoined`, `MemberJoinRequested`, `MemberLeft`, `MemberReturned`, `MemberUpdated`, `InviteRequested` |
| Plans and purchases | `MemberPurchased`, `MemberPurchaseRequested`, `MemberPlanChanged`, `MemberRemovedFromPlan`, `MemberSubscriptionRenewed`, `MemberSubscriptionCanceled` |
| Courses | `MemberCourseProgressStarted`, `MemberCourseProgressUpdated`, `MemberCourseProgressCompleted`, `MemberLessonCompleted` |
| Tags, badges and ambassadors | `MemberTagAdded`, `MemberTagRemoved`, `MemberBadgeAdded`, `MemberBadgeRemoved`, `MemberAmbassadorLeveledUp`, `GiftLeaderboardUpdated` |
| Content | `PostCreated`, `PostUpdated`, `ArticleCreated`, `ArticleUpdated`, `CommentCreated`, `QuestionCreated`, `QuestionUpdated`, `ReactionCreated`, `ReactionDeleted`, `ReportedContentCreated`, and created and updated events for three poll types |
| Events and RSVPs | `EventCreated`, `EventUpdated`, `EventCanceled`, `EventInstanceCanceled`, `RsvpCreated`, `RsvpUpdated`, `RsvpDeleted` |
| Custom fields | `CustomFieldResponseCreated`, `CustomFieldResponseUpdated`, `CustomFieldResponseRemoved` |

The names on the wire don't quite match the reference. The delivery example sends `"event_type": "PostCreatedHook"`, while the reference page is called `PostCreated`. It is the only published example, so match leniently: strip a trailing `Hook` before comparing.

`payload` holds the object the event is about. `MemberJoined`, for example, carries the `member`, the `space_id` they joined and the `network_id`. `event_id` is a UUID you can use to spot repeated deliveries.

## Setting up Mighty Networks webhooks

Generate a long random API key first, for example with `openssl rand -hex 32`, and store it server-side without any `Bearer ` prefix.

1. In your Network settings, open the webhook configuration.
2. Enter your HTTPS endpoint URL.
3. Enter the API key.
4. Select the events you want.
5. Save, then trigger a subscribed event, such as a post in a space, to test it.

**With Hookdeck.** Mighty Networks is a supported source in Hookdeck. Create a source with the Mighty Networks type, paste only the API key you configured in Mighty Networks into **API Key**, and use the Hookdeck source URL as the webhook endpoint. Mighty Networks sends `Bearer <key>` in the `Authorization` header, and Hookdeck matches that scheme for you, so don't add `Bearer ` yourself. The source accepts `POST` only, which is the method Mighty Networks uses. A request without the right header still gets a `200` from Hookdeck, but Hookdeck marks it as failed verification and doesn't deliver it to your service.

## Securing Mighty Networks webhooks

Check that `Authorization` uses the `Bearer` scheme, then compare the rest with your stored key in constant time. Auth schemes are case-insensitive, so accept `bearer` too. Check lengths before calling `crypto.timingSafeEqual`.

```javascript
const crypto = require('crypto');
const express = require('express');

function verifyMightyNetworksRequest(headers) {
  const key = process.env.MIGHTY_NETWORKS_WEBHOOK_SECRET; // the bare API key
  if (!key) return false; // fail closed when unconfigured
  const auth = headers['authorization'];
  if (typeof auth !== 'string' || !/^bearer /i.test(auth)) return false;
  const received = Buffer.from(auth.slice(7), 'utf8');
  const expected = Buffer.from(key, 'utf8');
  return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}

const app = express();

app.post('/webhooks/mighty-networks', express.raw({ type: '*/*' }), (req, res) => {
  if (!verifyMightyNetworksRequest(req.headers)) {
    return res.sendStatus(401);
  }

  let event;
  try {
    event = JSON.parse(req.body.toString('utf8'));
  } catch {
    return res.sendStatus(400);
  }
  const name = String(event.event_type || '').replace(/Hook$/, ''); // PostCreatedHook -> PostCreated
  // Deduplicate on event.event_id, route on name, then process asynchronously.
  res.sendStatus(200);
});

```

The same check in Python:

```python
import hmac
import os

def verify_mighty_networks_request(headers) -> bool:
    key = os.environ.get("MIGHTY_NETWORKS_WEBHOOK_SECRET")
    if not key:
        return False
    auth = headers.get("authorization")  # case-insensitive in Starlette and Flask
    if not auth or auth[:7].lower() != "bearer ":
        return False
    return hmac.compare_digest(auth[7:].encode("utf-8"), key.encode("utf-8"))

```

A static key proves the sender knows it, but it doesn't prove the body is unchanged, and it gives no replay protection: nothing is signed, and `event_timestamp` is not covered by anything. Use HTTPS, which Mighty Networks requires in production anyway, keep the key long and random, keep it out of logs, and change it in Network settings and in your receiver at the same time if it might have leaked.

> **Make Mighty Networks webhooks production-ready.** [Hookdeck Event Gateway](/event-gateway) checks the bearer key on every Mighty Networks request, stores each member, purchase and content event, and answers fast enough that the circuit breaker never trips because of your service.

## Mighty Networks webhook limitations and pain points

### The circuit breaker pauses delivery

**The Problem:** After a run of failures, webhooks stop arriving for a while, even for new events.

**Why It Happens:** Mighty Networks protects delivery with a circuit breaker. When deliveries fail several times in a row (a non-`2xx` response, a timeout or a connection error), it opens and "new webhooks for that endpoint are not delivered". After a cooldown it probes your endpoint and resumes once the probe succeeds. The docs don't say whether events from the paused period are sent later.

**Workarounds:**

* Keep the endpoint highly available and answer within 10 seconds.
* After a gap, check your logs for a run of failures and reconcile members and purchases through the API.

**How Hookdeck Can Help:** Hookdeck answers each request as soon as it arrives and stores it, so problems in your own service don't count as failures against Mighty Networks. It then delivers to your service with [automatic retries](/docs/retries), and [Issues](/docs/issues) alert you when deliveries fail.

### `PostCreatedHook` or `PostCreated`?

**The Problem:** A handler that switches on the documented event names never matches.

**Why It Happens:** The only delivery example sends `PostCreatedHook`, while every reference page names the event without the suffix.

**Workarounds:**

* Strip a trailing `Hook` before matching, and log any name you don't recognise.

**How Hookdeck Can Help:** Hookdeck [filters](/docs/filters) can route on `event_type` with either spelling, and every request is stored, so you can check the real values your Network sends.

### Retries bring duplicates

**The Problem:** The same purchase or membership change is processed twice.

**Why It Happens:** Any non-`2xx` response is retried up to 5 times over several hours, and a handler that times out after doing its work triggers a retry anyway.

**Workarounds:**

* Mighty Networks asks you to implement idempotency. Store `event_id` before processing and skip repeats.

**How Hookdeck Can Help:** Hookdeck [deduplication](/docs/deduplication) can drop repeated deliveries based on `event_id` before they reach your handler.

## Best practices

### Store only the bare key

Keep the key without `Bearer ` in your secret store, and compare it with the part of the header after the scheme. That way a change of case in the scheme can't break verification.

### Subscribe to what you use

Each event you select is more traffic and more chances to fail. Start with the membership and purchase events your systems act on.

### Re-read money-related changes

For `MemberPurchased`, `MemberPlanChanged` or `MemberSubscriptionCanceled`, confirm the member's current plan through the API before granting or removing access.

### Acknowledge fast and process asynchronously

Check the key, store the event, return `200`, then do the work. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks) and our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

## Conclusion

Mighty Networks sends unsigned JSON `POST` requests that carry your configured API key as `Authorization: Bearer <key>`. Compare the key in constant time over HTTPS, strip the `Hook` suffix before matching `event_type`, deduplicate on `event_id`, and answer within 10 seconds so the circuit breaker stays closed.

[Hookdeck Event Gateway](https://hookdeck.com) checks the bearer key on every request and holds each community event until your service has processed it.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Mighty Networks webhooks reliably in minutes.