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
secretis only returned once during creation. Store it securely to verify webhook signatures.
Available Events
Row Events
| Event | Description |
|---|---|
row.created | A new row was added to a table |
row.updated | A row was modified |
row.deleted | A row was removed |
Table Events
| Event | Description |
|---|---|
table.created | A new table was created |
table.updated | Table settings were modified |
table.deleted | A table was deleted |
Member Events
| Event | Description |
|---|---|
member.invited | Someone was invited to the org |
member.joined | Someone accepted an invitation |
member.removed | Someone 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
- Respond quickly - Return a 200 status within 30 seconds
- Process asynchronously - Queue long-running tasks
- Verify signatures - Always validate the
X-Webhook-Signatureheader - Handle duplicates - Use the event ID for idempotency
- Monitor failures - Check delivery history regularly