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

# Webhooks

> Learn how to integrate Pollo AI API’s Webhook service to receive secure, authenticated notifications for video generation task completions. 

To integrate our Webhook service into your system, you need to provide a Webhook URL, a specific endpoint where we will send notifications when a video generation task completes. Each notification requires a signature to verify the data’s security and authenticity.

## 1. Getting Your Secret Key

You need a **Secret** key for signature verification. Follow these steps to get it:

1. [Go to the Webhook page](https://api.pollo.ai/webhook) and create a new webhook key.
2. On the **Webhook** page, create a new webhook key.
3. Copy and save this key. It will be used as the `secret` for verifying Webhook signatures.

## 2. Steps to Integrate Webhooks

1. **Configure Your Webhook URL**
   In your video generation API request Post, provide your `webhookUrl`, for example:
   ```
     {
         "input": {}
         "webhookUrl": "https://url.to.your.app/api/pollo/webhook"
     }
   ```
   Please note that `input` is video generation parameters, which vary by model and should not be changed.

2. **Verify Webhook Signatures**
   Each Webhook message will include the following HTTP header, which you need to use to verify the authenticity of the message:
   * `X-Webhook-Id`：A unique identifier for the Webhook message.
   * `X-Webhook-Timestamp`：The timestamp of when the message was sent.
   * `X-Webhook-Signature`：A Base64 encoded signature that you need to use to verify that the message has not been tampered with.

3. **Signature Algorithm**
   The signature for the Webhook message is calculated using the HMAC-SHA-256 algorithm. Here’s how it works:

   * The content to be signed consists of  `webhook_id`、`webhook_timestamp` and the request `body`，each separated by `.`
   * Use the **Base64** encoded Secret along with the content to calculate the HMAC-SHA-256 signature.

   Code Implementation：

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

   // Get the fields from the Header and the request body
   const webhookId = "xxx";
   const webhookTimestamp = "xxx";
   const body = JSON.stringify({}); // Request body content

   // Build the content to be signed
   const signedContent = `${webhookId}.${webhookTimestamp}.${body}`;

   // Get the Secret（Base64 encoded）
   const secret = "xxx";  // Obtain from https://api.pollo.ai

   // Signing process
   const secretBytes = Buffer.from(secret, 'base64');
   const computedSigBase64 = crypto
     .createHmac('sha256', secretBytes)
     .update(signedContent)
     .digest('base64');
   ```

4. **Signature Verification**

   Compare `X-Webhook-Signature` with `computedSigBase64` to ensure the message's signature is correct. The verification code is as follows:

   ```javascript theme={null}
   const expectedSignatures = ['xxx'];  // Get `X-Webhook-Signature` from Header
   const computedSigBase64 = "xxx";  // The signature calculated above

   const isValid = expectedSignatures.some(expectedSig => {
     if (expectedSig.length !== computedSigBase64.length) {
         return false;
     }
     const expectedBuffer = Buffer.from(expectedSig, 'base64');
     const computedBuffer = Buffer.from(computedSigBase64, 'base64');
     return crypto.timingSafeEqual(expectedBuffer, computedBuffer);
   });

   if (!isValid) {
     // Invalid signature, reject processing
     console.log("Invalid signature");
   }
   ```

5. **Event Notification Structure**

   The structure of the event notification sent by the Webhook is as follows:

   ```json theme={null}
   {
     "taskId": "<string>",
     "status": "succeed/failed"
   }
   ```

   * `taskId`: A unique identifier for the task.
   * `status`: The status of the task, which can be either `succeed` or `failed`.

6. **Retry Mechanism**

   If the received Webhook notification shows a processing failure, the system will automatically retry. The retries will be performed at certain intervals, up to a maximum of 10 attempts. If all attempts fail, the system will stop retrying until you intervene manually.

## 3. Example Code

### 3.1 Using JavaScript to Integrate Webhook

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

http.createServer((req, res) => {
  const webhookId = req.headers['x-webhook-id'];
  const webhookTimestamp = req.headers['x-webhook-timestamp'];
  const signature = req.headers['x-webhook-signature'];
  let body = '';

  req.on('data', chunk => {
    body += chunk;
  });

  req.on('end', () => {
    // Obtain Secret
    const secret = "xxx"; // Obtain from https://api.pollo.ai
    const signedContent = `${webhookId}.${webhookTimestamp}.${body}`;

    // Calculate the signature
    const secretBytes = Buffer.from(secret, 'base64');
    const computedSigBase64 = crypto
      .createHmac('sha256', secretBytes)
      .update(signedContent)
      .digest('base64');

    // Verify the signature
    if (crypto.timingSafeEqual(Buffer.from(signature, 'base64'), Buffer.from(computedSigBase64, 'base64'))) {
      // Signature is valid, process the message
      const event = JSON.parse(body);
      if (event.status === 'succeed') {
        // Handle success event
        console.log('Task succeeded:', event.taskId);
      } else {
        // Handle success event
        console.log('Task failed:', event.taskId);
      }
    } else {
      // Signature verification failed, reject processing
      console.log('Invalid signature');
    }
    res.end('OK');
  });
}).listen(8080);
```

### 3.2 Using Python to Integrate Webhook

```python theme={null}
import hmac
import hashlib
import base64
from http.server import BaseHTTPRequestHandler, HTTPServer

class WebhookHandler(BaseHTTPRequestHandler):
    def do_POST(self):
        webhook_id = self.headers['X-Webhook-Id']
        webhook_timestamp = self.headers['X-Webhook-Timestamp']
        signature = self.headers['X-Webhook-Signature']
        content_length = int(self.headers['Content-Length'])
        body = self.rfile.read(content_length).decode('utf-8')

        # Get the Secret
        secret = "xxx"  # Obtain from https://api.pollo.ai
        signed_content = f"{webhook_id}.{webhook_timestamp}.{body}"

        # Calculate the signature
        secret_bytes = base64.b64decode(secret)
        computed_sig_base64 = base64.b64encode(
            hmac.new(secret_bytes, signed_content.encode('utf-8'), hashlib.sha256).digest()
        ).decode('utf-8')

        # Verify the signature
        if hmac.compare_digest(signature, computed_sig_base64):
            # Signature is valid, process the message
            event = json.loads(body)
            if event['status'] == 'succeed':
                print(f"Task succeeded: {event['taskId']}")
            else:
                print(f"Task failed: {event['taskId']}")
        else:
            print("Invalid signature")

        self.send_response(200)
        self.end_headers()

if __name__ == '__main__':
    server = HTTPServer(('localhost', 8080), WebhookHandler)
    server.serve_forever()
```
