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:
- Go to the Webhook page and create a new webhook key.
- On the Webhook page, create a new webhook key.
- Copy and save this key. It will be used as the
secret
for verifying Webhook signatures.
2. Steps to Integrate Webhooks
-
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.
-
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.
-
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:
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://pollo.ai/api-platform
// Signing process
const secretBytes = Buffer.from(secret, 'base64');
const computedSigBase64 = crypto
.createHmac('sha256', secretBytes)
.update(signedContent)
.digest('base64');
-
Signature Verification
Compare X-Webhook-Signature
with computedSigBase64
to ensure the message’s signature is correct. The verification code is as follows:
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");
}
-
Event Notification Structure
The structure of the event notification sent by the Webhook is as follows:
{
"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
.
-
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
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://pollo.ai/api-platform
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
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://pollo.ai/api-platform
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()