Webhooks let you react to moderation events in real time. Whenever an event you subscribe to fires, we’llDocumentation Index
Fetch the complete documentation index at: https://docs.moderationapi.com/llms.txt
Use this file to discover all available pages before exploring further.
POST a JSON payload to your URL. A single webhook can subscribe to any combination of events — you don’t need a separate URL per event type.
Configure webhooks under Configure → Webhooks in the dashboard.
How it works
- Add a webhook in the dashboard, set its URL, and tick the events you care about.
- Whenever any of those events fire, we POST the event to your URL.
- Your endpoint returns a
2xxwithin 5 seconds to acknowledge. - Anything else (timeout,
4xx,5xx) triggers retries with exponential backoff — up to 5 attempts total.
Request headers
Every delivery includes:| Header | Description |
|---|---|
webhook-version | Payload envelope version. Currently always v2. |
webhook-event-id | Stable event ID (matches id in the body). Use this to dedupe retries. |
modapi-signature | HMAC-SHA256 signature of the raw request body. See Verifying signatures. |
User-Agent | ModAPI/1.0. Useful for allow-listing in security tools — see Troubleshooting. |
Content-Type | application/json. |
Payload envelope
Every event shares the same outer envelope. The event-specific data lives indata.object.
Stable event ID, prefixed with
evt_. Identical across retries — use it to
dedupe.The event type, e.g.
queue_item.rejected or author.blocked. See the event
catalog.Always
v2.ISO 8601 timestamp of when the event was emitted.
Wraps the event-specific payload.
Envelope shape
Event catalog
| Event | Fires when | data.object |
|---|---|---|
queue_item.resolved | A moderator marks a queue item as resolved (checked off the queue). | The item, plus optional author and queue references. |
queue_item.action | A custom moderation action runs on a queue item. | The action that ran, with the related item, author, and queue. |
queue_item.rejected | The built-in reject action runs on a queue item. | Same shape as queue_item.action. |
queue_item.allowed | The built-in allow action runs on a queue item. | Same shape as queue_item.action. |
author.blocked | An author transitions to the blocked status. | The action that drove the transition, with the affected author. |
author.unblocked | An author transitions back to enabled. May fire automatically when a temporary suspension expires. | Same shape as author.blocked. |
author.suspended | An author is suspended for a finite period. The nested author.block.until indicates when the suspension lifts. | Same shape as author.blocked. |
author.updated | Public author fields (name, email, profile picture, metadata, etc.) change. Status transitions don’t trigger this. | The updated author. |
author.trust_level_changed | An author’s resolved trust level transitions to a new value. Doesn’t fire for no-op recomputes. | The updated author. |
author.action | A custom action runs against an author. | Same shape as author.blocked. |
Reject and allow are first-class events. If you want to capture every
moderation action firing on a queue item, subscribe to
queue_item.action
and queue_item.rejected and queue_item.allowed. Built-in actions
don’t fire under queue_item.action.Routing by content type
Queue-item events carry the item’smeta_type — a high-level classifier you set when submitting content (or inherit from the channel). Use it to fan a single webhook out to the right handler per entity:
meta_type | Typical use |
|---|---|
profile | User profiles |
message | DMs / chat |
post | Long-form posts |
comment | Replies |
event | Event listings |
product | Marketplace |
review | Ratings/reviews |
other | Anything else |
Webhook router
Verifying signatures
Each delivery is signed with HMAC-SHA256 using your project’s webhook secret. Find the secret under API Keys in the dashboard. To verify, computeHMAC_SHA256(rawRequestBody, webhookSecret) as a hex digest and compare it to the modapi-signature header. Always use a constant-time comparison.
Preventing replay attacks
The envelopecreated timestamp lets you reject events older than your tolerance window (e.g. 5 minutes). Combine that with the stable webhook-event-id header to dedupe retries — store recently-seen IDs and ignore repeats.
Retries and delivery
- Success: any
2xxresponse within 5 seconds closes the delivery. - Failure: any non-
2xx, timeout, or network error triggers a retry. - Limits: up to 5 attempts total, with exponential backoff between tries.
- Permanent failure: after the final attempt fails, we’ll email the project’s admin.
Troubleshooting
Check the events log
If webhooks aren’t behaving as expected, the events log is the first place to look. It shows every delivery attempt with full request and response details.Allow Moderation API through your firewall
Some hosting providers and security services block webhook traffic by default. Cloudflare’s Bot Fight Mode, for example, will challenge the request instead of letting it through.- Cloudflare
- Other providers
Common blocking scenarios
- Bot Fight Mode / Super Bot Fight Mode is enabled
- WAF Managed Rules active
- Custom security rules
Choose your solution based on your plan
- Super Bot Fight Mode (Pro+)
- Bot Fight Mode (Free)
✅ Use Security Rules (Recommended)
- Go to your Cloudflare dashboard
- Select your domain
- Navigate to Security → Security rules
- Create a custom rule:
- Name: “Moderation API Webhooks”
- Field: User Agent
- Operator: starts with
- Value:
ModAPI/ - Action: Skip
All Super Bot Fight Mode Rulesand other rules that might interfere.
- Make sure to place this rule before other rules
- Deploy the rule
Still having issues?
- Check your hosting provider’s security logs for blocked
ModAPI/requests. - Verify your endpoint returns a
2xxstatus code within 5 seconds. - Test with a minimal endpoint (just respond
200 OK) to isolate the issue. - Make sure firewall allow rules don’t conflict with deny rules earlier in the chain.