Skip to main content
Webhooks notify your server when important events occur in Shortkit, such as content finishing processing or data exports completing.

Overview

When an event occurs:
  1. shortkit sends an HTTP POST to your endpoint
  2. Request includes event data and signature
  3. Your server verifies and processes the event

Setting up webhooks

Create a webhook endpoint

Your endpoint must:
  • Accept POST requests
  • Use HTTPS (required)
  • Return 2xx status within 30 seconds
  • Verify the signature

Register in Admin Portal

  1. Go to Settings → Webhooks
  2. Click Add Webhook
  3. Enter your endpoint URL
  4. Select events to receive
  5. Copy the signing secret

Register via API

curl -X POST https://api.shortkit.dev/v1/webhooks \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://yourserver.com/webhooks/shortkit",
    "events": ["content.ready", "content.errored"],
    "description": "Production webhook"
  }'
Response:
{
  "data": {
    "webhookId": "whk_abc123",
    "url": "https://yourserver.com/webhooks/shortkit",
    "events": ["content.ready", "content.errored"],
    "secret": "whsec_xyz789...",
    "status": "active"
  }
}
The signing secret is shown only once. Store it securely.

Available events

Content events

EventTrigger
content.readyContent finished processing and is available
content.erroredContent processing failed
export.readyData export completed

Webhook payload

Format

{
  "event": "content.ready",
  "data": {
    "contentId": "cnt_abc123",
    "title": "My Video",
    "duration": 45.2,
    "status": "ready"
  },
  "timestamp": "2024-02-04T12:00:00Z",
  "webhookId": "whk_xyz789"
}

Headers

HeaderDescription
Content-Typeapplication/json
X-Shortform-SignatureHMAC-SHA256 signature
X-Shortform-TimestampEvent timestamp
X-Shortform-Webhook-IDWebhook configuration ID
X-Shortform-Delivery-IDUnique delivery attempt ID

Signature verification

Always verify webhook signatures to ensure requests are from shortkit.

Verification process

  1. Extract timestamp and signature from headers
  2. Construct the signed payload: {timestamp}.{body}
  3. Compute expected signature using your secret
  4. Compare signatures using timing-safe comparison

Implementation examples

const crypto = require('crypto');

function verifyWebhook(req, secret) {
  const signature = req.headers['x-shortform-signature'];
  const timestamp = req.headers['x-shortform-timestamp'];
  const body = req.rawBody; // Raw request body string

  // Construct signed payload
  const signedPayload = `${timestamp}.${body}`;

  // Compute expected signature
  const expected = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');

  const expectedSignature = `sha256=${expected}`;

  // Timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express middleware
app.post('/webhooks/shortkit', express.raw({ type: 'application/json' }), (req, res) => {
  if (!verifyWebhook(req, process.env.SHORTKIT_WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Process event...

  res.status(200).send('OK');
});

Retry policy

Failed webhook deliveries are retried automatically:
AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
624 hours
A delivery is considered failed if:
  • Connection timeout (10 seconds)
  • Non-2xx response code
  • Response not received within 30 seconds
After all retries are exhausted, the delivery is marked as failed.

Event handling

Idempotency

Events may be delivered more than once. Handle duplicates using the X-Shortform-Delivery-ID:
const processedDeliveries = new Set();

app.post('/webhooks/shortkit', (req, res) => {
  const deliveryId = req.headers['x-shortform-delivery-id'];

  if (processedDeliveries.has(deliveryId)) {
    return res.status(200).send('Already processed');
  }

  // Process event...

  processedDeliveries.add(deliveryId);
  res.status(200).send('OK');
});

Async processing

For long-running tasks, acknowledge immediately and process asynchronously:
app.post('/webhooks/shortkit', async (req, res) => {
  // Verify signature...

  // Acknowledge immediately
  res.status(200).send('OK');

  // Process asynchronously
  const event = JSON.parse(req.body);
  await queue.add('process-webhook', event);
});

Testing webhooks

Send test event

From the Admin Portal:
  1. Go to Settings → Webhooks
  2. Click on your webhook
  3. Click Send Test Event
  4. Select event type
  5. View response

Local development

Use a tunnel service for local testing:
# Using ngrok
ngrok http 3000

# Register the ngrok URL as your webhook
# https://abc123.ngrok.io/webhooks/shortkit

Webhook logs

View delivery history:
  1. Go to Settings → Webhooks → [Your Webhook]
  2. See Recent Deliveries
  3. View request/response for each attempt

Managing webhooks

List webhooks

curl https://api.shortkit.dev/v1/webhooks \
  -H "Authorization: Bearer sk_live_your_secret_key"

Update webhook

curl -X PATCH https://api.shortkit.dev/v1/webhooks/whk_abc123 \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "events": ["content.ready", "content.errored", "export.ready"]
  }'

Disable webhook

curl -X PATCH https://api.shortkit.dev/v1/webhooks/whk_abc123 \
  -H "Authorization: Bearer sk_live_your_secret_key" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "disabled"
  }'

Delete webhook

curl -X DELETE https://api.shortkit.dev/v1/webhooks/whk_abc123 \
  -H "Authorization: Bearer sk_live_your_secret_key"

Rotate secret

curl -X POST https://api.shortkit.dev/v1/webhooks/whk_abc123/rotate-secret \
  -H "Authorization: Bearer sk_live_your_secret_key"

Next steps