Method: POST
This endpoint creates a new web_call Agent. Only web_call agents are supported.
https://app.salescloser.ai/api/v2/agents
company_name (required) - String
Company/Product name stored as company_name.
agent_nickname (required) - String
agent_name (required) - String
Must match the agent name format used in the app.
avatar_id (optional) - Integer
Realtime avatar ID (from Avatars endpoint).
agent_position (required) - String
voice_id (required) - String
Provider voice identifier (see Voices endpoint). Example: BCT3xQAsoGrdDreaWeJE
prompt (required) - String
The core prompt for the agent. Stored internally.
language (optional) - String
ISO code. Defaults to en if omitted.
voice_speed (optional) - Integer
Range 70–120. Defaults to 100.
description (optional) - String
Short description shown alongside the agent.
timezone (optional) - String
Valid IANA timezone. If omitted, defaults to your account timezone.
knowledge_base (optional) - String
Plain text only (no links). Automatically creates or updates a Knowledge Base and links it to the agent.
Notes:
web_call.{
"company_name": "My Web Agent",
"agent_nickname": "Web Demo Agent",
"agent_name": "ProductDemo2025",
"agent_position": "Product Specialist",
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"prompt": "You are a helpful AI sales agent that explains our product clearly.",
"language": "en",
"voice_speed": 100,
"timezone": "America/Los_Angeles",
"avatar_id": 42
}
{
"data": {
"id": 123,
"company_name": "My Web Agent",
"agent_name": "ProductDemo2025",
"agent_position": "Product Specialist",
"language": "en",
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"voice_speed": 100,
"timezone": "America/Los_Angeles",
"start_meeting_url": "https://app.salescloser.ai/agents/{agentUuid}/start-meeting"
},
"message": "Agent created successfully."
}
Method: GET
Returns full details for a specific Agent.
https://app.salescloser.ai/api/v2/agents/{agentId}
{
"data": {
"id": 123,
"company_name": "My Web Agent",
"agent_name": "ProductDemo2025",
"agent_position": "Product Specialist",
"language": "English",
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"voice_speed": 100,
"timezone": "America/Los_Angeles",
"start_meeting_url": "https://app.salescloser.ai/agents/{agentUuid}/start-meeting",
"sequence_type": "prompt_based",
"sequence_prompt": "You are a helpful AI sales agent ..."
}
}
Method: PATCH
Updates an existing web_call Agent. The type cannot be changed.
https://app.salescloser.ai/api/v2/agents/{agentId}
company_name (optional) - String
Updates company/product name.
agent_nickname (optional) - String
Updates the display name (max 255 characters).
avatar_id (optional) - Integer
Realtime avatar ID (from Avatars endpoint).
agent_name (optional) - String
agent_position (optional) - String
description (optional) - String
Short description.
language (optional) - String
Language name (see Languages endpoint).
voice_id (optional) - String
Provider voice identifier.
voice_speed (optional) - Integer
Range 70–120.
timezone (optional) - String
Valid IANA timezone.
prompt (optional) - String
Replaces the agent's prompt.
knowledge_base (optional) - String
Plain text only (no links). Replaces the agent's existing knowledge base content; creates one if missing.
{
"agent_nickname": "Demo",
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"voice_speed": 95,
"prompt": "Update: keep responses concise.",
"timezone": "America/New_York"
}
{
"data": {
"id": 123,
"company_name": "My Web Agent",
"agent_name": "ProductDemo2025",
"agent_position": "Product Specialist",
"language": "English",
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"voice_speed": 95,
"timezone": "America/Los_Angeles",
"start_meeting_url": "https://app.salescloser.ai/agents/{agentUuid}/start-meeting",
"sequence_type": "prompt_based",
"sequence_prompt": "Update: keep responses concise."
},
"message": "Agent updated successfully."
}
Method: GET
Returns the list of voices available to your account.
https://app.salescloser.ai/api/v2/voices
[
{
"id": 31,
"voice_id": "BCT3xQAsoGrdDreaWeJE",
"name": "Natasha V2",
"accent": "US",
"gender": "female",
"description": "Clear, friendly",
"use_case": "general",
"age": "adult",
"default_speed": 100,
"min_speed": 70,
"max_speed": 120
},
{
"id": 12,
"voice_id": "21m00Tcm4TlvDq8ikWAM",
"name": "Rachel",
"accent": "US",
"gender": "female",
"default_speed": 100,
"min_speed": 70,
"max_speed": 120
}
]
Method: GET
Returns a list of supported languages by name.
https://app.salescloser.ai/api/v2/languages
["Arabic","Bulgarian","Dutch","English","French","German","Greek","Hindi","Indonesian","Italian","Japanese","Portuguese","Romanian","Russian","Spanish","Turkish"]
Method: GET
Returns the list of available avatars for your tenant (global and tenant-specific).
https://app.salescloser.ai/api/v2/avatars
[
{
"id": 12,
"name": "Alex",
"thumbnail_image_url": "https://...signed-url..."
},
{
"id": 13,
"name": "Taylor",
"thumbnail_image_url": null
}
]
To authenticate generate a new API Token in your profile, and pass it in the Authorization header as a Bearer token
Authorization: Bearer {yourToken}
Method: GET
This endpoint returns a list of all Agents in your account in alphabetical order.
https://app.salescloser.ai/api/v2/agents
[
{
"id": 1,
"name": "My New Product Showcase"
},
{
"id": 2,
"name": "My New Course Demo"
},
...
]
Method: GET
This endpoint returns a list of all States that belong to an Agent in your account.
https://app.salescloser.ai/api/v2/agents/{agentId}
[
{
"id": 1,
"name": "step_1",
},
{
"id": 2,
"name": "step_2"
},
{
"id": 3,
"name": "step_3"
},
{
"id": 4,
"name": "step_4"
},
...
]
Method: POST
This endpoint creates a Campaign with status DRAFT
https://app.salescloser.ai/api/v2/campaigns
agent_id (required) - Integer
Has to be attached to a Phone Number
title (required) - String
Max length: 255 characters
scheduled_at (required) - DateTime
Has to be in the UTC timezone
Format: "Y-m-d H:i:s" 2026-02-23 10:32:43
ring_timeout (optional) - Integer
Ring timeout in seconds (1-600). If not provided, uses Twilio's default (60 seconds)
leads (required) - array
Has to include at least one lead object with the following fields
{
"id": 1000,
"title": "My First Campaign",
"status": "draft",
"scheduled_at": "2024-04-02T20:32:53.000000Z"
}
Method: PATCH
This endpoint updates a Campaign
https://app.salescloser.ai/api/v2/campaigns/{campaignId}
title (required) - String
Max length: 255 characters
scheduled_at (required) - DateTime
Has to be in the UTC timezone
Format: "Y-m-d H:i:s" 2026-02-23 10:32:43
ring_timeout (optional) - Integer
Ring timeout in seconds (1-600). If not provided, uses Twilio's default (60 seconds)
status (optional) - String
Valid options: draft, live.
{
"id": 1000,
"title": "My First Campaign",
"status": "live",
"scheduled_at": "2024-04-02T20:32:53.000000Z"
}
Method: GET
This endpoint returns a paginated list of all Calls in your account.
https://app.salescloser.ai/api/v2/calls
status (optional) - String
Valid options: completed, in_progress, incomplete, draft, scheduled, sent_to_server, pending.
type (optional) - String
Valid options: inbound_call, outbound_call, zoom.
agent_id (optional) - Integer
A valid Agent ID
campaign_id (optional) - Integer
A valid Campaign ID
lead_id (optional) - Integer
A valid Lead ID
order_by (optional) - String
Defaults to id.
Valid options: id scheduled_at, finished_at.
order_direction (optional) - String
Defaults to DESC.
Valid options: ASC, DESC.
per_page (optional) - Integer
Defaults to 24.
page (optional) - String
Defaults to 1.
{
"data": [
{
"id": 1000,
"agent_id": 123,
"lead_id": 123,
"campaign_id": null,
"finished_demo_at": null,
"status": "pending",
"final_step_reached": null,
"next_steps": null,
"summary_background": null,
"provider_meeting_id": null,
"minutes": null,
"retries": 0,
"incomplete_reason": null,
"sent_to_server_at": null,
"created_at": "2024-04-02T20:32:53.000000Z",
"updated_at": "2024-05-06T20:40:37.000000Z",
"scheduled_at": null,
"type": "zoom"
},
...
],
"metadata": {
"current_page": 1,
"total_records": 80,
"has_more_pages": true,
"total_pages": 4
}
}
Method: POST
This endpoint creates a Call.
https://app.salescloser.ai/api/v2/calls
agent_id (required) - Integer
Has to be attached to a Phone Number
scheduled_at (required) - DateTime
Has to be in the UTC timezone
Format: "Y-m-d H:i:s" 2026-02-23 10:32:43
lead (required) - Object
{
"data": {
"demo": {
"id": 1235,
"agent_id": 122,
"lead_id": 489,
"campaign_id": null,
"finished_demo_at": null,
"status": "draft",
"final_step_reached": null,
"next_steps": null,
"summary_background": null,
"provider_meeting_id": null,
"minutes": null,
"retries": 0,
"incomplete_reason": null,
"sent_to_server_at": null,
"created_at": "2024-07-10T19:54:37.000000Z",
"updated_at": "2024-07-10T19:54:37.000000Z",
"scheduled_at": "2024-09-01T12:00:00.000000Z",
"type": "outbound_phone"
}
},
"message": "Call created successfully"
}
Method: GET
This endpoint returns a paginated list of all Leads in your account.
https://app.salescloser.ai/api/v2/leads
search (optional) - String
Search leads by first name, last name, email, phone number, or business name
status (optional) - Array
Filter by lead status. Valid options: 0 (Created), 1 (Open), 2 (Working), 3 (Disqualified), 4 (Qualified), 5 (Opportunity Created), 6 (Opportunity Lost), 7 (Customer).
per_page (optional) - Integer
Number of results per page (1-100). Defaults to 24.
{
"data": [
{
"id": 2,
"email": "john.doe@example.com",
"first_name": "John",
"last_name": "Doe",
"phone_number": "555-1234",
"business_name": "Acme Corp",
"website": "https://example.com",
"client_id": 21,
"comments": "Interested in our premium package",
"timezone": "America/New_York",
"was_recently_created": false,
"created_at": "2025-06-12T20:23:16.000000Z",
"updated_at": "2025-06-12T20:23:16.000000Z",
"custom_field": "custom_value",
"api_source": "mobile_app"
},
{
"id": 1,
"email": "jane.smith@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone_number": "555-5678",
"business_name": "Smith Consulting",
"website": "https://smithconsulting.com",
"client_id": 21,
"comments": null,
"timezone": "America/Mexico_City",
"was_recently_created": false,
"created_at": "2025-06-06T20:16:46.000000Z",
"updated_at": "2025-06-06T20:16:46.000000Z"
}
],
"metadata": {
"current_page": 1,
"total_records": 2,
"per_page": 24,
"has_more_pages": false,
"total_pages": 1
}
}
Method: POST
This endpoint creates a new Lead in your account.
https://app.salescloser.ai/api/v2/leads
phone_number (required) - String
Valid phone number. Must be unique per client.
email (optional) - String
Valid email address
first_name (optional) - String
Lead's first name (max 255 characters)
last_name (optional) - String
Lead's last name (max 255 characters)
business_name (optional) - String
Company or business name (max 255 characters)
website_url (optional) - String
Valid website URL (max 255 characters)
comments (optional) - String
Additional notes or comments (max 1000 characters)
timezone (optional) - String
Valid IANA timezone (see Timezones section)
status (optional) - Integer
Lead status (0-7). Defaults to 0 (Created)
Custom Fields
You can pass any additional fields as strings. They will be stored in the lead's metadata for flexible data storage.
{
"phone_number": "555-1234",
"email": "jane.smith@example.com",
"first_name": "Jane",
"last_name": "Smith",
"business_name": "Smith Consulting",
"website_url": "https://smithconsulting.com",
"comments": "Potential high-value client",
"timezone": "America/New_York",
"status": 1,
"lead_source": "website_form",
"campaign_id": "summer_2024",
"industry": "consulting"
}
{
"data": {
"id": 3,
"email": "jane.smith@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone_number": "+19871231232",
"business_name": "Smith Consulting",
"website": "https://smithconsulting.com",
"client_id": 21,
"comments": "Potential high-value client",
"timezone": "America/New_York",
"was_recently_created": true,
"created_at": "2025-08-29T17:47:03.000000Z",
"updated_at": "2025-08-29T17:47:03.000000Z",
"lead_source": "website_form",
"campaign_id": "summer_2024",
"industry": "consulting"
},
"message": "Lead created successfully."
}
Method: GET
This endpoint retrieves a specific Lead by ID.
https://app.salescloser.ai/api/v2/leads/{leadId}
leadId (required) - Integer
The ID of the lead to retrieve
{
"data": {
"id": 2,
"email": "jane.smith@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone_number": "555-1234",
"business_name": "Smith Consulting",
"website": "https://smithconsulting.com",
"client_id": 21,
"comments": "Potential high-value client",
"timezone": "America/New_York",
"was_recently_created": false,
"created_at": "2025-06-12T20:23:16.000000Z",
"updated_at": "2025-06-12T20:23:16.000000Z",
"lead_source": "website_form",
"campaign_id": "summer_2024",
"industry": "consulting"
}
}
Method: PATCH
This endpoint updates an existing Lead. All fields are optional - only provide the fields you want to update.
https://app.salescloser.ai/api/v2/leads/{leadId}
leadId (required) - Integer
The ID of the lead to update
phone_number (optional) - String
Valid phone number. Must be unique per client if changed.
email (optional) - String
Valid email address
first_name (optional) - String
Lead's first name (max 255 characters)
last_name (optional) - String
Lead's last name (max 255 characters)
business_name (optional) - String
Company or business name (max 255 characters)
website_url (optional) - String
Valid website URL (max 255 characters)
comments (optional) - String
Additional notes or comments (max 1000 characters)
timezone (optional) - String
Valid IANA timezone (see Timezones section)
status (optional) - Integer
Lead status (0-7)
Custom Fields
You can update custom fields by passing them as strings. New custom fields will be added, existing ones will be updated, and missing ones will be preserved.
{
"email": "jane.smith.updated@example.com",
"status": 4,
"comments": "Qualified lead - ready for sales call",
"lead_source": "referral",
"priority": "high"
}
{
"data": {
"id": 3,
"email": "jane.smith.updated@example.com",
"first_name": "Jane",
"last_name": "Smith",
"phone_number": "+19871231232",
"business_name": "Smith Consulting",
"website": "https://smithconsulting.com",
"client_id": 21,
"comments": "Qualified lead - ready for sales call",
"timezone": "America/New_York",
"was_recently_created": false,
"created_at": "2025-08-29T17:47:03.000000Z",
"updated_at": "2025-08-29T17:47:53.000000Z",
"lead_source": "referral",
"campaign_id": "summer_2024",
"industry": "consulting",
"priority": "high"
},
"message": "Lead updated successfully."
}
Method: GET
This endpoint returns a list of all Knowledge Bases in your account in alphabetical order.
https://app.salescloser.ai/api/v2/knowledge-bases
{
"data": [
{
"id": 1,
"client_id": 21,
"name": "Product Documentation",
"agents": [],
"knowledgeBaseFiles": [
{
"id": 1,
"title": "Product Documentation",
"type": "text",
"status": 1
}
]
},
{
"id": 2,
"client_id": 21,
"name": "FAQ Knowledge Base",
"agents": [],
"knowledgeBaseFiles": []
}
]
}
Method: POST
This endpoint creates a new Knowledge Base.
https://app.salescloser.ai/api/v2/knowledge-bases
name (required) - String
Name of the knowledge base (max 255 characters)
{
"name": "Product Documentation"
}
{
"data": {
"id": 1,
"client_id": 21,
"name": "Product Documentation",
"agents": [],
"knowledgeBaseFiles": [
{
"id": 1,
"title": "Product Documentation",
"type": "text",
"status": 1
}
]
},
"message": "Knowledge base created successfully."
}
Method: GET
This endpoint retrieves a specific Knowledge Base by ID.
https://app.salescloser.ai/api/v2/knowledge-bases/{knowledgeBaseId}
knowledgeBaseId (required) - Integer
The ID of the knowledge base to retrieve
{
"data": {
"id": 1,
"client_id": 21,
"name": "Product Documentation",
"agents": [],
"knowledgeBaseFiles": [
{
"id": 1,
"title": "Product Documentation",
"type": "text",
"status": 1
}
]
}
}
Method: PATCH
This endpoint updates an existing Knowledge Base. All fields are optional - only provide the fields you want to update.
https://app.salescloser.ai/api/v2/knowledge-bases/{knowledgeBaseId}
knowledgeBaseId (required) - Integer
The ID of the knowledge base to update
name (optional) - String
Name of the knowledge base (max 255 characters)
{
"name": "Updated Product Documentation"
}
{
"data": {
"id": 1,
"client_id": 21,
"name": "Updated Product Documentation",
"agents": [],
"knowledgeBaseFiles": [
{
"id": 2,
"title": "Updated Product Documentation",
"type": "text",
"status": 1
}
]
},
"message": "Knowledge base updated successfully."
}
Method: POST
This endpoint creates a new Knowledge Base File with text content and links it to an existing Knowledge Base.
https://app.salescloser.ai/api/v2/knowledge-base-files
knowledgebase_id (required) - Integer
The ID of the knowledge base to link this file to. Must belong to your account.
content (required) - String
Plain text content to be stored in the knowledge base file.
{
"knowledgebase_id": 1,
"content": "This is additional documentation for the Product Documentation knowledge base. It includes detailed information about advanced features, troubleshooting guides, and best practices for using the product effectively."
}
{
"data": {
"id": 5,
"file_name": "text_content_1704067200_abc123def456.txt",
"title": "Text Content",
"type": "text",
"encoded_status": "pending"
},
"message": "Knowledge base file created successfully."
}
Method: DELETE
This endpoint deletes a Knowledge Base File. The file must belong to a Knowledge Base owned by your account.
https://app.salescloser.ai/api/v2/knowledge-base-files/{knowledgebaseFileId}
knowledgebaseFileId (required) - Integer
The ID of the knowledge base file to delete
{
"message": "Knowledge base file deleted successfully."
}
Method: POST
This endpoint attaches one or more knowledge bases to an agent. All knowledge bases must belong to your account and the agent must not already be attached to any of the provided knowledge bases.
https://app.salescloser.ai/api/v2/agents/{agentId}/knowledge-bases
agentId (required) - Integer
The ID of the agent to attach knowledge bases to. Must belong to your account.
knowledge_base_ids (required) - Array of Integers
An array of knowledge base IDs to attach to the agent. Must contain at least one ID. All knowledge bases must belong to your account.
{
"knowledge_base_ids": [1, 2, 3]
}
{
"message": "Knowledge bases attached to agent successfully."
}
If the agent is already attached to one or more of the provided knowledge bases:
{
"message": "The given data was invalid.",
"errors": {
"knowledge_base_ids": [
"Agent is already linked to knowledge base IDs: 1, 2"
]
}
}
Method: DELETE
This endpoint detaches a knowledge base from an agent. The agent must be attached to the knowledge base, and both must belong to your account.
https://app.salescloser.ai/api/v2/agents/{agentId}/knowledge-bases/{knowledgeBaseId}
agentId (required) - Integer
The ID of the agent to detach the knowledge base from. Must belong to your account.
knowledgeBaseId (required) - Integer
The ID of the knowledge base to detach. Must belong to your account and be attached to the agent.
{
"message": "Knowledge base detached from agent successfully."
}
If the agent is not attached to the knowledge base:
{
"message": "Agent is not attached to this knowledge base.",
"errors": {
"knowledge_base_id": [
"This agent is not linked to this knowledge base."
]
}
}
User Webhooks allow you to receive real-time notifications when specific events occur in your account. Configure your webhook URL in your account settings to start receiving events.
Webhooks are configured per client via settings:
All webhook requests include:
Content-Type: application/json
User-Agent: SalesCloser-Webhook/1.0
X-Webhook-Signature: {hmac-sha256-signature} // Only if signature is configured
If you have configured a webhook signature secret, each webhook request will include an X-Webhook-Signature header containing an HMAC-SHA256 hash. You should validate this signature to ensure the webhook is authentic.
How the signature is generated:
X-Webhook-Signature headerPHP Example:
// Get the raw request body (important: before any parsing)
$rawPayload = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = 'your_webhook_secret';
$expectedSignature = hash_hmac('sha256', $rawPayload, $secret);
if (hash_equals($expectedSignature, $receivedSignature)) {
// Signature is valid
$data = json_decode($rawPayload, true);
// Process the webhook...
} else {
// Invalid signature - reject the request
http_response_code(401);
exit('Invalid signature');
}
Use file_get_contents('php://input') to get the raw body. Don't use $_POST or parsed JSON.
Node.js Example (Express):
const crypto = require('crypto');
const express = require('express');
const app = express();
// Capture raw body before JSON parsing
app.use('/webhook', express.json({
verify: (req, res, buf) => {
req.rawBody = buf;
}
}));
app.post('/webhook', (req, res) => {
const rawBody = req.rawBody;
const receivedSignature = req.headers['x-webhook-signature'] || '';
const secret = 'your_webhook_secret';
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
if (receivedSignature.length === expectedSignature.length &&
crypto.timingSafeEqual(
Buffer.from(expectedSignature, 'utf8'),
Buffer.from(receivedSignature, 'utf8')
)) {
// Signature is valid
res.status(200).send('OK');
} else {
// Invalid signature
res.status(401).send('Invalid signature');
}
});
You must use the raw request body, not JSON.stringify(req.body). Re-stringifying may produce different JSON.
Python Example (Flask):
import hmac
import hashlib
import json
from flask import Flask, request
def verify_webhook_signature(payload: bytes, signature: str, secret: str) -> bool:
expected_signature = hmac.new(
secret.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected_signature, signature)
@app.route('/webhook', methods=['POST'])
def webhook():
# Get raw body before JSON parsing
raw_payload = request.get_data()
received_signature = request.headers.get('X-Webhook-Signature', '')
secret = 'your_webhook_secret'
if verify_webhook_signature(raw_payload, received_signature, secret):
data = json.loads(raw_payload)
# Process the webhook...
return 'OK', 200
else:
return 'Invalid signature', 401
Use request.get_data() to get raw bytes, not request.get_json().
Security Notes: Always use timing-safe comparison functions (like hash_equals in PHP, crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python) to prevent timing attacks. Store your webhook secret securely and validate the signature before processing any webhook data.
demo.completed)Triggered when a demo/call is completed.
{
"event": "demo.completed",
"data": {
"last_state_name": "string | null",
"status": "Completed | Incomplete | In Progress | Pending | Scheduled | Draft",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": {
"id": "number",
"uid": "string",
"title": "string",
"datetime": "2024-01-15T10:00:00Z",
"duration": "number",
"timezone": "string",
"user": "object",
"attendees": "array"
},
"answered_by": "number | null",
"call_started_at": "2024-01-15T10:00:00+00:00 | null",
"call_ended_at": "2024-01-15T10:30:00+00:00 | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "https://app.salescloser.ai/leads/{lead_id}",
"lead_comments": "string | null",
"lead_status": "Created | Open | Working | Disqualified | Qualified | Opportunity created | Opportunity lost | Customer",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"campaign_id": "number | null",
"campaign_title": "string | null",
"campaign_status": "Draft | Live | Scheduled | null",
"campaign_scheduled_at": "datetime | null",
"timestamp": "2024-01-15T10:30:00+00:00"
}
}
demo.started)Triggered when a demo/call starts.
{
"event": "demo.started",
"data": {
"last_state_name": "string | null",
"status": "Completed | Incomplete | In Progress | Pending | Scheduled | Draft",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": { ... },
"answered_by": "number | null",
"call_started_at": "2024-01-15T10:00:00+00:00 | null",
"call_ended_at": "2024-01-15T10:30:00+00:00 | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"campaign_id": "number | null",
"campaign_title": "string | null",
"campaign_status": "string | null",
"campaign_scheduled_at": "datetime | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
lead.created)Triggered when a new lead is created.
Note: This webhook uses lead_website_url instead of lead_website.
{
"event": "lead.created",
"data": {
"lead_id": "number",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_email": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website_url": "string | null",
"lead_comments": "string | null",
"lead_profile": "https://app.salescloser.ai/leads/{lead_id}",
"lead_status": "Created | Open | Working | Disqualified | Qualified | Opportunity created | Opportunity lost | Customer",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
lead.updated)Triggered when a lead's information is updated.
Note: This webhook uses lead_website_url instead of lead_website.
{
"event": "lead.updated",
"data": {
"lead_id": "number",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_email": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website_url": "string | null",
"lead_comments": "string | null",
"lead_profile": "https://app.salescloser.ai/leads/{lead_id}",
"lead_status": "string",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
lead.status_updated)Triggered when a lead's status changes.
Note: This webhook uses lead_website_url instead of lead_website.
{
"event": "lead.status_updated",
"data": {
"lead_id": "number",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_email": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website_url": "string | null",
"lead_comments": "string | null",
"lead_profile": "https://app.salescloser.ai/leads/{lead_id}",
"lead_status": "string",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
booking.scheduled)Triggered when a booking/appointment is scheduled during a call.
{
"event": "booking.scheduled",
"data": {
"last_state_name": "string | null",
"status": "string",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": {
"id": "number",
"uid": "string",
"title": "string",
"datetime": "2024-01-20T14:00:00Z",
"duration": 30,
"timezone": "America/New_York",
"user": "object",
"attendees": "array"
},
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"campaign_id": "number | null",
"campaign_title": "string | null",
"campaign_status": "string | null",
"campaign_scheduled_at": "datetime | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
step.started)Triggered when a specific step/state is started during a call.
Note: This webhook does NOT include Campaign data.
{
"event": "step.started",
"data": {
"state": "string",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
step.completed)Triggered when a specific step/state is completed during a call.
Note: This webhook does NOT include Campaign data.
{
"event": "step.completed",
"data": {
"state": "string",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
inbound_call.received)Triggered when an inbound call is received.
{
"event": "inbound_call.received",
"data": {
"last_state_name": "string | null",
"status": "string",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"campaign_id": "number | null",
"campaign_title": "string | null",
"campaign_status": "string | null",
"campaign_scheduled_at": "datetime | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
audio_transcript.created)Triggered when an audio transcript is generated for a call.
Note: This webhook does NOT include Campaign data.
{
"event": "audio_transcript.created",
"data": {
"audio_transcript": "https://app.salescloser.ai/demo-recordings/{uuid}/file",
"transcript_content": "WEBVTT\n\n00:00:00.000 --> 00:00:05.000\nHello, ...",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
recording.generated)Triggered when a call recording is generated and available.
Note: This webhook does NOT include Campaign data.
{
"event": "recording.generated",
"data": {
"call_recording_url": "https://app.salescloser.ai/demo-recordings/{uuid}/file",
"call_recording_type": "call_recording | shared_screen_with_speaker_view",
"call_recording_origin": "twilio | zoom | livekit",
"call_recording_share_url": "https://app.salescloser.ai/calls/public-view?demo_id={id}&signature={signature}",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"timestamp": "2024-01-15T10:00:00+00:00"
}
}
guest_joined_demo)Triggered when a guest joins a web call/demo.
Note: This webhook does NOT include a timestamp field and uses a different dispatch mechanism.
{
"guest_name": "string",
"guest_email": "string",
"last_state_name": "string | null",
"status": "string",
"next_steps": "string | null",
"summary_background": "string | null",
"meeting_id": "string | null",
"final_step_reached": "string | null",
"minutes": "number | null",
"zoom_url": "string | null",
"booking": "object | null",
"answered_by": "number | null",
"call_started_at": "datetime | null",
"call_ended_at": "datetime | null",
"lead_id": "number",
"lead_email": "string | null",
"lead_first_name": "string | null",
"lead_last_name": "string | null",
"lead_phone_number": "string | null",
"lead_business_name": "string | null",
"lead_website": "string | null",
"lead_profile": "string",
"lead_comments": "string | null",
"lead_status": "string",
"agent_id": "number",
"agent_company_name": "string",
"agent_agent_name": "string",
"agent_agent_position": "string | null",
"agent_company_category": "string | null",
"agent_description": "string | null",
"agent_pain_points": "string | null",
"agent_language": "string",
"agent_additional_information": "string | null",
"campaign_id": "number | null",
"campaign_title": "string | null",
"campaign_status": "string | null",
"campaign_scheduled_at": "datetime | null"
}
| Value | Label |
|---|---|
| 0 | Created |
| 1 | Open |
| 2 | Working |
| 3 | Disqualified |
| 4 | Qualified |
| 5 | Opportunity created |
| 6 | Opportunity lost |
| 7 | Customer |
Leads can have custom metadata fields. These are included in the webhook payload with the prefix lead_. For example, if a lead has metadata { "company_size": "50-100" }, the webhook will include:
{
"lead_company_size": "50-100"
}
These are the timezones you can use for your leads and campaigns. When uploading timezones via a CSV file, make sure the format strictly follows standard IANA timezone names. Incorrect formatting may result in scheduling issues.
America/New_York
Asia/Karachi
Europe/London
GMT
UTC+5
america/new_york
New York
Timezones are case-sensitive and must exactly match standard IANA formats. Informal or incorrect names will lead to campaign or lead scheduling errors.