Webhooks

Receive real-time notifications when events happen

Webhooks allow you to receive HTTP POST requests when specific events occur in your organization.

Overview

When an event occurs (like a row being created), Vastal sends an HTTP POST request to your configured webhook URL with details about the event.

Create Webhook

POST /webhooks

Request Body:

{
  "name": "My Integration",
  "url": "https://your-app.com/webhooks/vastal",
  "events": [
    "row.created",
    "row.updated",
    "row.deleted"
  ]
}

Response:

{
  "success": true,
  "data": {
    "id": "whk_abc123",
    "name": "My Integration",
    "url": "https://your-app.com/webhooks/vastal",
    "events": ["row.created", "row.updated", "row.deleted"],
    "secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxx",
    "is_active": true
  }
}

Important: The secret is only returned once during creation. Store it securely to verify webhook signatures.

Available Events

Row Events

EventDescription
row.createdA new row was added to a table
row.updatedA row was modified
row.deletedA row was removed

Table Events

EventDescription
table.createdA new table was created
table.updatedTable settings were modified
table.deletedA table was deleted

Member Events

EventDescription
member.invitedSomeone was invited to the org
member.joinedSomeone accepted an invitation
member.removedSomeone was removed from the org

Webhook Payload

When an event occurs, we send a POST request with this structure:

{
  "event": "row.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "organization_id": "org_xyz",
  "data": {
    "table_id": "tbl_abc123",
    "table_name": "Contacts",
    "row_id": "row_001",
    "row_data": {
      "name": "John Doe",
      "email": "john@example.com"
    }
  }
}

Verifying Signatures

Every webhook request includes a signature header to verify authenticity.

Header:

X-Webhook-Signature: sha256=xxxxxxxxxxxxxxxxxxxxxxxxxx

Verification (Node.js):

import crypto from 'crypto';

function verifyWebhook(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return `sha256=${expectedSignature}` === signature;
}

// In your webhook handler
app.post('/webhooks/vastal', (req, res) => {
  const signature = req.headers['x-webhook-signature'];

  if (!verifyWebhook(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook
  const { event, data } = req.body;
  console.log(`Received event: ${event}`, data);

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

Verification (Python):

import hmac
import hashlib

def verify_webhook(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        json.dumps(payload).encode(),
        hashlib.sha256
    ).hexdigest()
    return f"sha256={expected}" == signature

Retry Policy

If your endpoint returns a non-2xx status code, we'll retry the webhook:

  • 1st retry: After 1 minute
  • 2nd retry: After 5 minutes
  • 3rd retry: After 30 minutes
  • 4th retry: After 2 hours
  • 5th retry: After 24 hours

After 5 failed attempts, the webhook is marked as failed and we stop retrying.

Viewing Delivery History

You can view recent deliveries for each webhook:

GET /webhooks/{webhook_id}/deliveries

Response:

{
  "success": true,
  "data": [
    {
      "id": "del_001",
      "event_type": "row.created",
      "status_code": 200,
      "duration_ms": 145,
      "success": true,
      "created_at": "2024-01-15T10:30:00Z"
    },
    {
      "id": "del_002",
      "event_type": "row.updated",
      "status_code": 500,
      "duration_ms": 3021,
      "success": false,
      "error_message": "Connection timeout",
      "created_at": "2024-01-15T09:15:00Z"
    }
  ]
}

Test Webhook

Send a test event to verify your endpoint is working:

POST /webhooks/{webhook_id}/test

Response:

{
  "success": true,
  "data": {
    "status_code": 200,
    "duration_ms": 145,
    "response_body": "OK"
  }
}

Best Practices

  1. Respond quickly - Return a 200 status within 30 seconds
  2. Process asynchronously - Queue long-running tasks
  3. Verify signatures - Always validate the X-Webhook-Signature header
  4. Handle duplicates - Use the event ID for idempotency
  5. Monitor failures - Check delivery history regularly