Skip to main content

Overview

Webhooks allow you to receive real-time notifications when events occur in Rowbase. Instead of polling the API, Rowbase pushes updates to your endpoint.

Setting Up Webhooks

Create a Webhook

  1. Go to Settings → Webhooks
  2. Click Create Webhook
  3. Enter your endpoint URL
  4. Select which events to subscribe to
  5. Click Create

Webhook URL Requirements

Your endpoint must:
  • Use HTTPS (HTTP not allowed for security)
  • Respond with 2xx status within 30 seconds
  • Accept POST requests with JSON body

Events

Available Events

EventDescription
dataset.createdA new dataset was created
dataset.updatedDataset metadata was updated
dataset.deletedA dataset was deleted
dataset.data.addedRows were added to a dataset
dataset.data.updatedRows were modified
dataset.data.deletedRows were deleted
operation.createdAn operation was added
operation.updatedAn operation was modified
operation.deletedAn operation was removed
project.createdA new project was created
project.updatedProject settings were changed
project.deletedA project was deleted

Event Payload

All webhook events follow this structure:
{
  "id": "evt_xxx",
  "type": "dataset.data.added",
  "created_at": "2024-01-15T10:30:00Z",
  "data": {
    "dataset_id": "ds_xxx",
    "dataset_name": "Customers",
    "project_id": "proj_xxx",
    "rows_affected": 5,
    "triggered_by": {
      "type": "user",
      "id": "user_xxx",
      "email": "[email protected]"
    }
  }
}

Verifying Webhooks

Signature Verification

Each webhook request includes a signature header for verification:
X-Rowbase-Signature: sha256=abc123...
Verify the signature to ensure the request came from Rowbase:
const crypto = require('crypto');

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

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(`sha256=${expected}`)
  );
}

// In your webhook handler
app.post('/webhooks/rowbase', (req, res) => {
  const signature = req.headers['x-rowbase-signature'];
  const isValid = verifyWebhook(
    JSON.stringify(req.body),
    signature,
    process.env.ROWBASE_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook
  console.log('Event:', req.body.type);
  res.status(200).send('OK');
});

Retry Policy

If your endpoint doesn’t respond with a 2xx status, Rowbase retries with exponential backoff:
AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours
68 hours
After 6 failed attempts, the webhook is marked as failing. You’ll receive an email notification.

Testing Webhooks

Test Events

Send test events from the webhook settings page:
  1. Go to Settings → Webhooks
  2. Click on your webhook
  3. Click Send Test Event
  4. Choose an event type
  5. View the response

Local Development

Use a tunnel service to test webhooks locally:
# Using ngrok
ngrok http 3000

# Your webhook URL becomes:
# https://abc123.ngrok.io/webhooks/rowbase

Webhook Logs

View recent webhook deliveries:
  1. Go to Settings → Webhooks
  2. Click on a webhook
  3. View the Delivery Log
Each log entry shows:
  • Event type and timestamp
  • Request payload
  • Response status and body
  • Delivery attempts and timing

Best Practices

Return a 200 response immediately, then process the event asynchronously. This prevents timeouts.
Webhooks may be delivered more than once. Use the event id to deduplicate.
Always verify the webhook signature to ensure requests are authentic.
For high-volume webhooks, push events to a message queue for reliable processing.

Example: Sync to Database

app.post('/webhooks/rowbase', async (req, res) => {
  // Verify signature (see above)

  const event = req.body;

  switch (event.type) {
    case 'dataset.data.added':
      // Fetch the new data
      const data = await rowbase.datasets.getData(
        event.data.dataset_id,
        { limit: event.data.rows_affected }
      );

      // Insert into your database
      await db.insert('synced_data', data.rows);
      break;

    case 'dataset.data.deleted':
      // Remove from your database
      await db.delete('synced_data', {
        rowbase_ids: event.data.row_ids
      });
      break;
  }

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