Documentation

Standard webhooks

For workflows without an event name, ModelRiver sends the complete AI response to your webhook endpoint immediately after processing.

How standard webhooks work

For workflows without an event_name, ModelRiver sends the complete AI response to your webhook endpoint immediately after processing. This is a simple fire-and-forget pattern: your backend receives the result and can process it as needed.

Webhook payload structure

JSON
1{
2 "type": "task.completed",
3 "workflow": "customer-support-summary",
4 "status": "success",
5 "channel_id": "550e8400-e29b-41d4-a716-446655440000",
6 "data": {
7 "summary": "Customer requested refund for order #12345...",
8 "sentiment": "negative",
9 "category": "billing"
10 },
11 "meta": {
12 "provider": "openai",
13 "model": "gpt-4o",
14 "tokens": {
15 "prompt": 245,
16 "completion": 89,
17 "total": 334
18 },
19 "duration_ms": 2341,
20 "attempts": [
21 {
22 "provider": "openai",
23 "model": "gpt-4o",
24 "duration_ms": 2341,
25 "success": true
26 }
27 ]
28 },
29 "customer_data": {
30 "user_id": "user_789",
31 "session_id": "sess_abc123"
32 },
33 "timestamp": "2026-01-05T12:34:56.789Z"
34}

Headers sent with webhooks

HeaderDescription
mr-signatureHMAC-SHA256 signature of the payload
mr-timestampUnix timestamp when the webhook was sent
mr-channel-idUnique identifier for this request
content-typeAlways application/json

Integration examples

Node.js (Express)

JAVASCRIPT
1app.post('/webhooks/ai', (req, res) => {
2 const { type, data, customer_data } = req.body;
3
4 // Your business logic here
5 console.log('AI completed:', data);
6
7 res.status(200).json({ received: true });
8});

Python (Flask)

PYTHON
1@app.route('/webhooks/ai', methods=['POST'])
2def handle_webhook():
3 payload = request.json
4 event_type = payload['type']
5 data = payload['data']
6
7 # Your business logic here
8 print(f'AI completed: {data}')
9
10 return jsonify({'received': True}), 200

Next steps