Skip to main content

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:

ParameterDefaultMaximum
page1โ€”
per_page15100

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:

CodeHTTP StatusMeaning
UNAUTHORIZED401Missing or invalid API key
FORBIDDEN403API key lacks the required scope
NOT_FOUND404Record does not exist
VALIDATION_FAILED422Request data failed validation
RATE_LIMITED429Too many requests
SERVER_ERROR500Unexpected 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:

ParameterDescription
sourceFilter by source (e.g. facebook, website)
statusFilter by status (e.g. new, contacted, qualified)
pipeline_idFilter by pipeline ID
stage_idFilter by pipeline stage ID
assigned_user_idFilter by assigned user ID
tagFilter by tag name
searchSearch by name, email, or phone
created_afterISO 8601 date โ€” only leads created after this date
created_beforeISO 8601 date โ€” only leads created before this date
starredtrue to show only starred leads
sortField to sort by: created_at, updated_at, lead_score, first_name, last_name, email
directionasc 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();