Webhooks enable your application to receive real-time notifications when events occur in InstaView. Instead of polling the API, webhooks push data to your endpoint immediately when interviews complete, analyses finish, or other events happen.
Most webhook payloads contain minimal data (IDs and status), but the analysis.completed event
includes the full analysis results. For other details like transcripts, use the Interview
API to fetch the complete resource.
For ATS integrations managing multiple companies, you can register webhooks per company by specifying the companyId parameter when creating a webhook. This enables:
Company-specific endpoints: Each company can have its own webhook URL (e.g., different subdomains)
Selective event delivery: Webhooks with companyId only receive events for that specific company
Global webhooks: Webhooks without companyId receive events for all companies accessible by the API key
// Webhook for Company Aawait createWebhook({ url: 'https://company-a.yourats.com/webhooks/instaview', companyId: 'company-a-uuid', events: ['interview.completed', 'analysis.completed']});// Webhook for Company Bawait createWebhook({ url: 'https://company-b.yourats.com/webhooks/instaview', companyId: 'company-b-uuid', events: ['interview.completed', 'analysis.completed']});// Global webhook (receives all events)await createWebhook({ url: 'https://admin.yourats.com/webhooks/instaview', // No companyId - receives events for all companies events: ['interview.completed', 'analysis.completed']});
// List all webhooks (includes both company-specific and global webhooks)const allWebhooks = await fetch('/webhooks', { headers });// List webhooks for a specific company (excludes global webhooks)// Only returns webhooks that have the specified companyIdconst companyWebhooks = await fetch('/webhooks?companyId=company-uuid', { headers });
Note: When filtering by companyId, only company-specific webhooks are returned. Global webhooks (those without a companyId) are excluded from filtered results. To see all webhooks including global ones, omit the companyId parameter.
Every webhook request includes an HMAC-SHA256 signature in the X-Webhook-Signature header. Always verify this signature to ensure requests are from InstaView.The signature format is: sha256=<hex-encoded-signature>
Store your signing secret securely! The signing secret is only returned
once when you create a webhook configuration. If lost, you must delete and
recreate the webhook to get a new secret.
Best practices for secret management:
Store secrets in environment variables or a secrets manager
Never commit secrets to version control
Rotate secrets periodically by creating new webhooks
Use different secrets for development and production
Handle duplicate deliveries gracefully using the deliveryId:
Copy
// Note: Use Redis or database storage in production for multi-instance deploymentsconst processedDeliveries = new Set();app.post('/webhooks/instaview', (req, res) => { const { deliveryId } = req.body; if (processedDeliveries.has(deliveryId)) { return res.status(200).send('Already processed'); } processedDeliveries.add(deliveryId); // Process the event... res.status(200).send('OK');});
Use HTTPS
Production webhook URLs must use HTTPS. HTTP is only allowed for localhost
during development.
Return 2xx for Success
Any 2xx status code indicates successful receipt. Retry behavior depends on the status code:
Status
Meaning
200, 201, 202
Success - no retry
429
Rate limit - will retry
4xx (except 429)
Client error - no retry (permanent errors like 401, 404)
const response = await fetch("https://api.instaview.sk/webhooks", { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ url: "https://api.yourcompany.com/webhooks/instaview", name: "Production Webhook", description: "Receives interview completion notifications", events: ["interview.completed", "analysis.completed"], companyId: "company-uuid", // Optional: Associate with specific company headers: [{ name: "Authorization", value: "Bearer your-internal-token" }], }),});const { data } = await response.json();// IMPORTANT: Store this secret securely - it's only shown once!console.log("Signing secret:", data.signingSecret);
Per-Company Webhooks: For ATS integrations managing multiple companies, you can specify companyId when creating a webhook. This allows you to register separate webhooks per company (e.g., different subdomains). If omitted, the webhook will receive events for all companies accessible by the API key (global webhook).
For more comprehensive testing of interview-related webhook events (interview.completed, analysis.completed), you can create test interviews using the isTest flag:
Copy
// Create a test interview that immediately completesconst testInterview = await fetch("https://api.instaview.sk/v1/public/interviews", { method: "POST", headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ candidateId: "candidate-uuid", agentId: "agent-uuid", isTest: true, // Creates test interview }),});// This will trigger:// 1. interview.completed webhook// 2. analysis.completed webhook// Both events will be sent to your webhook endpoint
Test interviews are useful for:
Testing your webhook handler’s processing logic for interview completion
Verifying that analysis data is correctly parsed and stored
End-to-end testing of your integration without waiting for real interviews
Development and debugging without consuming billing minutes
See the Create Interview documentation for more details on test mode.
Security: Sensitive headers (Authorization, X-API-Key, X-Secret, API-Key)
are automatically encrypted at rest. When listing webhooks, these header
values are masked for security.
Possible causes: - Webhook is not subscribed to the event type - Webhook
is disabled (isActive: false) - Circuit breaker is open (check
circuitOpenedAt) Solutions: - Verify event subscriptions in webhook
configuration - Check if webhook is active - Reset circuit breaker if needed
Signature verification failing
Possible causes: - Using wrong signing secret - Modifying payload before
verification - Encoding issues Solutions: - Verify you’re using the
original signing secret - Verify the raw request body, not parsed JSON -
Ensure UTF-8 encoding
Webhook disabled automatically
Cause: Too many consecutive failures triggered the circuit breaker
Solutions: 1. Fix the underlying issue (endpoint availability,
authentication, etc.) 2. Use the test endpoint to verify connectivity 3. Reset
the circuit breaker
Missing events
Possible causes: - Event occurred before webhook was configured - Event
type not in subscription list Note: Webhooks only deliver events that
occur after configuration. For historical data, use the API to poll for past
events.