curl -X POST https://client-backend.oktivo.com/api/v1/crm/leads \
-H "Authorization: Bearer okt_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"metadata": { "source": "website" },
"customFields": {
"course": "Data Science",
"campaign": "spring-2026"
}
}'
const res = await fetch(
"https://client-backend.oktivo.com/api/v1/crm/leads",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OKTIVO_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Priya Sharma",
phone: "9876543210",
email: "[email protected]",
metadata: { source: "website" },
customFields: { course: "Data Science" },
}),
}
);
const data = await res.json();
import os, requests
res = requests.post(
"https://client-backend.oktivo.com/api/v1/crm/leads",
headers={
"Authorization": f"Bearer {os.environ['OKTIVO_API_TOKEN']}",
"Content-Type": "application/json",
},
json={
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"metadata": {"source": "website"},
"customFields": {"course": "Data Science"},
},
)
print(res.json())
{
"success": true,
"merged": false,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"opportunityValue": null,
"opportunityId": null,
"source": "website",
"customFields": { "course": "Data Science", "campaign": "spring-2026" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T09:12:33.000Z"
}
}
{
"success": true,
"merged": true,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "contacted",
"leadTemperature": "hot",
"source": "website",
"customFields": { "course": "Data Science" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T10:40:01.000Z"
}
}
{
"success": false,
"message": "Validation failed",
"errors": [
{ "field": "phone", "message": "Provide a phone number or an email address" }
]
}
{
"success": false,
"message": "A lead with this phone already exists for source \"api\"",
"code": "DUPLICATE_LEAD_SOURCE"
}
Leads
Capture a Lead
Create (or merge into) a lead in your Oktivo CRM dashboard.
POST
/
api
/
v1
/
crm
/
leads
curl -X POST https://client-backend.oktivo.com/api/v1/crm/leads \
-H "Authorization: Bearer okt_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"metadata": { "source": "website" },
"customFields": {
"course": "Data Science",
"campaign": "spring-2026"
}
}'
const res = await fetch(
"https://client-backend.oktivo.com/api/v1/crm/leads",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OKTIVO_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Priya Sharma",
phone: "9876543210",
email: "[email protected]",
metadata: { source: "website" },
customFields: { course: "Data Science" },
}),
}
);
const data = await res.json();
import os, requests
res = requests.post(
"https://client-backend.oktivo.com/api/v1/crm/leads",
headers={
"Authorization": f"Bearer {os.environ['OKTIVO_API_TOKEN']}",
"Content-Type": "application/json",
},
json={
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"metadata": {"source": "website"},
"customFields": {"course": "Data Science"},
},
)
print(res.json())
{
"success": true,
"merged": false,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"opportunityValue": null,
"opportunityId": null,
"source": "website",
"customFields": { "course": "Data Science", "campaign": "spring-2026" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T09:12:33.000Z"
}
}
{
"success": true,
"merged": true,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "contacted",
"leadTemperature": "hot",
"source": "website",
"customFields": { "course": "Data Science" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T10:40:01.000Z"
}
}
{
"success": false,
"message": "Validation failed",
"errors": [
{ "field": "phone", "message": "Provide a phone number or an email address" }
]
}
{
"success": false,
"message": "A lead with this phone already exists for source \"api\"",
"code": "DUPLICATE_LEAD_SOURCE"
}
Push a lead into your Oktivo CRM from any external system — a website form, a
chatbot, an ad platform, a payment flow, or your own backend. The same person
arriving more than once is intelligently de-duplicated into a single lead with a
full source history, so you can fire this endpoint freely without creating
duplicates.
Generate a token in the dashboard under Settings → API Tokens → Create Token
(
Authentication
This endpoint accepts an API Token (okt_...), or a logged-in JWT. Send
it as a Bearer token:
Authorization: Bearer okt_your_token_here
app.oktivo.com/account). The okt_... value is shown only once — copy it
immediately. Accounts allow up to 5 active tokens. See
Capturing Leads via API for a
step-by-step walkthrough and Authentication for rotation and
expiry.
The lead is always scoped to the token owner’s account — you cannot create
leads in another account. The
crm_api feature must be enabled on your plan.Identity Rule
A lead must be reachable, so at least one ofphone or email is required.
name is optional. If you send neither a phone nor an email, the request is
rejected with a 400.
Phone numbers are accepted in any common format and normalized to E.164. A
10-digit Indian mobile such as 9876543210 becomes +919876543210; an
already-E.164 value like +14155551234 is kept as-is.
Request Body
string
Contact’s display name. Optional. Maximum 200 characters. Aliases accepted
(first present wins, in this order):
name, contactName, contact_name,
fullName, full_name.string
Phone number. Any format is accepted and normalized to E.164. Required unless
email is provided.string
Email address. Validated when present. Required unless
phone is provided.string
Pipeline stage for the lead, e.g.
new, contacted, qualified,
negotiation, won, lost. Custom statuses configured for your org are also
accepted. Defaults to your pipeline’s first stage when omitted.string
Intent signal. One of
hot, warm, cold.number
The lead’s primary deal amount. Accepts a plain number or a numeric string
(e.g.
"₹2,50,000" → 250000). Feeds the dashboard opportunity funnel.object
Acquisition attribution.
Any other
Show metadata properties
Show metadata properties
string
How the lead arrived. Only a known Oktivo source value is honoured;
anything else falls back to
api. See Lead Sources below.string
Submitter’s IP address. If omitted, it is captured from the request. Used
as a match signal for ad-platform conversion APIs.
string
Submitter’s User-Agent. If omitted, it is captured from the request.
metadata key (for example a platform’s verbatim eventType) is
stored as-is on the lead.object
A bag of custom fields to store on the lead (
industryData and fields are
accepted aliases). Keys max 50 characters, string values max 2000 characters.
Maximum 50 custom fields per lead.You can also send custom fields as plain top-level keys — any body key that is
not a reserved field name is treated as a custom field. The explicit
customFields object wins on key collisions.Example: {"course": "Data Science", "campaign": "spring-2026"}string
Optional web-tracking visitor id. When present, the lead is stitched to that
visitor’s prior anonymous web activity.
visitor_id is also accepted.Deduplication
Oktivo keeps one lead per phone (or email) per account. How a repeat arrival is handled depends on the source:- A repeat from a new source always merges into the existing lead and appends an entry to its source history.
- A repeat from a source the lead already has returns a
409for curated sources (manual,csv_import,api,webhook) to protect your data from accidental overwrites. - For self-service / event-stream sources (
website,chatbot,landing,whatsapp,google_form,ai_powered_lead,payment_page_drop) a repeat always merges and the latest non-empty values win — so returning visitors and re-fired events never 409.
"merged": true and returns a 200. A brand-new lead returns 201 with
"merged": false.
Lead Sources
Setmetadata.source to attribute the lead. Only these canonical values are
honoured; any other value is stored as api.
| Source | Meaning |
|---|---|
api | Generic programmatic ingestion (default) |
webhook | Forwarded from an external webhook |
website | Website capture form |
chatbot | Website / app chatbot |
whatsapp | WhatsApp conversation |
google_form | Google Form submission |
facebook_ad / google_ad | Ad-platform lead |
ai_powered_lead | Your AI lead-scoring engine |
payment_page_drop | Abandoned checkout |
landing | Hosted landing page demo request |
Response
boolean
true when the lead was created or merged.boolean
true when the request merged into an existing lead (200); false for a
newly created lead (201).object
Show data properties
Show data properties
string
Unique identifier for the lead.
string
Linked contact identifier (used when triggering calls).
string
Resolved contact name.
string
Normalized E.164 phone.
string
Normalized email.
string
Pipeline stage.
string
Lead temperature.
number
Primary deal amount, or
null.string
Created opportunity id, or
null.string
Resolved canonical source.
object
Stored custom fields.
string
ISO timestamp.
string
ISO timestamp.
curl -X POST https://client-backend.oktivo.com/api/v1/crm/leads \
-H "Authorization: Bearer okt_your_token_here" \
-H "Content-Type: application/json" \
-d '{
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"metadata": { "source": "website" },
"customFields": {
"course": "Data Science",
"campaign": "spring-2026"
}
}'
const res = await fetch(
"https://client-backend.oktivo.com/api/v1/crm/leads",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.OKTIVO_API_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Priya Sharma",
phone: "9876543210",
email: "[email protected]",
metadata: { source: "website" },
customFields: { course: "Data Science" },
}),
}
);
const data = await res.json();
import os, requests
res = requests.post(
"https://client-backend.oktivo.com/api/v1/crm/leads",
headers={
"Authorization": f"Bearer {os.environ['OKTIVO_API_TOKEN']}",
"Content-Type": "application/json",
},
json={
"name": "Priya Sharma",
"phone": "9876543210",
"email": "[email protected]",
"metadata": {"source": "website"},
"customFields": {"course": "Data Science"},
},
)
print(res.json())
{
"success": true,
"merged": false,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "new",
"leadTemperature": "warm",
"opportunityValue": null,
"opportunityId": null,
"source": "website",
"customFields": { "course": "Data Science", "campaign": "spring-2026" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T09:12:33.000Z"
}
}
{
"success": true,
"merged": true,
"data": {
"leadId": "lead_7f8a9b0c1d2e",
"contactUID": "contact_3e4f5g6h7i8j",
"name": "Priya Sharma",
"phone": "+919876543210",
"email": "[email protected]",
"status": "contacted",
"leadTemperature": "hot",
"source": "website",
"customFields": { "course": "Data Science" },
"createdAt": "2026-10-06T09:12:33.000Z",
"updatedAt": "2026-10-06T10:40:01.000Z"
}
}
{
"success": false,
"message": "Validation failed",
"errors": [
{ "field": "phone", "message": "Provide a phone number or an email address" }
]
}
{
"success": false,
"message": "A lead with this phone already exists for source \"api\"",
"code": "DUPLICATE_LEAD_SOURCE"
}
Error Codes
| Code | Meaning |
|---|---|
| 400 | Validation failed — check the errors array (missing phone/email, bad email, >50 custom fields, oversized value) |
| 401 | Missing or invalid token |
| 403 | crm_api feature not enabled on your plan |
| 409 | Duplicate lead for this source (DUPLICATE_LEAD_SOURCE) or email already belongs to another lead (DUPLICATE_LEAD_EMAIL) |
| 429 | Rate limit exceeded — wait and retry |
| 500 | Internal server error |