Skip to content

Add threads and their history to an import

POST
/v1/imports/{id}/threads
curl --request POST \
--url https://api.threadkite.app/v1/imports/2489E9AD-2EE2-8E00-8EC9-32D5F69181C0/threads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "threads": [ { "externalId": "deal-1042", "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" } }, "inboxId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "lead": { "at": "2026-04-15T12:00:00Z", "channel": "form", "source": "facebook", "subject": "example", "message": "", "fields": { "additionalProperty": "example" }, "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 } ] } ] }, "entries": [], "owner": { "email": "sam@example.co.uk", "name": "Sam Lee" }, "state": "open", "outcome": "deal", "outcomeNote": "example", "closedAt": "2026-04-15T12:00:00Z", "tags": [ "Trialling" ] } ] }'

Up to 25 threads at a time, each with its contact, the lead that started it, and its messages, notes and events in any order. Contacts are matched as leads are (your id, then email, then phone), so someone already in Threadkite is found, not added again; history for a contact whose current thread is here goes on that thread, which keeps its own owner and state. Each thread is matched on the import’s source and its externalId, and each entry on its own externalId (or when it happened and what it says), so sending the same thread again, in this import or a later one, adds only what is new. A thread that cannot be imported is reported as failed (a refusal writes nothing; send it again to finish one that stopped part way); the rest still go in.

id
required
string format: uuid
Media typeapplication/json
object
threads
required
Array<object>
>= 1 items <= 25 items
object
externalId
required

Its id in the other system (a deal, ticket or lead)

string
>= 1 characters <= 200 characters

Example

deal-1042
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
inboxId

The default inbox when left out

string format: uuid
lead

The lead that started it, counted as a lead on its date. Without one, the thread starts with its first message

object
at
required

When they first got in touch

string format: date-time
channel
string
default: api
Allowed values: form api email phone chat marketplace
source

The lead source, as a key; made if new

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

Example

facebook
subject
string
nullable <= 500 characters
message
string
"" <= 50000 characters
fields

Other details from the old system, shown with the lead (question to answer)

object
key
additional properties
string
items

What it is about: catalogue items or free-text lines, with 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
entries

Its messages, notes and events, in any order

Array<object>
default: <= 1000 items
object
kind
required

message: from or to the contact; note: the team’s internal note; event: a line in the timeline (a stage change, a call logged)

string
Allowed values: message note event
direction

For messages: in from the contact, out from your team

string
Allowed values: in out
channel

For messages; email when left out

string
Allowed values: email sms whatsapp chat phone form api marketplace visit messenger instagram

Example

email
at
required

When it happened

string format: date-time

Example

2026-08-06T13:00:48Z
subject
string
nullable <= 500 characters
text
string
"" <= 100000 characters
html

Email as it was sent or received, shown as it was

string
nullable <= 500000 characters
author

Who on your team wrote it (outgoing messages, notes and events)

object
email

Matched to a member of your team: their messages and notes show as theirs, and an owner given this way gets the thread

string
<= 254 characters

Example

sam@example.co.uk
name

Shown when the email is not one of your team

string
<= 200 characters

Example

Sam Lee
participants

Email: every address on it as it was sent (from, to, cc)

Array<object>
<= 100 items
object
role
required
string
Allowed values: from to cc
address
required
string
>= 1 characters <= 254 characters
name
string
nullable <= 200 characters
externalId

Its id in the other system. Without one, an entry is recognised by when it happened and what it says

string
>= 1 characters <= 200 characters
owner

Who looks after it: a member of your team, by email

object
email

Matched to a member of your team: their messages and notes show as theirs, and an owner given this way gets the thread

string
<= 254 characters

Example

sam@example.co.uk
name

Shown when the email is not one of your team

string
<= 200 characters

Example

Sam Lee
state
string
default: open
Allowed values: open done
outcome

For a done thread: deal (won), lost, none or no_reply

string
Allowed values: deal lost none no_reply
outcomeNote
string
<= 1000 characters
closedAt

When it was closed; its last entry when left out

string format: date-time
tags

Tags as well as the import’s own (made if new)

Array<string>
<= 20 items

Example

[
"Trialling"
]
Media typeapplication/json
object
import
required

A batch of history brought in from another system

object
id
required
string format: uuid
source
required
string
name
required
string
status
required

open takes more threads; undone has had what it made removed

string
Allowed values: open undone
tag
required
object
id
required
string format: uuid
name
required
string
threadsCreated
required
integer
>= -9007199254740991 <= 9007199254740991
threadsUpdated
required

Threads already in Threadkite that it added history to

integer
>= -9007199254740991 <= 9007199254740991
contactsCreated
required
integer
>= -9007199254740991 <= 9007199254740991
messagesImported
required

Messages, notes and events stored

integer
>= -9007199254740991 <= 9007199254740991
createdAt
required
string format: date-time
undoneAt
required
string format: date-time
nullable
results
required
Array<object>
object
externalId
required
string
status
required

created: a new thread; updated: history added to a thread already in Threadkite (imported before, or the contact’s current thread); failed: nothing written, see error

string
Allowed values: created updated failed
threadId
required
string format: uuid
nullable
contactId
required
string format: uuid
nullable
entriesImported
required
integer
>= -9007199254740991 <= 9007199254740991
entriesSkipped
required

Entries already there from an earlier run

integer
>= -9007199254740991 <= 9007199254740991
error
required
object
code
required
string
message
required
string

Example

{
"import": {
"source": "pipedrive",
"status": "open"
},
"results": [
{
"status": "created"
}
]
}
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"
}
]
}
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"
}
]
}
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
}