Next CapNext Cap

Webhooks

Real-time event notifications pushed to your server when leads are created, tickets are updated, and more.

Overview

Webhooks push real-time event notifications to your server when things happen in your Next Cap account — a lead is captured, a ticket is created or updated, a conversation completes, etc.

Enterprise plan only. Pro plan organizations have access to the REST API but not webhooks. Upgrade to Enterprise to enable real-time event delivery.

Setting Up Webhooks

You can create and manage webhooks from the Next Cap Dashboard or programmatically via the API using a Data API key.

From the Dashboard (recommended):

  1. Go to Settings → API Keys → Webhooks tab.
  2. Click Create Webhook.
  3. Enter your endpoint URL and select the events you want to receive.
  4. Copy the signing secret immediately — it is shown only once.

Alternatively, you can register webhooks via the API:

Register a webhook (API)bash
curl -X POST -H "X-Api-Key: sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-server.com/webhooks/nextcap", "events": ["lead.created", "ticket.created"]}' \
https://api.nextcap.ai/api/v1/external/webhooks
Response — 201 Createdjson
{
"data": {
"id": "uuid",
"url": "https://your-server.com/webhooks/nextcap",
"secret": "a1b2c3...your-signing-secret...z9y8",
"events": ["lead.created", "ticket.created"],
"is_active": true,
"created_at": "2026-04-01T12:00:00.000Z"
}
}
The secret is shown only once on creation. Store it securely — you will need it to verify webhook signatures.

Event Types

lead.createdevent

A new lead was captured (pre-chat form, in-chat, manual, or Telegram).

ticket.createdevent

A new support ticket was created.

ticket.updatedevent

A ticket was modified (any field change).

ticket.status_changedevent

A ticket's status changed (e.g., open → resolved).

ticket.assignedevent

A ticket was assigned or reassigned to an agent.

ticket.department_changedevent

A ticket was transferred to a different department.

ticket.reopenedevent

A resolved or closed ticket was reopened.

ticket.replyevent

An agent replied to a ticket (includes content and actor ID).

ticket.customer_replyevent

A customer replied to a ticket via widget or email.

conversation.createdevent

A new chat conversation was started.

conversation.completedevent

A conversation was resolved.

conversation.handed_offevent

A conversation was escalated to human support (entered handoff queue).

visitor.identifiedevent

A visitor's identity was captured (email, name, etc.).

Payload Format

Webhook payloadjson
{
"event": "lead.created",
"timestamp": "2026-04-01T12:05:00.000Z",
"data": {
"id": "uuid",
"email": "john@acme.com",
"name": "John Doe",
"company": "Acme Inc",
"source": "pre_chat_form",
"created_at": "2026-04-01T12:05:00.000Z"
}
}

The data field uses the same shape as the corresponding REST API response for that entity.

Signature Verification

Every webhook request includes an X-Webhook-Signature header containing an HMAC-SHA256 hex digest of the raw request body, signed with your webhook secret.

Verify signature (Node.js)javascript
const crypto = require("crypto");
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected),
);
}
// In your Express handler:
app.post("/webhooks/nextcap", (req, res) => {
const sig = req.headers["x-webhook-signature"];
if (!verifyWebhook(req.rawBody, sig, WEBHOOK_SECRET)) {
return res.status(401).send("Invalid signature");
}
// Process the event
console.log(req.body.event, req.body.data);
res.status(200).send("OK");
});
Verify signature (Python)python
import hmac, hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler:
@app.post("/webhooks/nextcap")
def handle_webhook():
sig = request.headers.get("X-Webhook-Signature")
if not verify_webhook(request.data, sig, WEBHOOK_SECRET):
abort(401)
payload = request.json
print(payload["event"], payload["data"])
return "OK", 200

Retries & Auto-Disable

Failed deliveries are retried 3 times with exponential backoff (5s, 30s, 2 min). After 10 consecutive failures, the webhook is automatically disabled. You can re-enable it by deleting and re-creating it.

Management Endpoints

GET/external/webhooksAPI Key

List all registered webhooks for your organization.

POST/external/webhooksAPI Key

Register a new webhook.

urlstringrequired

HTTPS URL to receive webhook events.

eventsstring[]required

Array of event types to subscribe to.

DELETE/external/webhooks/:idAPI Key

Remove a registered webhook.

POST/external/webhooks/:id/testAPI Key

Send a test event to verify your endpoint is receiving payloads.