REST API Reference
Overviewโ
LeadHub includes a complete REST API that lets external tools read and write your data โ leads, pipelines, automations, forms, and more. Use it to integrate with Zapier, build custom dashboards, connect your website, or automate anything.
Base URLโ
All API requests go to:
https://yourdomain.com/api/v1
Replace yourdomain.com with your actual LeadHub domain.
Authenticationโ
Every request (except the health check) requires an API key.
Create API keys in the admin panel at Settings โ API Keys. See the Settings page for instructions.
Include your API key in every request as a Bearer token in the Authorization header:
Authorization: Bearer lh_your_api_key_here
If you send a request without an API key, or with an invalid key, you receive a 401 Unauthorized response.
Rate Limitingโ
Each API key is limited to 1,000 requests per hour by default (configurable per key). If you exceed this limit, you receive a 429 Too Many Requests response.
Every response includes these headers so you can track your usage:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 847
X-RateLimit-Reset: 1711580400
X-RateLimit-Reset is a Unix timestamp of when your limit resets.
Paginationโ
Endpoints that return lists of records support pagination. Add these query parameters:
| Parameter | Default | Maximum |
|---|---|---|
page | 1 | โ |
per_page | 15 | 100 |
Example: GET /api/v1/leads?page=2&per_page=25
Response Formatโ
Success Responseโ
{
"data": { ... },
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 15,
"total": 73,
"from": 1,
"to": 15
},
"links": {
"first": "https://yourdomain.com/api/v1/leads?page=1",
"last": "https://yourdomain.com/api/v1/leads?page=5",
"prev": null,
"next": "https://yourdomain.com/api/v1/leads?page=2",
"self": "https://yourdomain.com/api/v1/leads?page=1"
}
}
For single-record responses (show, create, update), data contains the record object and meta is omitted.
Error Responseโ
{
"status": "error",
"message": "The given data was invalid.",
"code": "VALIDATION_FAILED",
"errors": {
"email": ["The email field must be a valid email address."]
}
}
Common error codes:
| Code | HTTP Status | Meaning |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid API key |
FORBIDDEN | 403 | API key lacks the required scope |
NOT_FOUND | 404 | Record does not exist |
VALIDATION_FAILED | 422 | Request data failed validation |
RATE_LIMITED | 429 | Too many requests |
SERVER_ERROR | 500 | Unexpected server error |
Health Checkโ
No authentication required.
GET /api/v1/health
Response:
{
"status": "ok",
"version": "1.0.0",
"timestamp": "2026-03-28T09:15:00+00:00"
}
Use this to check if your LeadHub instance is reachable before making other requests.
Leadsโ
Required scope: read:leads to retrieve, write:leads to create/update, delete:leads to delete.
List Leadsโ
GET /api/v1/leads
Query parameters for filtering:
| Parameter | Description |
|---|---|
source | Filter by source (e.g. facebook, website) |
status | Filter by status (e.g. new, contacted, qualified) |
pipeline_id | Filter by pipeline ID |
stage_id | Filter by pipeline stage ID |
assigned_user_id | Filter by assigned user ID |
tag | Filter by tag name |
search | Search by name, email, or phone |
created_after | ISO 8601 date โ only leads created after this date |
created_before | ISO 8601 date โ only leads created before this date |
starred | true to show only starred leads |
sort | Field to sort by: created_at, updated_at, lead_score, first_name, last_name, email |
direction | asc or desc (default: desc) |
Get a Leadโ
GET /api/v1/leads/{id}
Create a Leadโ
POST /api/v1/leads
Request body (JSON):
{
"first_name": "Sarah",
"last_name": "Johnson",
"email": "[email protected]",
"phone": "+14155551234",
"source": "website",
"status": "new",
"pipeline_id": 1,
"pipeline_stage_id": 2,
"assigned_user_id": 5,
"notes": "Interested in the enterprise plan.",
"custom_fields": {
"budget": "10000"
},
"tags": ["hot-lead", "enterprise"]
}
first_name is required. All other fields are optional.
Update a Leadโ
PUT /api/v1/leads/{id}
PATCH /api/v1/leads/{id}
Send only the fields you want to update. Same fields as create.
Delete a Leadโ
DELETE /api/v1/leads/{id}
Add a Tag to a Leadโ
POST /api/v1/leads/{id}/tags
Body: { "tag": "vip-client" }
Remove a Tag from a Leadโ
DELETE /api/v1/leads/{id}/tags/{tag}
Pipelinesโ
Required scope: read:pipelines or write:pipelines
GET /api/v1/pipelines
POST /api/v1/pipelines
GET /api/v1/pipelines/{id}
PUT /api/v1/pipelines/{id}
PATCH /api/v1/pipelines/{id}
DELETE /api/v1/pipelines/{id}
Pipeline Stagesโ
GET /api/v1/pipelines/{pipeline_id}/stages
POST /api/v1/pipelines/{pipeline_id}/stages
GET /api/v1/pipelines/{pipeline_id}/stages/{stage_id}
PUT /api/v1/pipelines/{pipeline_id}/stages/{stage_id}
PATCH /api/v1/pipelines/{pipeline_id}/stages/{stage_id}
DELETE /api/v1/pipelines/{pipeline_id}/stages/{stage_id}
Tagsโ
Required scope: read:tags or write:tags
GET /api/v1/tags
POST /api/v1/tags
GET /api/v1/tags/{id}
PUT /api/v1/tags/{id}
PATCH /api/v1/tags/{id}
DELETE /api/v1/tags/{id}
Usersโ
Required scope: read:users, write:users, or delete:users
GET /api/v1/users
POST /api/v1/users
GET /api/v1/users/{id}
PUT /api/v1/users/{id}
PATCH /api/v1/users/{id}
DELETE /api/v1/users/{id}
Formsโ
Required scope: read:forms, write:forms, or delete:forms
GET /api/v1/forms
POST /api/v1/forms
GET /api/v1/forms/{id}
PUT /api/v1/forms/{id}
PATCH /api/v1/forms/{id}
DELETE /api/v1/forms/{id}
Submit a Formโ
POST /api/v1/forms/{id}/submissions
Body: the form field values as key-value pairs.
Automationsโ
Required scope: read:automations, write:automations, or delete:automations
GET /api/v1/automations
POST /api/v1/automations
GET /api/v1/automations/{id}
PUT /api/v1/automations/{id}
PATCH /api/v1/automations/{id}
DELETE /api/v1/automations/{id}
Integrationsโ
Required scope: read:integrations or write:integrations
GET /api/v1/integrations/types
GET /api/v1/integrations
POST /api/v1/integrations
GET /api/v1/integrations/{id}
PUT /api/v1/integrations/{id}
PATCH /api/v1/integrations/{id}
DELETE /api/v1/integrations/{id}
GET /api/v1/integrations/types returns the list of available integration types (Facebook, Google Ads, Mailgun, etc.).
Inbound Lead Intakeโ
A simplified endpoint for creating leads from external sources, webhooks, or no-code tools like Zapier and Make.
POST /api/inbound/leads?tenant={workspace-slug}
Authenticate with Authorization: Bearer {api_key} and pass the workspace slug as a query parameter.
Request body:
{
"email": "[email protected]",
"first_name": "Sarah",
"last_name": "Johnson",
"phone": "+14155551234",
"company": "Tech Corp",
"source": "zapier",
"notes": "Came from newsletter signup",
"tags": ["newsletter"],
"custom_fields": {
"utm_campaign": "spring-promo"
}
}
email is required. All other fields are optional.
Success response (201):
{
"status": "created",
"lead_id": 1842,
"is_duplicate": false
}
If the lead already exists (matched by email or phone), is_duplicate is true and the existing lead's ID is returned.
Code Examplesโ
cURLโ
curl -X GET "https://yourdomain.com/api/v1/leads?status=new&per_page=25" \
-H "Authorization: Bearer lh_your_api_key_here" \
-H "Accept: application/json"
curl -X POST "https://yourdomain.com/api/v1/leads" \
-H "Authorization: Bearer lh_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"first_name":"Sarah","email":"[email protected]","source":"api"}'
PHPโ
$apiKey = 'lh_your_api_key_here';
$baseUrl = 'https://yourdomain.com/api/v1';
// List leads
$response = file_get_contents($baseUrl . '/leads', false, stream_context_create([
'http' => [
'header' => "Authorization: Bearer {$apiKey}\r\nAccept: application/json\r\n",
],
]));
$leads = json_decode($response, true);
// Create a lead
$ch = curl_init($baseUrl . '/leads');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer {$apiKey}",
"Content-Type: application/json",
"Accept: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'first_name' => 'Sarah',
'email' => '[email protected]',
'source' => 'api',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
JavaScript (fetch)โ
const apiKey = 'lh_your_api_key_here';
const baseUrl = 'https://yourdomain.com/api/v1';
// List leads
const response = await fetch(`${baseUrl}/leads?status=new`, {
headers: {
'Authorization': `Bearer ${apiKey}`,
'Accept': 'application/json',
},
});
const { data, meta } = await response.json();
// Create a lead
const createResponse = await fetch(`${baseUrl}/leads`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
'Accept': 'application/json',
},
body: JSON.stringify({
first_name: 'Sarah',
email: '[email protected]',
source: 'website',
}),
});
const newLead = await createResponse.json();