Event Overview
The media.moderated
event is triggered when the moderation process completes for a media item. This includes both AI-based and manual moderation decisions.
Payload Structure
{
"event": "media.moderated",
"timestamp": "2024-01-15T14:35:00Z",
"data": {
"media_id": "123e4567-e89b-12d3-a456-426614174000",
"app_media_id": "user-upload-123",
"site_id": "98765432-dcba-4321-fedc-210987654321",
"status": "rejected",
"previous_status": "pending",
"moderation_type": "ai",
"moderated_at": "2024-01-15T14:35:00Z",
"moderation_details": {
"rule_violations": [
{
"rule_id": "550e8400-e29b-41d4-a716-446655440000",
"rule_name": "Inappropriate Content",
"confidence": 0.95,
"details": "Adult content detected"
}
],
"ai_analysis": {
"adult": 0.95,
"violence": 0.10,
"hate": 0.05
}
},
"metadata": {
"user_id": "abc-987",
"gender": "male"
}
}
}
Payload Fields
The event type. Always media.moderated
for this event.
ISO 8601 timestamp of when the event occurred.
Unique identifier for the media item in Pixel Patrol.
Your application’s identifier for this media item.
The site ID associated with this media.
The new moderation status: approved
, rejected
, or pending_review
.
The status before moderation.
How the content was moderated: ai
, manual
, or rule
.
Timestamp when moderation completed.
Detailed information about the moderation decision.
data.moderation_details.rule_violations
List of rules that were violated (if any).
data.moderation_details.ai_analysis
AI confidence scores for different content categories.
Custom metadata provided during submission.
Status Values
- approved: Content passed moderation and is safe to display
- rejected: Content violated one or more rules and should not be displayed
- pending_review: Content requires manual review by a moderator
Example Implementation
app.post('/webhook', async (req, res) => {
const signature = req.headers['x-pixelpatrol-signature'];
// Verify signature
if (!verifyWebhookSignature(req.body, signature)) {
return res.status(401).send('Invalid signature');
}
const { event, data } = req.body;
if (event === 'media.moderated') {
switch (data.status) {
case 'approved':
// Make content visible
await db.media.update({
where: { id: data.app_media_id },
data: {
status: 'published',
visible: true
}
});
break;
case 'rejected':
// Handle rejected content
await db.media.update({
where: { id: data.app_media_id },
data: {
status: 'rejected',
visible: false,
rejection_reason: data.moderation_details.rule_violations[0]?.details
}
});
// Notify user
await notifyUser(data.metadata.user_id, 'Content rejected');
break;
case 'pending_review':
// Flag for manual review
await db.media.update({
where: { id: data.app_media_id },
data: {
status: 'under_review',
visible: false
}
});
break;
}
}
res.status(200).send('OK');
});
Use Cases
- Content Publishing: Automatically publish approved content
- User Notifications: Inform users about moderation decisions
- Content Removal: Remove or hide rejected content
- Manual Review Queue: Route edge cases to human moderators
- Analytics: Track approval/rejection rates and reasons