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

# Webhooks

Webhooks allow you to receive real-time notifications when events occur in your G-Tateth account.

## Overview

Instead of polling the API for changes, webhooks push events to your application in real-time. This is more efficient and provides better user experience.

## Creating a Webhook

Create a webhook through the API:

```bash theme={null}
curl -X POST https://api.g-tateth.com/api/v1/webhooks \
  -H "Authorization: Bearer sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Webhook",
    "url": "https://myapp.com/webhooks/g-tateth",
    "events": ["conversation.created", "customer.updated"],
    "retryPolicy": {
      "maxRetries": 3,
      "backoffStrategy": "exponential"
    }
  }'
```

Or use the Developer Console in your dashboard.

## Supported Events

### Conversation Events

* `conversation.created` - New conversation created
* `conversation.updated` - Conversation updated
* `conversation.assigned` - Conversation assigned to agent
* `conversation.closed` - Conversation closed

### Customer Events

* `customer.created` - New customer created
* `customer.updated` - Customer updated

### Message Events

* `message.sent` - Message sent
* `message.received` - Message received

### User Events

* `user.created` - New user created
* `user.updated` - User updated

### Call Events

* `call.initiated` - Call has been initiated
* `call.ringing` - Call is ringing
* `call.answered` - Call has been answered
* `call.completed` - Call has completed
* `call.failed` - Call failed
* `call.recording.available` - Call recording is available

## Webhook Payload

When an event occurs, we'll send a POST request to your webhook URL:

```json theme={null}
{
  "event": "conversation.created",
  "timestamp": "2024-01-01T12:00:00Z",
  "data": {
    "_id": "...",
    "subject": "Customer inquiry",
    "status": "open",
    "channel": "email",
    "customerId": {
      "profile": {
        "firstName": "John",
        "lastName": "Doe",
        "email": "john@example.com"
      }
    }
  }
}
```

## Signature Verification

Each webhook request includes an `X-Webhook-Signature` header for verification. Always verify signatures to ensure requests are from G-Tateth.

### JavaScript/Node.js

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

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

// Express.js example
app.post('/webhooks/g-tateth', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.WEBHOOK_SECRET;
  
  if (!verifyWebhook(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }
  
  const event = JSON.parse(req.body);
  // Process event...
  
  res.status(200).send('OK');
});
```

### Python

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

def verify_webhook(payload, signature, secret):
    hash = hmac.new(
        secret.encode('utf-8'),
        json.dumps(payload).encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    
    expected_signature = f'sha256={hash}'
    
    return hmac.compare_digest(signature, expected_signature)

# Flask example
@app.route('/webhooks/g-tateth', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature')
    secret = os.environ.get('WEBHOOK_SECRET')
    
    if not verify_webhook(request.json, signature, secret):
        return 'Invalid signature', 401
    
    event = request.json
    # Process event...
    
    return 'OK', 200
```

## Retry Policy

Webhooks are automatically retried on failure:

* **Max Retries**: Configurable (default: 3)
* **Backoff Strategy**: `linear` or `exponential` (default: exponential)
* **Exponential**: 2s, 4s, 8s, 16s...
* **Linear**: 5s, 10s, 15s...

### Configuring Retry Policy

```json theme={null}
{
  "name": "My Webhook",
  "url": "https://myapp.com/webhooks",
  "events": ["conversation.created"],
  "retryPolicy": {
    "maxRetries": 5,
    "backoffStrategy": "exponential"
  }
}
```

## Testing Webhooks

Test your webhook endpoint:

```bash theme={null}
curl -X POST https://api.g-tateth.com/api/v1/webhooks/{webhook_id}/test \
  -H "Authorization: Bearer sk_live_your_api_key"
```

This sends a test event to your webhook URL.

## Delivery Logs

View webhook delivery history:

```bash theme={null}
curl https://api.g-tateth.com/api/v1/webhooks/{webhook_id}/logs \
  -H "Authorization: Bearer sk_live_your_api_key"
```

## Best Practices

### 1. Always Verify Signatures

Never trust requests without signature verification:

```javascript theme={null}
if (!verifyWebhook(payload, signature, secret)) {
  return res.status(401).send('Invalid signature');
}
```

### 2. Respond Quickly

Return 200 within 5 seconds. Process events asynchronously:

```javascript theme={null}
app.post('/webhooks/g-tateth', (req, res) => {
  // Acknowledge immediately
  res.status(200).send('OK');
  
  // Process asynchronously
  processWebhookAsync(req.body);
});
```

### 3. Handle Duplicates

Events may be delivered multiple times. Make handlers idempotent:

```javascript theme={null}
const processedEvents = new Set();

function handleWebhook(event) {
  if (processedEvents.has(event.id)) {
    return; // Already processed
  }
  
  processEvent(event);
  processedEvents.add(event.id);
}
```

### 4. Use HTTPS

Webhooks must use HTTPS URLs. HTTP is not supported for security reasons.

### 5. Idempotency

Make your webhook handlers idempotent - processing the same event multiple times should have the same effect:

```javascript theme={null}
async function handleConversationCreated(event) {
  const conversationId = event.data._id;
  
  // Check if already processed
  const existing = await db.conversations.findOne({ id: conversationId });
  if (existing) {
    return; // Already processed
  }
  
  // Process event
  await db.conversations.create(event.data);
}
```

## Troubleshooting

### Webhook Not Receiving Events

1. Check webhook is active
2. Verify URL is accessible (HTTPS required)
3. Check delivery logs for errors
4. Verify signature verification is working

### Webhook Failing

1. Check response time (must be \< 5 seconds)
2. Verify endpoint returns 200 status
3. Check server logs for errors
4. Review retry policy settings

## Resources

* [Webhooks API Reference](/api-reference/webhooks)
* [Best Practices](/guides/best-practices)
