Skip to content

Send in a lead

POST
/v1/leads
curl --request POST \
--url https://api.threadkite.app/v1/leads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "contact": { "contactId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "externalId": { "integration": "my-dms", "externalId": "CUST-10442" }, "name": "Sarah Turner", "email": "sarah.turner@example.co.uk", "phone": "07911 123456", "company": { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "name": "Acme Fleet Services", "domain": "acme.co.uk", "companyNumber": "01234567", "externalId": { "integration": "my-dms", "externalId": "CUST-10442" }, "jobTitle": "Head of Transport", "role": "Director" } }, "source": "website-form", "sourceId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "channel": "form", "inboxId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "locationId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "items": [ { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "source": "my-dms", "externalId": "example", "identifier": "SKU-1042", "label": "Tow bar", "quantity": 1, "addOns": [ { "id": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "source": "my-dms", "externalId": "example", "identifier": "SKU-1042", "label": "Tow bar", "quantity": 1 } ] } ], "leadType": "finance", "subject": "example", "message": "", "consent": { "channels": { "email": "opted_in", "sms": "opted_in", "whatsapp": "opted_in", "phone": "opted_in" }, "categories": [ "marketing_email" ], "version": "example" }, "tracking": { "landingPageUrl": "example", "referrer": "example", "utmSource": "google", "utmMedium": "cpc", "utmCampaign": "example", "utmTerm": "example", "utmContent": "example", "utmId": "example", "clickId": "gclid:Cj0KCQjw", "analyticsCorrelation": "example" }, "fields": { "additionalProperty": "example" }, "externalId": "example", "receivedAt": "2026-04-15T12:00:00Z" }'

Finds the contact (your id, then email, then phone) or adds one, adds the message to their thread in the inbox you name (inboxId, else the default inbox) and applies the lead rule: it is a new lead unless the same contact, source and item sent one to that inbox within your lead period. Send an Idempotency-Key header, or an externalId, so retries never create a second lead.

Media typeapplication/json
object
contact
required
object
contactId

A Threadkite contact id, if you have it

string format: uuid
externalId

The contact’s id in your system

object
integration
required

The other system, e.g. my-dms

string

Example

my-dms
externalId
required

The contact’s id there

string

Example

CUST-10442
name
string
nullable <= 200 characters

Example

Sarah Turner
email
string
nullable <= 254 characters

Example

sarah.turner@example.co.uk
phone
string
nullable <= 40 characters

Example

07911 123456
company

The company they work for, found or made (see CompanyCaptureDto): linked as their primary company when they have none

object
id

One of your companies

string format: uuid
name

Its name: the company with that name, or a new one when nothing else finds one

string
>= 1 characters <= 200 characters

Example

Acme Fleet Services
domain

Its web domain (or website address): finds the company with it

string
<= 253 characters

Example

acme.co.uk
companyNumber

Its registered number (Companies House)

string
<= 30 characters

Example

01234567
externalId

The company’s id in your system

object
integration
required

The other system, e.g. my-dms

string

Example

my-dms
externalId
required

The contact’s id there

string

Example

CUST-10442
jobTitle

Their job title there

string
<= 120 characters

Example

Head of Transport
role

What they do for the company, in your words

string
<= 80 characters

Example

Director
source

Source key; created if new, e.g. website-form or google-ads

string
/^[a-z0-9][a-z0-9_.-]{0,49}$/

Example

website-form
sourceId

Or a source id

string format: uuid
channel
string
default: api
Allowed values: form api email phone chat marketplace
inboxId

The inbox the lead goes to (Sales, Service…). The default inbox when left out; a key limited to inboxes must name one of them, or its first when the default is not one

string format: uuid
locationId
string format: uuid
nullable
items

What the lead is about, main item first: catalogue items or free-text lines, each with its add-ons

Array<object>
<= 20 items
object
id

A Threadkite item id

string format: uuid
source

The item’s source, with externalId

string
<= 50 characters

Example

my-dms
externalId

The item’s id in that source

string
>= 1 characters <= 200 characters
identifier

An identifier on the item, matched exactly (a SKU or a pack identifier)

string
<= 50 characters

Example

SKU-1042
label

A free-text line, when it is not in the catalogue

string
>= 1 characters <= 200 characters

Example

Tow bar
quantity
integer
>= 1 <= 9999
addOns

Added to this item (a warranty, delivery, build options)

Array<object>
<= 20 items
object
id

A Threadkite item id

string format: uuid
source

The item’s source, with externalId

string
<= 50 characters

Example

my-dms
externalId

The item’s id in that source

string
>= 1 characters <= 200 characters
identifier

An identifier on the item, matched exactly (a SKU or a pack identifier)

string
<= 50 characters

Example

SKU-1042
label

A free-text line, when it is not in the catalogue

string
>= 1 characters <= 200 characters

Example

Tow bar
quantity
integer
>= 1 <= 9999
leadType
string
nullable <= 50 characters

