Get Message History
curl --request GET \
--url https://app.tuco.ai/api/messages \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/messages"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/messages', 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.tuco.ai/api/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.tuco.ai/api/messages"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.tuco.ai/api/messages")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"messages": [
{
"_id": "<string>",
"message": "<string>",
"status": "<string>",
"channelType": "<string>",
"createdAt": "<string>",
"fromLine": {},
"recipient": {},
"attachmentDownloadUrls": [
{}
],
"attachmentNames": [
{}
]
}
],
"pagination": {
"page": 123,
"limit": 123,
"totalCount": 123,
"totalPages": 123
}
}Messages
Get Message History
Read the full conversation with a lead — inbound and outbound messages together, newest first, paginated.
GET
/
api
/
messages
Get Message History
curl --request GET \
--url https://app.tuco.ai/api/messages \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.tuco.ai/api/messages"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.tuco.ai/api/messages', 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.tuco.ai/api/messages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://app.tuco.ai/api/messages"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.tuco.ai/api/messages")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/messages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"messages": [
{
"_id": "<string>",
"message": "<string>",
"status": "<string>",
"channelType": "<string>",
"createdAt": "<string>",
"fromLine": {},
"recipient": {},
"attachmentDownloadUrls": [
{}
],
"attachmentNames": [
{}
]
}
],
"pagination": {
"page": 123,
"limit": 123,
"totalCount": 123,
"totalPages": 123
}
}Pair this with Get call recordings to
assemble a complete history for a lead: texts here, calls there.
Overview
Returns messages in your workspace, newest first. Filter byleadId to read the
whole conversation with one lead — inbound replies and outbound sends in the
same list.
Authentication
Pass your workspace API key as a Bearer token.Authorization: Bearer tuco_sk_xxxxxxxxxxxxx
Making a request
curl "https://app.tuco.ai/api/messages?leadId=6a4ed2d5dec1b2d01a6f7656&limit=50" \
-H "Authorization: Bearer tuco_your_key"
Query parameters
string
Only messages for this lead — this is how you read a single conversation.
24-character ObjectId hex.
string
Only messages sent from this Tuco line. 24-character ObjectId hex.
string
Match the
correlationId returned in a drip 202 ack.
Useful for confirming a queued drip became a real message.number
Page number, 1-based. Default
1.number
Messages per page. Default
50.Looking a conversation up by phone number
This endpoint has no phone-number filter.
leadId is the only way to scope to
one conversation.# 1. find the lead
curl "https://app.tuco.ai/api/leads?search=%2B13025550123" \
-H "Authorization: Bearer tuco_your_key"
# 2. read the conversation
curl "https://app.tuco.ai/api/messages?leadId=THE_LEAD_ID" \
-H "Authorization: Bearer tuco_your_key"
recipientPhone
directly and skips the lookup.
Response
{
"messages": [
{
"_id": "6a4ed2d5dec1b2d01a6f7656",
"message": "Sounds good — Tuesday works.",
"status": "delivered",
"channelType": "imessage",
"createdAt": "2026-09-17T15:28:41.632Z",
"fromLine": {
"_id": "6a4ed2d5dec1b2d01a6f7600",
"firstName": "Main",
"lastName": "Line",
"phone": "+13025550999",
"email": "line@example.com"
},
"recipient": {
"_id": "6a4ed2d5dec1b2d01a6f7601",
"firstName": "Dana",
"lastName": "Reed",
"phone": "+13025550123",
"email": "dana@example.com"
},
"attachmentDownloadUrls": ["https://app.tuco.ai/api/attachments/crm-media/photo.jpg?u=...&sig=..."],
"attachmentNames": ["photo.jpg"]
}
],
"pagination": {
"page": 1,
"limit": 50,
"totalCount": 128,
"totalPages": 3
}
}
array
Messages, newest first.
Show message fields
Show message fields
string
Message ID.
string
Message body. Empty for attachment-only sends.
string
Delivery status, e.g.
queued, scheduled, sent, delivered, failed, cancelled.string
How it was sent — e.g.
imessage, sms, email.string
When the message was created.
object
The Tuco line it was sent from (
_id, firstName, lastName, phone, email). null if the line has since been removed.object
The lead (
_id, firstName, lastName, phone, email). null if the lead has since been removed.array
Signed, fetchable URLs for the message’s attachments — present only when the message has attachments, max 5.
array
Filenames matching
attachmentDownloadUrls. Present only when the message has attachments.The full stored message document is returned, so you will see fields beyond those
listed above — e.g.
attachmentUrls, campaignId, correlationId. The fields listed
are the ones this endpoint guarantees or adds.object
A message’s raw
attachmentUrls point at private storage and return 403 to an API
key. Use attachmentDownloadUrls instead — those are signed and fetchable.You only ever see messages in your own workspace. The API key you authenticate with
determines the workspace; there is no parameter to query another one.
Errors
| HTTP | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 400 | No active workspace for this key |
| 500 | Unexpected server error |