Webhooks
Webhooks let you receive real-time notifications when videos finish processing, so you don't have to poll the API.
Register Webhook
POST /callbacks
bash
curl -X POST https://api.sketchpen.app/api/v1/callbacks \
-H "X-Api-Key: sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook",
"event": "video.completed"
}'Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| `url` | string | Yes | HTTPS URL to receive webhook |
| `event` | string | Yes | Event type to subscribe to |
Response
json
{
"id": "uuid",
"user_id": "uuid",
"url": "https://your-server.com/webhook",
"event": "video.completed",
"secret": "whsec_abc123...",
"is_active": true,
"created_at": "2024-01-01T00:00:00Z"
}โ ๏ธ Save the secret
The secret field is returned when you query or create webhooks. Use it to verify webhook payloads.
List Webhooks
GET /callbacks
bash
curl https://api.sketchpen.app/api/v1/callbacks \ -H "X-Api-Key: sk_live_..."
Response:
json
[
{
"id": "uuid",
"user_id": "uuid",
"url": "https://your-server.com/webhook",
"event": "video.completed",
"secret": "whsec_abc123...",
"is_active": true,
"created_at": "2024-01-01T00:00:00Z"
}
]Delete Webhook
DELETE /callbacks/{id}
bash
curl -X DELETE https://api.sketchpen.app/api/v1/callbacks/uuid \ -H "X-Api-Key: sk_live_..."
Returns 204 No Content on success.
Event Types
| Event | Description |
|---|---|
| `video.completed` | Video generation completed successfully |
| `video.failed` | Video generation failed |
Webhook Payload
When an event occurs, a POST request is sent to your URL:
json
{
"event": "video.completed",
"video_id": "uuid",
"data": {
"id": "uuid",
"status": "completed",
"prompt": "...",
"video_url": "https://...",
"audio_url": "https://...",
"thumbnail_url": "https://...",
"created_at": "2024-01-01T00:00:00.000000",
"updated_at": "2024-01-01T00:00:05.000000"
},
"created_at": 1711234567
}Verifying Signatures
Verify the webhook using the X-Sketchpen-Signature and X-Sketchpen-Timestamp headers. The signature is a SHA-256 HMAC of the timestamp concatenated with the raw string payload.
python
import hmac
import hashlib
def verify_signature(payload_str: str, signature_header: str, timestamp_header: str, secret: str) -> bool:
message = f"{timestamp_header}.{payload_str}"
expected = hmac.new(
secret.encode('utf-8'),
message.encode('utf-8'),
hashlib.sha256
).hexdigest()
expected_sig = f"sha256={expected}"
return hmac.compare_digest(expected_sig, signature_header)javascript
const crypto = require('crypto');
function verifySignature(payloadStr, signatureHeader, timestampHeader, secret) {
const message = `${timestampHeader}.${payloadStr}`;
const expected = crypto
.createHmac('sha256', secret)
.update(message)
.digest('hex');
const expectedSig = `sha256=${expected}`;
return crypto.timingSafeEqual(
Buffer.from(signatureHeader),
Buffer.from(expectedSig)
);
}โน๏ธ Retry policy
Failed webhooks (non-2xx response) are retried up to 3 times with exponential backoff.