Example

finance
subject
string
nullable <= 500 characters
message
string
"" <= 50000 characters

Example

Is this still available?
consent
object
channels
object
email
string
Allowed values: opted_in opted_out unknown
sms
string
Allowed values: opted_in opted_out unknown
whatsapp
string
Allowed values: opted_in opted_out unknown
phone
string
Allowed values: opted_in opted_out unknown
categories
Array<string>
<= 20 items

Example

[
"marketing_email"
]
version

The wording version shown

string
nullable <= 200 characters
tracking
object
landingPageUrl
string
nullable <= 2000 characters
referrer
string
nullable <= 2000 characters
utmSource
string
nullable <= 200 characters

Example

google
utmMedium
string
nullable <= 200 characters

Example

cpc
utmCampaign
string
nullable <= 200 characters
utmTerm
string
nullable <= 200 characters
utmContent
string
nullable <= 200 characters
utmId

The ad platform’s campaign id (utm_id)

string
nullable <= 200 characters
clickId

The ad click id as kind:value, where kind is gclid, gbraid, wbraid, msclkid, fbclid or ttclid

string
nullable <= 500 characters

Example

gclid:Cj0KCQjw
analyticsCorrelation

Analytics visitor id

string
nullable <= 200 characters
fields
Any of:
Array<object>
<= 100 items
object
label
required

The question, as the form asks it

string
>= 1 characters <= 100 characters

Example

Annual income
value
required

The answer

string
<= 5000 characters

Example

£32,000
section

The part of the form it was in

string
nullable <= 100 characters

Example

Employment
externalId

Your id for the lead; repeats are ignored

string
<= 500 characters
receivedAt

When it was received (defaults to now)

string format: date-time
Media typeapplication/json
object
contactId
required
string format: uuid
threadId
required
string format: uuid
inboxId
required

The inbox it went to

string format: uuid
messageId
required
string format: uuid
isLead
required

Counted as a new lead (false when the same contact, source and item already sent one to the same inbox within the lead period)

boolean
createdContact
required
boolean
createdThread
required
boolean
duplicate
required

The externalId was already received; nothing new was stored

boolean
matchedBy
required

How the contact was matched; null for a new contact

string
nullable
Allowed values: id external_id email phone
conflict
required
One of:
object
emailContactId
required
string format: uuid
phoneContactId
required

The phone number is also on this contact

string format: uuid

Example

{
"matchedBy": "id"
}
Media typeapplication/json
object
statusCode
required
number
code
required

Stable machine-readable reason

string
message
required
string
errors

With code invalid: every problem with the request, by field (message is the first)

Array<object>
object
path
required

Dotted path inside the item, e.g. attributes.price.amountMinor

string
message
required
string

Example

{
"statusCode": 403,
"code": "forbidden",
"message": "You do not have permission to do that.",
"errors": [
{
"message": "Enter the make"
}
]
}

Missing or invalid API key

Media typeapplication/json
object
statusCode
required
number
code
required

Stable machine-readable reason

string
message
required
string
errors

With code invalid: every problem with the request, by field (message is the first)

Array<object>
object
path
required

Dotted path inside the item, e.g. attributes.price.amountMinor

string
message
required
string

Example

{
"statusCode": 403,
"code": "forbidden",
"message": "You do not have permission to do that.",
"errors": [
{
"message": "Enter the make"
}
]
}

The organisation is on the Free plan (code upgrade_required)

Media typeapplication/json
object
statusCode
required
number
code
required

Stable machine-readable reason

string
message
required
string
feature
required

The feature that needs Pro

string
nullable
Allowed values: extraSeats connections aiAssistant aiReplies rules fullReports api inboxes bulkMessages videoMessages
upgradePath
required

Where to upgrade or pay, in the web app

string

Example

{
"statusCode": 402,
"code": "upgrade_required",
"message": "Connections are part of Pro. Upgrade to connect texts, calls and more.",
"feature": "extraSeats",
"upgradePath": "/settings/billing"
}

The key does not have the scope (or the person the permission)

Media typeapplication/json
object
statusCode
required
number
code
required

Stable machine-readable reason

string
message
required
string
errors

With code invalid: every problem with the request, by field (message is the first)

Array<object>
object
path
required

Dotted path inside the item, e.g. attributes.price.amountMinor

string
message
required
string

Example

{
"statusCode": 403,
"code": "forbidden",
"message": "You do not have permission to do that.",
"errors": [
{
"message": "Enter the make"
}
]
}

Rate limit reached

Media typeapplication/json
object
statusCode
required
number
code
required

Stable machine-readable reason

string
message
required
string
retryAfter
required

Seconds until another request will be accepted

number

Example

{
"statusCode": 429,
"code": "rate_limited",
"message": "Too many requests. Each key can make 120 requests a minute; try again in 12 seconds.",
"retryAfter": 12
}