Webhooks
Receive real-time notifications when events occur.
Overview
Webhooks allow you to:
- Get instant event notifications
- Automate workflows
- Sync with external systems
- Build reactive integrations
Plan Requirement
Webhook access requires a plan that includes API features.
How Webhooks Work
- You configure an endpoint URL
- Select events to subscribe to
- When events occur, we send HTTP POST requests
- Your server processes the payload
- You respond with 2xx status
Available Events
| Event | Description |
|---|---|
photo_request.created | New photo request created |
photo_request.first_viewed | Request viewed for the first time |
photo_submission.created | Photos submitted (Permanent Links) |
photo_request.submitted | One-time request completed |
photo_request.expired | Request expired without submission |
photo_submission.dropbox_synced | Photo synced to Dropbox with shared link |
Creating a Webhook
Steps
- Go to Webhooks in the sidebar
- Click Create Webhook
- Enter a descriptive name
- Provide your endpoint URL
- Select events to subscribe
- Toggle Active (default: on)
- Click Create
Endpoint Requirements
| Requirement | Value |
|---|---|
| Protocol | HTTPS required |
| Accessibility | Public internet |
| Response | 2xx status code |
| Timeout | 30 seconds max |
Private Networks
Private and internal network addresses (localhost, 10.x.x.x, 192.168.x.x) are not allowed.
Webhook Payload
Request Format
http
POST /your-endpoint HTTP/1.1
Host: your-server.com
Content-Type: application/json
X-Webhook-Signature: sha256=abc123...
X-Webhook-ID: wh_123456
X-Webhook-Timestamp: 1609459200Payload Structure
json
{
"event": "photo_request.submitted",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"id": "req_abc123",
"type": "one_time",
"instructions": "Send photos of the vehicle",
"photos": [
{
"id": "photo_xyz789",
"url": "https://...",
"slot_instructions": "Front view",
"metadata": {
"gps_lat": 45.1234,
"gps_lng": 12.5678,
"captured_at": "2024-01-15T10:28:00Z"
}
}
],
"submitted_at": "2024-01-15T10:30:00Z"
}
}Signature Verification
Why Verify
Verify webhook signatures to ensure:
- Request came from Visiono
- Payload wasn't tampered with
- Prevent replay attacks
Signature Header
X-Webhook-Signature: sha256=abc123def456...Verification Steps
php
// PHP example
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'];
$secret = 'your-webhook-secret';
$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}javascript
// Node.js example
const crypto = require('crypto');
const payload = JSON.stringify(req.body);
const signature = req.headers['x-webhook-signature'];
const secret = process.env.WEBHOOK_SECRET;
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) {
return res.status(401).send('Invalid signature');
}Managing Webhooks
Test Webhook
Send a test event:
- Click Test on the webhook
- Confirm the action
- Check response status
- View in logs if failed
View Logs
See delivery history:
- Click Logs on the webhook
- View recent deliveries
- Check status and response
- Debug failures
Log Details
Each log shows:
- Event type
- Timestamp
- Response status
- Response time
- Request/response body (for debugging)
Regenerate Secret
Get a new signing secret:
- Click Regenerate Secret
- Confirm the action
- Copy new secret immediately
- Update your server
Update Server First
After regenerating, the old secret stops working. Update your verification code before regenerating.
Deactivate Webhook
Temporarily stop receiving events:
- Click Deactivate
- Confirm the action
- Events are no longer sent
- Reactivate when ready
Delete Webhook
Permanently remove:
- Click Delete
- Confirm the action
- All logs are deleted
Retry Policy
Automatic Retries
Failed deliveries are retried:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
Failure Criteria
A delivery fails if:
- Connection timeout (30s)
- Non-2xx response
- Network error
- SSL error
After Max Retries
If all retries fail:
- Event is marked as failed
- Logged for review
- No further attempts
Best Practices
Endpoint Design
- Respond quickly (< 5 seconds)
- Process async if needed
- Return 2xx immediately
- Handle idempotency
Error Handling
javascript
// Recommended pattern
app.post('/webhook', async (req, res) => {
// Verify signature first
if (!verifySignature(req)) {
return res.status(401).send('Invalid');
}
// Acknowledge immediately
res.status(200).send('OK');
// Process async
processWebhookAsync(req.body);
});Idempotency
Events may be sent more than once. Handle duplicates:
javascript
// Check if already processed
const eventId = req.headers['x-webhook-id'];
if (await isProcessed(eventId)) {
return res.status(200).send('Already processed');
}
// Process and mark as handled
await processEvent(req.body);
await markProcessed(eventId);Monitoring
- Log all incoming webhooks
- Alert on failures
- Monitor response times
- Track event volumes
Troubleshooting
Not Receiving Events
- Verify webhook is active
- Check endpoint URL is correct
- Ensure HTTPS is working
- Verify server is accessible
- Check selected events
Signature Mismatch
- Use the correct secret
- Compare full payload (not parsed)
- Check for encoding issues
- Verify HMAC algorithm (SHA256)
Timeouts
- Reduce processing time
- Acknowledge immediately
- Process asynchronously
- Check server resources
View Failed Deliveries
- Go to webhook logs
- Filter by status (failed)
- View request/response details
- Fix and retest
Webhook Limits
Per Plan
| Plan | Max Webhooks |
|---|---|
| Professional | 5 webhooks |
| Enterprise | Unlimited |
Rate Limits
| Limit | Value |
|---|---|
| Events per minute | 100 |
| Payload size | 1 MB |
Related Pages
- API Keys - API authentication
- API Reference - Full API docs
- Integrations - Pre-built integrations
