Update Thread
curl --request PATCH \
--url https://app.puffle.ai/api/threads/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"unread_count": 4503599627370495,
"account_id": "<string>",
"participant_email": "<string>",
"participant_name": "<string>",
"draft_subject": "<string>",
"draft_body_text": "<string>",
"draft_body_html": "<string>",
"draft_cc": "<string>",
"draft_bcc": "<string>",
"draft_attachments": [
{
"name": "<string>",
"bucket": "<string>",
"path": "<string>",
"url": "<string>",
"mime_type": "<string>",
"size": 1,
"content_id": "<string>"
}
]
}
'import requests
url = "https://app.puffle.ai/api/threads/{id}"
payload = {
"unread_count": 4503599627370495,
"account_id": "<string>",
"participant_email": "<string>",
"participant_name": "<string>",
"draft_subject": "<string>",
"draft_body_text": "<string>",
"draft_body_html": "<string>",
"draft_cc": "<string>",
"draft_bcc": "<string>",
"draft_attachments": [
{
"name": "<string>",
"bucket": "<string>",
"path": "<string>",
"url": "<string>",
"mime_type": "<string>",
"size": 1,
"content_id": "<string>"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
unread_count: 4503599627370495,
account_id: '<string>',
participant_email: '<string>',
participant_name: '<string>',
draft_subject: '<string>',
draft_body_text: '<string>',
draft_body_html: '<string>',
draft_cc: '<string>',
draft_bcc: '<string>',
draft_attachments: [
{
name: '<string>',
bucket: '<string>',
path: '<string>',
url: '<string>',
mime_type: '<string>',
size: 1,
content_id: '<string>'
}
]
})
};
fetch('https://app.puffle.ai/api/threads/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.puffle.ai/api/threads/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'unread_count' => 4503599627370495,
'account_id' => '<string>',
'participant_email' => '<string>',
'participant_name' => '<string>',
'draft_subject' => '<string>',
'draft_body_text' => '<string>',
'draft_body_html' => '<string>',
'draft_cc' => '<string>',
'draft_bcc' => '<string>',
'draft_attachments' => [
[
'name' => '<string>',
'bucket' => '<string>',
'path' => '<string>',
'url' => '<string>',
'mime_type' => '<string>',
'size' => 1,
'content_id' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.puffle.ai/api/threads/{id}"
payload := strings.NewReader("{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.puffle.ai/api/threads/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.puffle.ai/api/threads/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyUnibox
Update Thread
Update thread lifecycle, unread count, sender, and one-off email draft fields.
PATCH
/
api
/
threads
/
{id}
Update Thread
curl --request PATCH \
--url https://app.puffle.ai/api/threads/{id} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"unread_count": 4503599627370495,
"account_id": "<string>",
"participant_email": "<string>",
"participant_name": "<string>",
"draft_subject": "<string>",
"draft_body_text": "<string>",
"draft_body_html": "<string>",
"draft_cc": "<string>",
"draft_bcc": "<string>",
"draft_attachments": [
{
"name": "<string>",
"bucket": "<string>",
"path": "<string>",
"url": "<string>",
"mime_type": "<string>",
"size": 1,
"content_id": "<string>"
}
]
}
'import requests
url = "https://app.puffle.ai/api/threads/{id}"
payload = {
"unread_count": 4503599627370495,
"account_id": "<string>",
"participant_email": "<string>",
"participant_name": "<string>",
"draft_subject": "<string>",
"draft_body_text": "<string>",
"draft_body_html": "<string>",
"draft_cc": "<string>",
"draft_bcc": "<string>",
"draft_attachments": [
{
"name": "<string>",
"bucket": "<string>",
"path": "<string>",
"url": "<string>",
"mime_type": "<string>",
"size": 1,
"content_id": "<string>"
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.patch(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PATCH',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
unread_count: 4503599627370495,
account_id: '<string>',
participant_email: '<string>',
participant_name: '<string>',
draft_subject: '<string>',
draft_body_text: '<string>',
draft_body_html: '<string>',
draft_cc: '<string>',
draft_bcc: '<string>',
draft_attachments: [
{
name: '<string>',
bucket: '<string>',
path: '<string>',
url: '<string>',
mime_type: '<string>',
size: 1,
content_id: '<string>'
}
]
})
};
fetch('https://app.puffle.ai/api/threads/{id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.puffle.ai/api/threads/{id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_POSTFIELDS => json_encode([
'unread_count' => 4503599627370495,
'account_id' => '<string>',
'participant_email' => '<string>',
'participant_name' => '<string>',
'draft_subject' => '<string>',
'draft_body_text' => '<string>',
'draft_body_html' => '<string>',
'draft_cc' => '<string>',
'draft_bcc' => '<string>',
'draft_attachments' => [
[
'name' => '<string>',
'bucket' => '<string>',
'path' => '<string>',
'url' => '<string>',
'mime_type' => '<string>',
'size' => 1,
'content_id' => '<string>'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.puffle.ai/api/threads/{id}"
payload := strings.NewReader("{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}")
req, _ := http.NewRequest("PATCH", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.patch("https://app.puffle.ai/api/threads/{id}")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.puffle.ai/api/threads/{id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Patch.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"unread_count\": 4503599627370495,\n \"account_id\": \"<string>\",\n \"participant_email\": \"<string>\",\n \"participant_name\": \"<string>\",\n \"draft_subject\": \"<string>\",\n \"draft_body_text\": \"<string>\",\n \"draft_body_html\": \"<string>\",\n \"draft_cc\": \"<string>\",\n \"draft_bcc\": \"<string>\",\n \"draft_attachments\": [\n {\n \"name\": \"<string>\",\n \"bucket\": \"<string>\",\n \"path\": \"<string>\",\n \"url\": \"<string>\",\n \"mime_type\": \"<string>\",\n \"size\": 1,\n \"content_id\": \"<string>\"\n }\n ]\n}"
response = http.request(request)
puts response.read_bodyCLI:
At least one valid field is required.
puffle thread update --id <id> --status <status> --unread-count <unread-count> --account-id <account-id> --participant-email <participant-email> --participant-name <participant-name> --draft-subject <draft-subject> --draft-body-text <draft-body-text> --draft-body-html <draft-body-html> --draft-cc <draft-cc> --draft-bcc <draft-bcc>
Overview
Updates a Unibox thread. Use it to archive or reactivate a thread, update unread count, choose a sender for an email draft, or edit one-off draft fields before sending.Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Thread ID. |
Request Body
| Field | Type | Description |
|---|---|---|
status | string | Set to active or archived. Other values are rejected with 400. |
unread_count | number | Sets the stored unread count. |
account_id | string or null | Email sender account ID, or null to clear it. Non-null values must refer to a ready email sender in the workspace. |
participant_email | string | Recipient email for a draft one-off email. Stored lowercase. |
participant_name | string | Recipient display name for a draft. |
draft_subject | string or null | Draft email subject. |
draft_body_text | string or null | Draft plain-text body. |
draft_body_html | string or null | Draft HTML body. |
draft_cc | string or null | Draft CC recipients. |
draft_bcc | string or null | Draft BCC recipients. |
draft_attachments | array or null | Dashboard-only attachment metadata. Bearer API-key callers must omit this field; ask the human to add or clear attachments in Unibox. |
Example
curl -X PATCH "https://app.puffle.ai/api/threads/3d986dd1-9d70-45b7-8e36-5d5b8b1c9337" \
-H "Authorization: Bearer $PUFFLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"account_id": "8a2f0c7a-9d1e-4d8f-9d7d-6a8b8e8f4a11",
"participant_email": "founder@example.com",
"draft_subject": "Quick question",
"draft_body_text": "Hi Alex, I had a quick question."
}'
{
"thread": {
"id": "3d986dd1-9d70-45b7-8e36-5d5b8b1c9337",
"status": "draft",
"account_id": "8a2f0c7a-9d1e-4d8f-9d7d-6a8b8e8f4a11",
"participant_email": "founder@example.com",
"draft_subject": "Quick question"
}
}
Duplicate Recipient Handling
When changingaccount_id on an email thread, the API checks whether that sender already has a non-archived, non-warmup thread with the same participant_email. If one exists, the response is 409 with existing_thread.
AI agent notes
Use this endpoint for draft edits and thread state changes. Do not use it to send a message; call Send message after the draft is ready. The public API cannot upload a new thread attachment. Do not invent storage metadata or call/api/threads/{id}/attachments; that multipart route is UI-only. If a new file must be attached, ask the human to add it in Unibox. Before sending, re-fetch the thread and confirm the recipient, sender, subject, body, and any existing attachment names with the human. Surface 400, 403, 404, and 409 responses without retrying the same update.Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Path Parameters
Thread (conversations.id) UUID.
Body
application/json
Available options:
active, archived Required range:
0 <= x <= 9007199254740991Email sender account ID, or null when no sender is selected yet.
Recipient email address.
Recipient display name.
Draft email subject.
Draft plain-text body.
Draft HTML body.
Draft CC recipients.
Draft BCC recipients.
Dashboard-only attachment metadata. Bearer API-key callers must omit this field and ask a human to manage attachments in Unibox.
Show child attributes
Show child attributes
Response
Successful response.
Was this page helpful?
⌘I