Book an appointment
const url = 'https://api.threadkite.app/v1/appointments';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"threadId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","type":"consultation","startsAt":"2026-04-15T12:00:00Z","endsAt":"2026-04-15T12:00:00Z","hostUserId":"example","locationId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","itemId":"2489E9AD-2EE2-8E00-8EC9-32D5F69181C0","notes":"example","notifyChannel":"email"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.threadkite.app/v1/appointments \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "threadId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "type": "consultation", "startsAt": "2026-04-15T12:00:00Z", "endsAt": "2026-04-15T12:00:00Z", "hostUserId": "example", "locationId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "itemId": "2489E9AD-2EE2-8E00-8EC9-32D5F69181C0", "notes": "example", "notifyChannel": "email" }'From a thread with a contact. With notifyChannel, the customer is sent a confirmation now (with a calendar file by email), reminders the day before and two hours before, and any changes. If their consent or details don’t allow it, the appointment is still booked and notifyFailure says why.
Authorizations
Section titled “Authorizations”Request Bodyrequired
Section titled “Request Bodyrequired”object
The thread it is booked from
An id from GET /v1/appointment-types
Example
consultationWhen it ends; defaults to the type’s usual length
Who it is with (a Full seat who can see the thread). Defaults to you, else the thread owner.
Where it is; defaults to the thread’s location
What it is about; defaults to the thread’s item
Send a confirmation, reminders (the day before and two hours before) and any changes on this channel. Null sends nothing.
Responses
Section titled “Responses”object
The thread’s inbox
object
The time zone it is written in
object
object
The channel the customer is told on (null: not told)
Why the latest message to the customer wasn’t sent, if it wasn’t
Why it was cancelled (for the team)
object
You can move, cancel and mark it
Example
{ "contact": { "name": "Sarah Turner" }, "type": "consultation", "typeLabel": "Consultation", "timeZone": "Europe/London", "status": "booked", "host": { "id": "usr_8f2c", "name": "James Patel" }, "item": { "title": "Oak dining table" }, "notifyChannel": "email", "notifyFailure": "They have opted out of texts.", "createdBy": { "id": "usr_8f2c", "name": "James Patel" }}object
Stable machine-readable reason
With code invalid: every problem with the request, by field (message is the first)
object
Dotted path inside the item, e.g. attributes.price.amountMinor
Example
{ "statusCode": 403, "code": "forbidden", "message": "You do not have permission to do that.", "errors": [ { "message": "Enter the make" } ]}Missing or invalid API key
object
Stable machine-readable reason
With code invalid: every problem with the request, by field (message is the first)
object
Dotted path inside the item, e.g. attributes.price.amountMinor
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)
object
Stable machine-readable reason
The feature that needs Pro
Where to upgrade or pay, in the web app
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)
object
Stable machine-readable reason
With code invalid: every problem with the request, by field (message is the first)
object
Dotted path inside the item, e.g. attributes.price.amountMinor
Example
{ "statusCode": 403, "code": "forbidden", "message": "You do not have permission to do that.", "errors": [ { "message": "Enter the make" } ]}object
Stable machine-readable reason
With code invalid: every problem with the request, by field (message is the first)
object
Dotted path inside the item, e.g. attributes.price.amountMinor
Example
{ "statusCode": 403, "code": "forbidden", "message": "You do not have permission to do that.", "errors": [ { "message": "Enter the make" } ]}Rate limit reached
object
Stable machine-readable reason
Seconds until another request will be accepted
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}