Webhooks
Event-driven integrations for real-time notifications.
Overview
Webhooks allow your application to receive real-time notifications when events occur in GoValid. Instead of polling the API, GoValid sends HTTP POST requests to your configured endpoint.
Base URL
https://api.govalid.org/api/v1/webhooks/
Available Events
| Event | Description |
|---|---|
qr.created | A new QR code was created |
qr.scanned | A QR code was scanned |
qr.expired | A QR code has expired |
qr.removed | A QR code was removed/inactivated |
qr.transferred | QR code ownership was transferred |
subscription.created | New subscription started |
subscription.cancelled | Subscription was cancelled |
payment.completed | Payment was successful |
payment.failed | Payment failed |
credit.topup | Credits were added |
counterfeit.detected | Potential counterfeit activity detected |
institution.staff.invited | Staff member was invited |
Register a Webhook
POST /api/v1/webhooks/
Request Body
{
"url": "https://your-server.com/webhook",
"events": ["qr.scanned", "qr.created", "qr.expired"],
"secret": "your_webhook_secret"
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | Your webhook endpoint URL (must be HTTPS) |
events | array | Yes | List of events to subscribe to |
secret | string | Yes | Secret for signature verification |
description | string | No | Description for your reference |
active | boolean | No | Enable/disable webhook (default: true) |
Response
{
"id": "wh-001",
"url": "https://your-server.com/webhook",
"events": ["qr.scanned", "qr.created", "qr.expired"],
"active": true,
"created_at": "2025-01-29T12:00:00Z"
}
List Webhooks
GET /api/v1/webhooks/
Response
{
"count": 2,
"results": [
{
"id": "wh-001",
"url": "https://your-server.com/webhook",
"events": ["qr.scanned", "qr.created"],
"active": true,
"last_triggered": "2025-01-29T15:00:00Z",
"success_count": 150,
"failure_count": 2,
"created_at": "2025-01-15T10:00:00Z"
}
]
}
Update Webhook
PATCH /api/v1/webhooks/{id}/
Delete Webhook
DELETE /api/v1/webhooks/{id}/
Webhook Payload
When an event occurs, GoValid sends a POST request to your endpoint:
{
"event": "qr.scanned",
"timestamp": "2025-01-29T12:00:00Z",
"webhook_id": "wh-001",
"data": {
"qr_id": "abc123",
"qr_title": "Product Certificate #001",
"scan_location": {
"country": "US",
"city": "New York",
"latitude": 40.7128,
"longitude": -74.0060
},
"device": "mobile",
"platform": "iOS",
"is_first_scan": false,
"scan_count": 15
},
"signature": "sha256=a1b2c3d4..."
}
Verifying Webhook Signatures
Every webhook payload includes a signature header for verification:
X-GoValid-Signature: sha256=a1b2c3d4...
Python Verification
import hashlib
import hmac
def verify_webhook(payload, signature, secret):
expected = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
Node.js Verification
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
Retry Policy
GoValid retries failed webhook deliveries:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 15 minutes |
| 5 | 1 hour |
After 5 failed attempts, the webhook is disabled.
Best Practices
- Respond quickly: Return 200 OK within 5 seconds
- Verify signatures: Always verify the webhook signature
- Handle duplicates: Use event IDs to prevent duplicate processing
- Use HTTPS: Webhook URLs must use HTTPS
- Monitor failures: Check webhook delivery status in the dashboard
Testing Webhooks
Test Endpoint
POST /api/v1/webhooks/{id}/test/
Sends a test event to verify your endpoint is working.
Webhook Logs
GET /api/v1/webhooks/{id}/logs/
View delivery history for a webhook.
Related
- Integrations Overview - All integration options
- API Reference - Full API documentation
- Code Examples - Common use cases