{"templateId":"openapi_docs","versions":[{"version":"v3","label":"V3 (Latest)","link":"/apis/openapi/webhooks","default":true,"active":false,"folderId":"58c9a61d"},{"version":"v2","label":"V2 (Soon to be deprecated)","link":"/apis/v2/openapi/webhooks","default":false,"active":true,"folderId":"58c9a61d"}],"sharedDataIds":{"openAPIDocsStore":"oas-apis/@v2/openapi.yaml","sidebar":"sidebar-sidebar.yaml__apis_v2_openapi"},"props":{"definitionId":"apis/@v2/openapi.yaml","dynamicMarkdocComponents":[],"baseSlug":"/apis/v2/openapi","seo":{"title":"Webhooks","description":"Subscribe to real-time notifications when contacts change jobs or companies experience key business events.\n\nWebhooks deliver HTTP POST requests to your endpoints when signals occur - from promotions and job changes to company growth.\n\n> For a full list of available signals, refer to the **Signal Options** endpoint under the Signals section.\n---\n**Key Features:**\n- Real-time contact & company signal notifications\n- Bulk subscription management (up to 25 items per request)\n- Secure delivery with HMAC-SHA256 signatures\n- Delivery monitoring with audit logs\n\n **Available Endpoints:**\n\n| Method | Endpoint | Purpose |\n|--------|----------|---------|\n| POST | `/api/subscriptions` | Create subscriptions (bulk supported) |\n| GET | `/api/subscriptions` | List all subscriptions |\n| GET | `/api/subscriptions/{id}` | Get subscription by ID |\n| PATCH | `/api/subscriptions/{id}` | Update subscription |\n| POST | `/api/subscriptions/delete` | Delete subscriptions (bulk supported) |\n| POST | `/api/subscriptions/{id}/test` | Test subscription delivery |\n| GET | `/api/audit-logs` | Get webhook delivery logs |\n| GET | `/api/audit-logs/stats` | Get delivery statistics |\n| GET | `/api/account/secret` | Get account webhook secret |\n| POST | `/api/account/secret/regenerate` | Regenerate account secret |\n\n> **Webhook Delivery Acknowledgment:** When receiving webhook deliveries (POST requests), your endpoint must acknowledge with a specific response format. See the Create Subscription endpoint for the required acknowledgment structure.\n      ---\n\n<details>\n<summary><strong>Rate Limits</strong></summary>\n\n| Operation | Limit |\n|-----------|-------|\n| API Requests | 100 requests/minute per account |\n| Create Subscriptions | 25 items per request |\n| Delete Subscriptions | 25 items per request |\n\n</details>\n\n---\n\n<details>\n<summary><strong>Security & Verification</strong></summary>\n\n**HTTPS Requirement:**\n- Production webhook URLs **must** use HTTPS\n- HTTP URLs are not accepted\n\n**Signature Verification:**\n\nAll webhook deliveries include an `X-Lusha-Signature` header containing an HMAC-SHA256 signature. Verify this signature to ensure the request is from Lusha:\n\n1. Extract the `X-Lusha-Signature` and `X-Lusha-Timestamp` headers\n2. Concatenate: `timestamp + \".\" + JSON.stringify(payload)`\n3. Compute HMAC-SHA256 using your webhook secret\n4. Compare the computed signature with the received signature\n\n**Example (Node.js):**\n```javascript\nconst crypto = require('crypto');\n\nfunction verifySignature(payload, signature, timestamp, secret) {\n  const signedPayload = `${timestamp}.${JSON.stringify(payload)}`;\n  const expectedSignature = crypto\n    .createHmac('sha256', secret)\n    .update(signedPayload)\n    .digest('hex');\n\n  return crypto.timingSafeEqual(\n    Buffer.from(signature),\n    Buffer.from(expectedSignature)\n  );\n}\n```\n\n> **Security Best Practice:** Always verify webhook signatures to prevent spoofed requests.\n\n</details>\n\n---\n\n<details>\n<summary><strong>Credits & Billing</strong></summary>\n\n**Credit Charges:**\n- Credits are charged when signals are detected and delivered to your webhook\n- The `creditsCharged` field in the webhook payload indicates how many credits were used\n- Credits are deducted from your account balance per signal type\n\n**No Duplicate Charges:**\n- Each signal is delivered once and charged once\n- Webhook delivery retries do not incur additional charges\n\n</details>\n\n---\n\n<details>\n<summary><strong>Error Response Format</strong></summary>\n\nAll error responses follow this format:\n```json\n{\n  \"statusCode\": 400,\n  \"message\": \"Validation failed\",\n  \"errors\": [\"entityType must be one of: contact, company\"]\n}\n```\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `statusCode` | number | HTTP status code |\n| `message` | string | Error message |\n| `errors` | string[] | Detailed error messages (optional) |\n\n</details>\n\n---\n","siteUrl":"https://docs.lusha.com","llmstxt":{"hide":false,"sections":[{"title":"Table of contents","includeFiles":["**/*"],"excludeFiles":[]}],"excludeFiles":[]}},"itemId":"webhooks","disableAutoScroll":true,"metadata":{"subType":"openapi-operation"},"compilationErrors":[],"markdown":{"partials":{},"variables":{"rbac":{"teams":["anonymous"]},"user":{},"remoteAddr":{"hostname":"docs.lusha.com","port":4000,"ipAddress":"216.73.216.47"},"lang":"default_locale","env":{"PUBLIC_REDOCLY_BRANCH_NAME":"main"}}},"pagePropGetterError":{"message":"","name":""}},"slug":"/apis/v2/openapi/webhooks","userData":{"isAuthenticated":false,"teams":["anonymous"]},"isPublic":true}