Webhooks
Webhooks let you receive real-time HTTP notifications when events occur in your tenant. Instead of polling for changes, register an endpoint and Vyntech Account will POST event payloads to it — signed with HMAC-SHA256 so you can verify authenticity.
How Webhooks Work
When something happens in your tenant — a user registers, a login fails, a session is revoked — Vyntech Account fires an event. If you have a webhook registered for that event type, here's what happens:
- 1An event occurs in your tenant (e.g., a user registers).
- 2The payload is constructed with full event details and signed using HMAC-SHA256 with your webhook secret.
- 3A POST request is sent to your registered endpoint with the payload as JSON body and the signature in the
X-Webhook-Signatureheader. - 4Your endpoint must respond with a 2xx status within 10 seconds.
- 5If delivery fails, the system retries with exponential backoff (up to 3 attempts).
Tip: Keep your webhook handler fast — acknowledge the request immediately and process the event asynchronously. Heavy processing inside the handler risks timeouts and unnecessary retries.
Event Types
Subscribe to specific events or use * to receive all events. Events follow a resource.action naming convention.
| Event | Description |
|---|---|
| Users | |
| user.registered | A new user registered in the tenant |
| user.updated | User profile or status was modified |
| user.deleted | User was permanently deleted |
| Authentication | |
| auth.login | Successful login (password + optional MFA) |
| auth.login.failed | Failed login attempt (bad password or MFA) |
| auth.logout | User logged out |
| auth.mfa_enabled | User enabled MFA |
| auth.mfa_disabled | User or admin disabled MFA |
| auth.password_changed | User changed their password |
| auth.password_reset | Password was reset via email flow |
| Sessions | |
| session.created | New session created after successful login |
| session.revoked | Session was revoked (by user, admin, or system) |
| Risk Engine | |
| risk.challenge_triggered | Risk score triggered a step-up challenge |
| risk.login_blocked | Login was blocked due to high risk score |
| Settings & API Keys | |
| settings.updated | Tenant settings were modified |
| api_key.created | New API key was created |
| api_key.revoked | API key was revoked |
Payload Format
Every webhook delivery sends a JSON payload with a consistent structure. TheX-Webhook-Signature header contains the HMAC-SHA256 signature of the raw request body.
Headers
Content-Typeapplication/jsonX-Webhook-Signaturesha256=<hex-encoded HMAC>X-Webhook-IDUnique delivery ID (for idempotency)X-Webhook-TimestampUnix timestamp of delivery attemptExample Payload
{
"id": "evt_01H9ABCD4F2B7NQ9RPWT3M6J",
"event": "user.registered",
"tenant_id": "tnt_01H7ABCD5E3C8MR0QPXS4N7K",
"timestamp": "2024-11-15T09:32:17Z",
"data": {
"user_id": "usr_01H8KXYZ4F2B7NQ9RPWT3M6J",
"email": "jane@acme-corp.com",
"display_name": "Jane Smith",
"status": "active",
"email_verified": false,
"mfa_enabled": false
}
}idUnique event ID — use for idempotency checkseventThe event type (e.g., user.registered)tenant_idWhich tenant this event belongs totimestampISO 8601 timestamp of when the event occurreddataEvent-specific payload (varies by event type)Registering a Webhook
Register a webhook endpoint by providing the target URL, the events you want to subscribe to, and an optional secret for signature verification. If you don't provide a secret, one will be generated for you.
/api/v1/webhooks🔒 AuthRegister a new webhook endpoint for your tenant.
{
"url": "https://your-app.com/webhooks/vyntech",
"events": ["user.registered", "auth.login", "auth.login.failed"],
"secret": "whsec_your_shared_secret_here"
}Important:The secret is only returned once at creation time. Store it securely — you'll need it to verify incoming webhook signatures. If you lose it, you must rotate the webhook secret.
Signature Verification
Every webhook delivery includes an X-Webhook-Signatureheader containing a HMAC-SHA256 signature of the raw request body, computed with your shared secret. Always verify this signature before processing the event to ensure the request came from Vyntech Account and wasn't tampered with.
How It Works
- 1Read the raw request body (do not parse JSON first — the signature is over the raw bytes).
- 2Compute HMAC-SHA256 of the raw body using your webhook secret as the key.
- 3Compare your computed signature with the value in
X-Webhook-Signature(after stripping thesha256=prefix). - 4Use a constant-time comparison to prevent timing attacks.
Verification Examples
Your webhook endpointPublicVerify the X-Webhook-Signature header before processing events.
Security warning: Never skip signature verification in production. Without it, any attacker who discovers your webhook URL can send fake events to your system. Always use constant-time comparison to prevent timing attacks.
Retry Policy
If your endpoint doesn't respond with a 2xx status within 10 seconds, or if the connection fails, Vyntech Account will retry delivery with exponential backoff.
| Attempt | Delay | Description |
|---|---|---|
| 1st retry | 10 seconds | Immediate retry for transient failures |
| 2nd retry | 60 seconds | Short cooldown |
| 3rd retry | 300 seconds | Final attempt (5 minutes) |
Failure Escalation
- •After 3 consecutive failures for a single event, the delivery is marked as
failedand won't be retried. - •If a webhook accumulates failures over time, it's marked as
failing— events continue to be sent but you'll see warnings in the admin dashboard. - •After 24 hours of continuous failures, the webhook is automatically
disabled. You'll receive an email notification and must re-enable it manually.
Check Webhook Status
/api/v1/webhooks/:id🔒 AuthGet the current status and delivery stats for a webhook.
Testing Webhooks
Before going live, you can send a test event to your webhook endpoint. The test endpoint sends a synthetic event with event: "webhook.test"to verify your endpoint is reachable and responding correctly.
/api/v1/webhooks/:id/test🔒 AuthSend a test event to verify your webhook endpoint is working.
Development tip: Use a tool like ngrok or webhook.site to expose your local development server to the internet for testing webhooks.
Best Practices
Respond quickly, process asynchronously
Return a 200 immediately and enqueue the event for background processing. Your endpoint has a 10-second timeout — if processing takes longer, the delivery will be marked as failed and retried unnecessarily.
Always verify signatures
Never skip HMAC verification, even in staging environments. It takes one line of code and prevents entire classes of security vulnerabilities. Use constant-time comparison to prevent timing attacks.
Use idempotency keys
The id field in the event payload is unique. Store processed event IDs and skip duplicates. Retries will resend the same event ID, so idempotency prevents double-processing.
Handle out-of-order delivery
Webhooks are delivered at-least-once but not necessarily in order. A user.updated event might arrive before user.registered due to retries. Use the timestamp field to determine event ordering and ignore stale updates.
Monitor webhook health
Set up alerts for failed deliveries. Use the GET /api/v1/webhooks/:id endpoint to check delivery stats periodically. If your webhook gets disabled after 24h of failures, you'll miss events until you fix the issue and re-enable it.
What's Next
Email Notifications Guide →
Configure transactional emails and notification preferences.
Risk Engine Guide →
Understand risk scoring and how it triggers webhook events.
Settings API →
Configure webhook URLs and event subscriptions via settings.
Sessions API →
Session lifecycle events that trigger webhook deliveries.