> ## Documentation Index
> Fetch the complete documentation index at: https://help-center.relyable.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Receive real-time notifications when events occur in Relyable

Webhooks allow your application to receive real-time notifications when events occur in Relyable, such as test completions, score drops, or critical failures.

## Setting Up Webhooks

<Steps>
  <Step title="Navigate to Workspace Settings">
    In your Relyable dashboard, go to **Settings** → **Webhooks**
  </Step>

  <Step title="Add Webhook URL">
    Click **Add Webhook** and enter your endpoint URL. This should be a publicly accessible HTTPS endpoint.
  </Step>

  <Step title="Select Events">
    Choose which events you want to receive:

    * Test run completed
    * Test run failed
    * Agent score dropped
    * Critical test case failed
  </Step>

  <Step title="Save and Get Secret">
    Save your webhook. You'll receive a signing secret to verify webhook authenticity.
  </Step>
</Steps>

## Webhook Events

### test\_run.completed

Sent when a test run finishes successfully:

```json theme={null}
{
  "event": "test_run.completed",
  "timestamp": "2025-01-16T15:38:00Z",
  "data": {
    "test_run_id": "run_xyz789",
    "agent_id": "agent_abc123",
    "agent_name": "Real Estate Inbound Agent",
    "score": 73.5,
    "previous_score": 68.2,
    "total_calls": 5,
    "passed_test_cases": 15,
    "failed_test_cases": 5,
    "duration_seconds": 420,
    "scenarios_tested": ["scenario_buying_1", "scenario_selling_1"],
    "view_url": "https://app.relyable.ai/agents/agent_abc123/runs/run_xyz789"
  }
}
```

### test\_run.failed

Sent when a test run fails to complete:

```json theme={null}
{
  "event": "test_run.failed",
  "timestamp": "2025-01-16T15:40:00Z",
  "data": {
    "test_run_id": "run_xyz789",
    "agent_id": "agent_abc123",
    "error": "Phone number not reachable",
    "calls_completed": 2,
    "calls_failed": 3
  }
}
```

### agent.score\_dropped

Sent when an agent's score drops below a threshold:

```json theme={null}
{
  "event": "agent.score_dropped",
  "timestamp": "2025-01-16T16:00:00Z",
  "data": {
    "agent_id": "agent_abc123",
    "agent_name": "Real Estate Inbound Agent",
    "current_score": 62.5,
    "previous_score": 78.2,
    "threshold": 70.0,
    "drop_percentage": 20.1,
    "period": "last_24_hours",
    "view_url": "https://app.relyable.ai/agents/agent_abc123"
  }
}
```

### test\_case.critical\_failure

Sent when a critical test case fails:

```json theme={null}
{
  "event": "test_case.critical_failure",
  "timestamp": "2025-01-16T16:05:00Z",
  "data": {
    "test_case_id": "tc_emergency_routing",
    "test_case_name": "Agent must route emergency calls",
    "agent_id": "agent_abc123",
    "call_id": "call_def456",
    "failure_reason": "Agent did not transfer emergency call within 10 seconds",
    "call_recording_url": "https://app.relyable.ai/calls/call_def456",
    "transcript": "..."
  }
}
```

## Verifying Webhooks

All webhooks include a signature in the `X-Relyable-Signature` header for security.

### Signature Verification (Node.js)

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhooks/relyable', (req, res) => {
  const signature = req.headers['x-relyable-signature'];
  const secret = process.env.RELYABLE_WEBHOOK_SECRET;
  
  if (!verifyWebhook(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  // Process webhook
  const { event, data } = req.body;
  
  switch (event) {
    case 'test_run.completed':
      handleTestComplete(data);
      break;
    case 'agent.score_dropped':
      alertTeam(data);
      break;
    // ... handle other events
  }
  
  res.status(200).send('OK');
});
```

### Signature Verification (Python)

```python theme={null}
import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected_signature = hmac.new(
        secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(signature, expected_signature)

# In your webhook handler
@app.route('/webhooks/relyable', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Relyable-Signature')
    secret = os.environ.get('RELYABLE_WEBHOOK_SECRET')
    
    if not verify_webhook(request.data, signature, secret):
        return 'Invalid signature', 401
    
    data = request.json
    event = data['event']
    
    if event == 'test_run.completed':
        handle_test_complete(data['data'])
    elif event == 'agent.score_dropped':
        alert_team(data['data'])
    
    return 'OK', 200
```

## Webhook Retry Logic

If your endpoint returns a non-200 status code, Relyable will retry:

| Attempt | Delay      |
| ------- | ---------- |
| 1       | Immediate  |
| 2       | 1 minute   |
| 3       | 5 minutes  |
| 4       | 15 minutes |
| 5       | 1 hour     |

After 5 failed attempts, the webhook is marked as failed and you'll receive an email notification.

## Testing Webhooks

Use the **Send Test Event** button in your webhook settings to send a test payload to your endpoint. This helps you verify your integration before real events occur.

## Best Practices

<AccordionGroup>
  <Accordion title="Respond Quickly">
    Return a 200 status code immediately. Process the webhook asynchronously to avoid timeouts.
  </Accordion>

  <Accordion title="Always Verify Signatures">
    Never trust webhook payloads without verifying the signature. This prevents spoofing attacks.
  </Accordion>

  <Accordion title="Handle Duplicate Events">
    Due to retries, you might receive the same event multiple times. Use the event ID to deduplicate.
  </Accordion>

  <Accordion title="Use HTTPS">
    Webhook URLs must use HTTPS. Plain HTTP is not supported for security reasons.
  </Accordion>
</AccordionGroup>

## Debugging Webhooks

View webhook delivery logs in your workspace settings:

* Request payload
* Response status code
* Response body
* Delivery timestamp
* Retry attempts

This helps you debug integration issues quickly.
