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

FieldTypeRequiredDescription
`url`stringYesHTTPS URL to receive webhook
`event`stringYesEvent 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

EventDescription
`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.

Need the raw text for your AI agent? View MDX ยท Full spec at /llms.txt