Webhooks

Receive automatic callbacks when requests are decided.

How webhooks work

When someone approves or rejects a request in your dashboard, we automatically POST the decision to your webhook URL. This lets your system know what happened and take action accordingly.

Setup

  1. Go to your project settings
  2. Add your webhook URL (must be HTTPS in production)
  3. Save

That’s it. We’ll start sending webhooks immediately.

Webhook payload

When a request is decided, we POST this JSON to your webhook URL:

{
  "event": "request.decided",
  "request_id": "req_abc123",
  "external_id": "your-reference-id",
  "title": "Brief description",
  "status": "approved",
  "decided_by_id": "user_xyz789",
  "decision_note": "Looks good",
  "decided_at": "2026-01-18T12:05:00Z",
  "payload": {
    "your": "original data"
  }
}

Fields:

  • event - Always "request.decided" (more events may be added in future)
  • request_id - The request ID
  • external_id - Your reference ID (if you provided one)
  • title - Request title
  • status - "approved" or "rejected"
  • decided_by_id - ID of user who made the decision
  • decision_note - Optional note from the user
  • decided_at - When the decision was made (ISO 8601)
  • payload - Your original payload data

Responding to webhooks

Your endpoint should:

  1. Return 200 OK status code
  2. Respond within 10 seconds
  3. Process the webhook asynchronously if needed

Example response:

{
  "received": true
}

The response body doesn’t matter - we only care about the status code.

Retries

If your webhook fails (non-200 status or timeout), we’ll retry:

  • 1st retry: 30 seconds later
  • 2nd retry: 5 minutes later
  • 3rd retry: 30 minutes later

After 3 failed attempts, we give up. You can manually retry from the request detail page.

Security

Verify the source

Only accept webhooks from our IP addresses (coming soon).

Use HTTPS

Always use HTTPS for your webhook URL in production. We reject HTTP URLs outside of localhost.

Validate the payload

Check that the request_id exists in your system before processing.

Testing

Use our test server for local development, or tools like:

Example implementations

Node.js / Express

app.post('/webhook', express.json(), async (req, res) => {
  const { event, request_id, status, payload } = req.body;

  if (event === 'request.decided') {
    // Handle the decision
    if (status === 'approved') {
      await processRefund(payload);
    }
  }

  res.json({ received: true });
});

Python / Flask

@app.route('/webhook', methods=['POST'])
def webhook():
    data = request.json

    if data['event'] == 'request.decided':
        if data['status'] == 'approved':
            process_refund(data['payload'])

    return {'received': True}

Webhook logs

View webhook delivery status and retry history in the request detail page. You can see:

  • Delivery status (pending, delivered, failed)
  • Response status code
  • Number of attempts
  • Last error message
  • Retry webhook manually