Agent skill

SeaTable Webhooks Skill

Receive and verify SeaTable webhooks. Use when setting up SeaTable webhook handlers, debugging X-Seatable-Signature verification, or handling base change events (insert_row, modify_row, delete_row).

Install this skill

npx skills add hookdeck/webhook-skills --skill seatable-webhooks


When to Use This Skill

  • How do I receive SeaTable webhooks?
  • How do I verify the X-Seatable-Signature header?
  • Why is my SeaTable webhook signature verification failing?
  • How do I handle insert_row, modify_row and delete_row changes?
  • Why did SeaTable mark my webhook as invalid?

Verification (core)

SeaTable signs the raw request body with HMAC-SHA256, using the webhook's secret key as a UTF-8 string. The header is X-Seatable-Signature: sha256=<hex>.

The secret key is optional. If none is set on the webhook, SeaTable sends no signature header, so anyone who finds the URL can post to it. Always set a secret.

const crypto = require('crypto');

function verify(rawBody, signatureHeader, secret) {
  if (!signatureHeader || !secret) return false;
  const received = signatureHeader.replace(/^sha256=/, '').toLowerCase();
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  try {
    return crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
  } catch {
    return false; // length mismatch = invalid
  }
}

Read the body raw for any content type (express.raw({ type: '*/*' })) and parse JSON only after verification.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Common Event Types

Every delivery has event (currently always update) and data. What changed is in data.op_type:

data.op_typeTriggered When
insert_rowA row is added or duplicated (UI, form or API)
modify_rowA row's content changes; data.row_data holds column_name, value, old_value
delete_rowA row is deleted

SeaTable's docs list insert_row as the value, but one sample on the secret-key page shows create_row. The examples accept both. Structural changes (new columns, views, comments, row locks) send nothing. A multi-row paste in the web editor sends one webhook with an extra data.row_count.

Environment Variables

SEATABLE_WEBHOOK_SECRET=your_webhook_secret_here   # secret key set on the webhook

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 seatable --path /webhooks/seatable

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 4, 2026

View on GitHub →