Webhooks API
Subscribe to events and receive real-time notifications via webhooks.
The Webhooks API lets you subscribe to events programmatically. Use it for Zapier-style instant triggers or custom integrations that need real-time notifications.
Note: The Webhooks API requires a Hobby plan or above with active billing.
Endpoints
| Endpoint | Method | Description |
|---|---|---|
/api/v1/webhooks/subscribe | POST | Create webhook subscription |
/api/v1/webhooks/subscribe/[id] | DELETE | Remove subscription |
/api/v1/chatbots | GET | List agents (for subscription) |
Create Subscription
POST /api/v1/webhooks/subscribe
Request Body
{
"event": "form_submission",
"targetUrl": "https://your-server.com/webhook",
"chatbotId": "123e4567-e89b-12d3-a456-426614174000"
}
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
event | string | Yes | lead_created, form_submission, custom_form_submitted, conversation_started, conversation_ended, or escalation_created |
targetUrl | string | Yes | URL to receive events — HTTPS required in production, HTTP also accepted outside production |
chatbotId | string (UUID) | Yes | Agent to subscribe to |
Response
Success (201):
{
"id": "subscription-uuid"
}
Example
curl -X POST 'https://your-domain.com/api/v1/webhooks/subscribe' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"event": "form_submission",
"targetUrl": "https://hooks.zapier.com/hooks/catch/123456/abcdef",
"chatbotId": "123e4567-e89b-12d3-a456-426614174000"
}'
Delete Subscription
DELETE /api/v1/webhooks/subscribe/[id]
Response
Success (200): Returns an empty response with status 200.
Example
curl -X DELETE 'https://your-domain.com/api/v1/webhooks/subscribe/sub_abc123' \ -H 'Authorization: Bearer YOUR_API_KEY'
List Agents
Get available agents to subscribe to:
GET /api/v1/chatbots
Response
{
"chatbots": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"name": "Support Bot",
"url": "https://your-domain.com/chat/support-bot"
}
]
}
Webhook Payload
When an event occurs, we POST to your target URL:
Form Submission Event
{
"event": "form_submission",
"eventId": "evt_91d0a3ce-5a9d-4b67-a454-bafb9484281a",
"data": {
"id": "lead-uuid",
"chatbotId": "123e4567-e89b-12d3-a456-426614174000",
"name": "John Smith",
"email": "[email protected]",
"phone": "+1234567890",
"conversationId": "conv_abc123",
"createdAt": "2025-01-10T12:00:00Z"
},
"timestamp": "2025-01-10T12:00:00Z"
}
Headers
We include these headers with each delivery:
Content-Type: application/json User-Agent: AgentkitWebhook/2.0 X-Agentkit-Event: form_submission X-Agentkit-Event-Id: evt_91d0a3ce-5a9d-4b67-a454-bafb9484281a X-Agentkit-Signature: t=<unix-seconds>,v1=<hex-hmac-sha256>
Verify the signature against the exact raw UTF-8 request body before parsing JSON. See Webhook security for the signing procedure and payload catalog.
URL Requirements
Security
In production, a subscription URL must use HTTPS. Outside production, HTTP is also accepted — but only http: and https: URLs are ever allowed, and every URL must additionally pass a public-destination check on the URL itself, which rejects localhost and similar loopback hostnames, literal private and link-local addresses, and cloud metadata endpoints.
See Webhook security for the full list of destination restrictions; it is the canonical description of this rule.
Validation
The URL is checked when you create the subscription; URLs that fail the checks above are rejected with a 400 error whose message names the production requirement. The check inspects the URL as written — it does not resolve hostnames, so point your subscription at the public endpoint you actually intend to receive events. At delivery time the hostname is resolved once, every resolved address must be public, and the connection is pinned to those addresses — a hostname that resolves to a private or internal address (including one that changes between lookup and connect) is never contacted; the attempt is recorded as target_blocked.
Reliability
Response Requirements
Your endpoint should:
- Return 2xx status within 10 seconds
- Handle duplicate deliveries (idempotent)
Failure Handling
- Failed deliveries are retried five times after the initial request
- One exhausted event increments the consecutive failure streak once
- At least 10 exhausted events spanning seven days automatically disable a subscription
- Owners can repair and re-enable subscriptions from webhook settings
- Delivery is at least once; use
eventIdfor idempotency and do not assume ordering
Error Responses
| Status | Message | Cause |
|---|---|---|
| 400 | Invalid JSON body | Malformed JSON |
| 400 | Invalid request body | Missing/invalid fields (includes unsupported event types) |
| 400 | Target URL must be a public HTTPS endpoint (localhost and private IPs are not allowed) | URL fails SSRF validation |
| 401 | Missing or invalid Authorization header | Header not provided or wrong format |
| 401 | Invalid API key | Key not recognized |
| 403 | Webhook subscriptions require a Hobby plan or above with active billing | Plan or billing status does not allow integrations |
| 403 | Chatbot does not belong to this account | Agent belongs to a different account |
| 403 | Subscription does not belong to this account | Subscription belongs to a different account |
| 404 | Chatbot not found | Invalid agent ID |
| 404 | Webhook subscription not found | Invalid subscription ID |
| 409 | Webhook subscription already exists for this event and URL | Duplicate subscription |
Zapier Integration
These endpoints power our Zapier integration. When you connect Agentkit to Zapier:
- Zapier calls
/api/v1/authto verify your API key - Zapier calls
/api/v1/chatbotsto list your agents - When you enable a trigger, Zapier calls
/api/v1/webhooks/subscribe - Events are delivered to Zapier's webhook URL
- When you disable, Zapier calls DELETE on the subscription
To integrate without writing code, use Zapier directly instead of these APIs.
Code Example
Node.js Subscription Manager
class WebhookManager {
constructor(apiKey, baseUrl) {
this.apiKey = apiKey;
this.baseUrl = baseUrl;
}
async subscribe(chatbotId, targetUrl, event = 'form_submission') {
const response = await fetch(`${this.baseUrl}/api/v1/webhooks/subscribe`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ event, targetUrl, chatbotId }),
});
if (!response.ok) {
throw new Error(`Subscribe failed: ${response.status}`);
}
return response.json();
}
async unsubscribe(subscriptionId) {
const response = await fetch(
`${this.baseUrl}/api/v1/webhooks/subscribe/${subscriptionId}`,
{
method: 'DELETE',
headers: { 'Authorization': `Bearer ${this.apiKey}` },
},
);
return response.ok;
}
}
Next Steps
- Set up lead collection to generate events
- Configure webhooks in UI for dashboard setup
- Connect to Zapier for 5,000+ integrations