Webhooks Setup
Configure event-driven notifications for your applications.
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.
How Webhooks Work
- You register a webhook URL in GoValid
- You subscribe to specific events
- When an event occurs, GoValid sends a POST request to your URL
- Your application processes the payload and responds with 200 OK
Setting Up Webhooks
Via Dashboard
- Log in to my.govalid.org
- Navigate to Account → Webhooks
- Click Add Webhook
- Enter your endpoint URL (must be HTTPS)
- Select events to subscribe to
- Set a secret for signature verification
- Click Save
Developer option: API setup
curl -X POST https://api.govalid.org/api/v1/webhooks/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-server.com/webhook",
"events": ["qr.scanned", "qr.created", "qr.expired"],
"secret": "your_webhook_secret"
}'
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 |
Webhook Payload
{
"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": "ID",
"city": "Jakarta"
},
"device": "mobile",
"platform": "iOS",
"is_first_scan": false,
"scan_count": 15
},
"signature": "sha256=a1b2c3d4..."
}
Verifying Signatures
Every webhook includes an X-GoValid-Signature header:
X-GoValid-Signature: sha256=a1b2c3d4...
Python Example
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 Example
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return `sha256=${expected}` === signature;
}
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
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.
Testing
Test Your Endpoint
Use the dashboard to send a test event:
- Go to Account → Webhooks
- Click Test next to your webhook
- Check your server logs for the test payload
Local Development
For local testing, use tools like:
- ngrok: Expose localhost to the internet
- localtunnel: Alternative to ngrok
- webhook.site: Temporary webhook URL for testing
Troubleshooting
Webhook Not Receiving Events
- Verify URL is accessible and uses HTTPS
- Check server logs for incoming requests
- Verify event subscriptions are correct
- Check webhook is active (not disabled)
Signature Verification Failing
- Ensure you're using the correct secret
- Verify you're hashing the raw request body
- Check encoding (UTF-8)
- Compare with test payload
Too Many Failures
- Check your server is responding within 5 seconds
- Ensure your endpoint returns 200 OK
- Review error logs for issues
- Re-enable webhook after fixing issues
Related
- Webhooks API Reference - Full API documentation
- Integrations Overview - All integration options
- API Reference - Complete API documentation