> ## Documentation Index
> Fetch the complete documentation index at: https://flows-docs.edges.run/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks & Callbacks

> Receive real-time notifications when flows complete

## Overview

Instead of polling for results, you can configure webhooks to receive automatic notifications when your flows complete. When you provide a `callback` configuration in your request, Edges will send a POST request to your specified URL with the results.

<Note>
  For action callbacks (outside of Flows), refer to the [Managing Callbacks](https://docs.edges.run/v1/runs/callbacks) documentation in the main Edges docs.
</Note>

## Setting up callbacks

Include a `callback` object in your flow run request:

```json theme={null}
{
  "inputs": [...],
  "callback": {
    "url": "https://your-app.com/webhook",
    "headers": {
      "Authorization": "Bearer your-secret-token"
    },
    "on": "all"
  }
}
```

| Field     | Type   | Required | Description                                                                                                                                                |
| --------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`     | string | Yes      | The URL where Edges will send webhook notifications                                                                                                        |
| `headers` | object | No       | Custom headers to include in the webhook request (e.g., for authentication)                                                                                |
| `on`      | string | No       | When to receive callbacks: `"all"` (default) sends callbacks as outputs are generated, `"final"` sends a single callback when the flow completes or errors |

<Tip>
  Always include an authentication header in your callback configuration to secure your webhook endpoint and verify that requests are coming from Edges.
</Tip>

## Webhook payload

When a flow completes (or reaches milestones), Edges sends this payload:

```typescript theme={null}
FlowWebhookPayload = {
  flow_run: {
    flow_run_uid: string    // Unique identifier for the flow run
    step_uid: string        // The step that triggered this callback
    status: string          // Current status of the flow run
  }
  error?: any               // Error details if the flow failed
  results_count?: number    // Number of results returned
  results?: any[]           // Array of result objects
}
```

**Example payload:**

```json theme={null}
{
  "flow_run": {
    "flow_run_uid": "550e8400-e29b-41d4-a716-446655440000",
    "step_uid": "linkedin-extract-people",
    "status": "SUCCEEDED"
  },
  "results_count": 25,
  "results": [
    {
      "linkedin_profile_url": "https://linkedin.com/in/example",
      "first_name": "John",
      "last_name": "Doe",
      "headline": "Software Engineer at Example Corp"
    }
    // ... more results
  ]
}
```

## Status values

The `status` field in the webhook payload can have the following values:

| Status              | Description                                      |
| ------------------- | ------------------------------------------------ |
| `CREATED`           | Flow run has been created                        |
| `QUEUED`            | Flow run is queued for execution                 |
| `RUNNING`           | Flow run is currently executing                  |
| `SUCCEEDED`         | Flow run completed successfully                  |
| `FAILED`            | Flow run failed                                  |
| `PARTIAL_SUCCEEDED` | Flow run partially succeeded (some items failed) |

## Handling webhooks

Here's an example of how to handle flow webhook payloads in your application:

<CodeGroup>
  ```python Python (Flask) theme={null}
  from flask import Flask, request, jsonify

  app = Flask(__name__)

  @app.route('/webhook', methods=['POST'])
  def handle_webhook():
      # Verify the request (check your auth header)
      auth_header = request.headers.get('Authorization')
      if auth_header != 'Bearer your-secret-token':
          return jsonify({'error': 'Unauthorized'}), 401
      
      payload = request.json
      flow_run = payload['flow_run']
      
      print(f"Flow {flow_run['flow_run_uid']} - Step {flow_run['step_uid']}")
      print(f"Status: {flow_run['status']}")
      
      if flow_run['status'] == 'FAILED':
          print(f"Error: {payload.get('error')}")
      elif payload.get('results'):
          print(f"Received {payload.get('results_count', len(payload['results']))} results")
          for result in payload['results']:
              # Process each result
              print(f"Result: {result}")
      
      return jsonify({'status': 'received'}), 200
  ```

  ```javascript Node.js (Express) theme={null}
  const express = require('express');
  const app = express();

  app.use(express.json());

  app.post('/webhook', (req, res) => {
    // Verify the request (check your auth header)
    const authHeader = req.headers['authorization'];
    if (authHeader !== 'Bearer your-secret-token') {
      return res.status(401).json({ error: 'Unauthorized' });
    }

    const payload = req.body;
    const { flow_run_uid, step_uid, status } = payload.flow_run;

    console.log(`Flow ${flow_run_uid} - Step ${step_uid}`);
    console.log(`Status: ${status}`);

    if (status === 'FAILED') {
      console.log('Error:', payload.error);
    } else if (payload.results) {
      console.log(`Received ${payload.results_count || payload.results.length} results`);
      payload.results.forEach(result => {
        // Process each result
        console.log('Result:', result);
      });
    }

    res.status(200).json({ status: 'received' });
  });

  app.listen(3000);
  ```
</CodeGroup>

## Best practices

<AccordionGroup>
  <Accordion icon="shield" title="Secure your webhook endpoint">
    Always use HTTPS for your webhook URL and include an authentication header in your callback configuration. Verify this header in your webhook handler to ensure requests are coming from Edges.
  </Accordion>

  <Accordion icon="bolt" title="Respond quickly">
    Your webhook endpoint should respond with a 2xx status code within a few seconds. If you need to do heavy processing, acknowledge the webhook first and process asynchronously.
  </Accordion>

  <Accordion icon="rotate" title="Handle retries gracefully">
    Edges may retry failed webhook deliveries. Make your webhook handler idempotent by checking if you've already processed a given `flow_run_uid`.
  </Accordion>

  <Accordion icon="triangle-exclamation" title="Handle errors">
    Always check the `status` field and handle error cases. If `status` is `FAILED`, check the `error` field for details about what went wrong.
  </Accordion>
</AccordionGroup>

<Warning>
  Webhook delivery is best-effort. For critical workflows, we recommend also polling the [Get Flow Run](/api/runs/get) endpoint as a fallback to ensure you don't miss any results.
</Warning>
