Update thread
Update a thread. To patch many threads, call /threads/bulk-update once instead of looping here. Requires the threads:write scope.
curl -X PATCH "https://productlane.com/api/v2/threads/{id}" \
-H "Authorization: Bearer $PRODUCTLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"external_ids": [
"string"
],
"text": "string",
"title": "string",
"pain_level": "UNKNOWN",
"assignee_id": "string",
"contact_id": "string",
"company_id": "string",
"tag_ids": [
"string"
],
"project_id": "string",
"status": "open",
"snoozed_until": "2026-01-15T09:30:00Z",
"closed_loop": true,
"ai_draft_html": "string",
"ai_draft_sources": [
null
],
"clear_ai_draft_error": true,
"notify": {
"slack": true,
"email": true
}
}'Authorization
AuthorizationstringheaderrequiredBearer authentication header of the form
Bearer <token>, where<token>is your auth token.
Parameters
idstringpathrequired
Body
external_idsstring[]Caller-owned identifiers. Replaces the full set.
textstringtitlestring | nullpain_levelenum<string>One of:UNKNOWNLOWMEDIUMHIGHassignee_idstring | nullWorkspace user id. Pass
nullto unassign.contact_idstringcompany_idstring | nullPass
nullto detach. Also propagates onto the thread's contact.tag_idsstring[]Replaces the thread's full tag set.
project_idstring | nullstatusenum<string>When
snoozed,snoozed_untilis required.One of:opensnoozeddonesnoozed_untilstring<date-time>closed_loopbooleanWith
status=done, marks the thread as fully closed.ai_draft_htmlstring | nullHTML body prefilled into the composer for the next outbound reply. Setting this stamps
ai_draft_generated_atand clearsai_draft_started_at+ai_draft_error_at. Passnull(or an empty string) to clear the draft.ai_draft_sourcesany[] | nullSources the AI consulted while generating the draft. Surfaces in the composer's "Drafted by AI" tooltip. Shape:
{ type, title, identifier?, url? }[]. Passnullto clear.clear_ai_draft_errorbooleanWhen
true, clearsai_draft_error_at. Use this to dismiss a stuck error pill in the composer without writing a new draft.notifyobjectSide-channel notifications to fire alongside the write (Slack and/or email).
Response
Successful response
idstringrequirednumberinteger | nullrequiredTicket number shown to customers as
#123. Unique per workspace.created_atstringrequiredupdated_atstringrequiredtitlestring | nullrequiredtextstringrequiredpain_levelenum<string>requiredOne of:UNKNOWNLOWMEDIUMHIGHoriginstringrequiredcustom_channelstring | nullrequiredChannel name when
originiscustom, such aswhatsapp.statusenum<string>requiredOne of:opensnoozeddonetabenum<string>requiredOne of:opennewneeds-responsemysnoozeddonesnoozed_untilstring | nullrequiredlast_inbound_message_atstring | nullrequiredlast_outbound_message_atstring | nullrequiredlast_state_change_atstring | nullrequiredis_readbooleanrequiredcontactobject | nullrequiredcompanyobject | nullrequiredassigneeobject | nullrequiredreporterobject | nullrequiredtagsobject[]requiredcustomer_needsobject[]requiredexternal_idsstring[]requiredCaller-owned cross-system identifiers (CRM ids, etc.). Replaced wholesale on create/update.
integration_idsobjectrequiredai_draft_htmlstring | nullrequiredai_draft_sourcesany[] | nullrequiredai_draft_generated_atstring | nullrequiredai_draft_started_atstring | nullrequiredai_draft_error_atstring | nullrequired
{
"id": "string",
"number": 0,
"created_at": "string",
"updated_at": "string",
"title": "string",
"text": "string",
"pain_level": "UNKNOWN",
"origin": "string",
"custom_channel": "string",
"status": "open",
"tab": "open",
"snoozed_until": "string",
"last_inbound_message_at": "string",
"last_outbound_message_at": "string",
"last_state_change_at": "string",
"is_read": true,
"contact": {
"id": "string",
"email": "string",
"name": "string",
"image_url": "string",
"company_id": "string",
"is_subscribed": true,
"external_ids": [
"string"
],
"integration_ids": {
"intercom": "string",
"front": "string",
"zendesk": "string",
"hubspot": "string",
"plain": "string",
"productboard": "string",
"slack_channel": "string"
},
"created_at": "string",
"updated_at": "string"
},
"company": {
"id": "string",
"name": "string",
"logo_url": "string",
"domains": [
"string"
],
"size": 0,
"revenue": 0,
"status_id": "string",
"status_name": "string",
"tier_id": "string",
"tier_name": "string",
"owner": {
"id": "string",
"name": "string",
"avatar_url": "string"
},
"external_ids": [
"string"
],
"integration_ids": {
"intercom": "string",
"front": "string",
"zendesk": "string",
"hubspot": "string",
"plain": "string",
"productboard": "string",
"slack_channel": "string"
},
"created_at": "string",
"updated_at": "string"
},
"assignee": {
"id": "string",
"name": "string",
"email": "string",
"image_url": "string"
},
"reporter": {
"id": "string",
"name": "string",
"email": "string",
"image_url": "string"
},
"tags": [
{
"id": "string",
"name": "string",
"color": "string",
"icon": "string",
"tag_group_id": "string",
"created_at": "string",
"updated_at": "string"
}
],
"customer_needs": [
{
"id": "string",
"thread_id": "string",
"project_id": "string",
"issue_id": "string",
"priority": 0,
"created_at": "string",
"updated_at": "string"
}
],
"external_ids": [
"string"
],
"integration_ids": {
"intercom": "string",
"front": "string",
"zendesk": "string",
"hubspot": "string",
"plain": "string",
"productboard": "string",
"slack_channel": "string"
},
"ai_draft_html": "string",
"ai_draft_sources": [
null
],
"ai_draft_generated_at": "string",
"ai_draft_started_at": "string",
"ai_draft_error_at": "string"
}