Webhooks
Overview
Section titled “Overview”Instead of polling GET /v1/verify/status/:jobId, you can provide a webhook_url when creating a verification request. BizVerify will POST to that URL when the job completes, fails, or is refunded.
Setting up webhooks
Section titled “Setting up webhooks”Include webhook_url in your verification request:
curl -X POST https://api.bizverify.co/v1/verify \ -H "Content-Type: application/json" \ -H "X-API-Key: bv_live_abc123..." \ -d '{ "entity_name": "Acme Corporation", "jurisdiction": "us-fl", "webhook_url": "https://your-app.com/webhooks/bizverify" }'Events
Section titled “Events”verification.completed
Section titled “verification.completed”Sent when a verification job finishes successfully.
{ "event": "verification.completed", "job_id": "job_abc123", "jurisdiction": "us-fl", "entity_name": "Acme Corporation", "status": "completed", "data": { "entity_name": "ACME CORPORATION", "entity_type": "corporation", "status": "active", "jurisdiction": "us-fl", "formation_date": "2015-03-12", "confidence": 95 }, "credits_charged": 1, "credits_refunded": false, "completed_at": "2026-04-02T12:00:00.000Z"}verification.failed
Section titled “verification.failed”Sent when a verification job fails after all retry attempts.
{ "event": "verification.failed", "job_id": "job_abc123", "jurisdiction": "us-fl", "entity_name": "Acme Corporation", "status": "failed", "error": "Data source timeout: the official source did not respond in time", "credits_charged": 1, "credits_refunded": true, "completed_at": "2026-04-02T12:05:00.000Z"}verification.refunded
Section titled “verification.refunded”Sent when an admin manually refunds credits for a job.
{ "event": "verification.refunded", "job_id": "job_abc123", "jurisdiction": "us-fl", "entity_name": "Acme Corporation", "status": "refunded", "credits_charged": 1, "credits_refunded": true, "completed_at": "2026-04-02T12:10:00.000Z"}Delivery details
Section titled “Delivery details”| Property | Value |
|---|---|
| Method | POST |
| Content-Type | application/json |
| User-Agent | BizVerify-Webhook/1.0 |
| Signature | X-BizVerify-Signature header (HMAC-SHA256) |
| Timeout | 10 seconds per attempt |
| Retries | 3 retries (4 total attempts) |
| Backoff | Exponential (1s, 2s, 4s) |
| Success | Any 2xx HTTP response |
Verifying signatures
Section titled “Verifying signatures”Every webhook delivery includes an X-BizVerify-Signature header containing an HMAC-SHA256 signature of the request body. Use this to verify that the request came from BizVerify and hasn’t been tampered with.
The header format is sha256=<hex-encoded-signature>.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhookSignature(body, signature, secret) { const expected = 'sha256=' + createHmac('sha256', secret) .update(body) .digest('hex'); return timingSafeEqual(Buffer.from(signature), Buffer.from(expected));}
// In your webhook handler:app.post('/webhooks/bizverify', (req, res) => { const signature = req.headers['x-bizverify-signature']; if (!signature || !verifyWebhookSignature(req.rawBody, signature, process.env.WEBHOOK_SECRET)) { return res.status(401).send('Invalid signature'); }
// Process the webhook payload const event = req.body; console.log(`Received ${event.event} for job ${event.job_id}`); res.status(200).send('OK');});Best practices
Section titled “Best practices”- Respond quickly. Return a
200status immediately and process the payload asynchronously. If your endpoint takes longer than 10 seconds, the delivery will be marked as failed and retried. - Handle duplicates. In rare cases (e.g., network issues), you may receive the same event more than once. Use
job_idas an idempotency key. - Verify the signature. Always verify the
X-BizVerify-Signatureheader to ensure the request came from BizVerify. See Verifying signatures above. - Use HTTPS. Always use an
https://URL for your webhook endpoint.