Webhooks Guide

Webhooks

Receive real-time notifications when drafts are approved or rejected.

Overview

Webhooks allow your application to receive instant notifications when a draft is approved or rejected. This enables you to execute the approved action automatically.

Tip: Configure your webhook URL in the Dashboard → Webhooks page.

Event Types

draft.approved

Triggered when a draft is approved. Contains the approved content for execution.

draft.rejected

Triggered when a draft is rejected. Includes optional rejection reason.

Webhook Payload

draft.approved

{
  "event": "draft.approved",
  "draft": {
    "id": "cmlgx2hvq0002k6gve9fuaz0k",
    "title": "Send welcome email",
    "content": {
      "to": "user@example.com",
      "subject": "Welcome!",
      "body": "Hello..."
    },
    "metadata": {
      "source": "ai_agent_v1"
    },
    "reviewedAt": "2026-02-10T12:05:00Z"
  },
  "timestamp": "2026-02-10T12:05:00Z"
}

draft.rejected

{
  "event": "draft.rejected",
  "draft": {
    "id": "cmlgx2hvq0002k6gve9fuaz0k",
    "title": "Send welcome email",
    "rejectionReason": "Content violates policy",
    "reviewedAt": "2026-02-10T12:05:00Z"
  },
  "timestamp": "2026-02-10T12:05:00Z"
}

Handling Webhooks

Example: Node.js/Express

app.post('/webhooks/processa', async (req, res) => {
  const { event, draft } = req.body

  if (event === 'draft.approved') {
    // Execute the approved action
    await executeAction(draft.content)

    // Respond with 200 to acknowledge receipt
    res.status(200).json({ received: true })
  }

  if (event === 'draft.rejected') {
    // Log rejection for monitoring
    console.log(`Draft ${draft.id} rejected: ${draft.rejectionReason}`)
    res.status(200).json({ received: true })
  }
})

Example: Python/Flask

@app.route('/webhooks/processa', methods=['POST'])
def handle_webhook():
    data = request.json
    event = data['event']
    draft = data['draft']

    if event == 'draft.approved':
        # Execute the approved action
        execute_action(draft['content'])
        return jsonify({'received': True}), 200

    if event == 'draft.rejected':
        # Log rejection
        print(f"Draft {draft['id']} rejected: {draft.get('rejectionReason')}")
        return jsonify({'received': True}), 200

Best Practices

Return 200 Quickly

Respond with 200 OK as soon as you receive the webhook. Process the action asynchronously to avoid timeouts.

Handle Idempotency

Use the draft ID to ensure you don't process the same event multiple times if webhooks are retried.

Use HTTPS

Always use HTTPS URLs for your webhook endpoints to ensure secure transmission.

Monitor Failures

Set up logging and monitoring for webhook delivery failures. We'll retry up to 3 times with exponential backoff.

Testing Webhooks

Test your webhook integration using these tools:

webhook.site

Get a temporary webhook URL to inspect payloads

Dashboard Test

Use the "Test Webhook" button in the Dashboard → Webhooks page to send a test event.

Go to Webhooks →