Read a conversation's messages
curl --request GET \
--url https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id} \
--header 'Authorization: Bearer <token>' \
--header 'zivio-tenant-id: <api-key>'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}"
headers = {
"Authorization": "Bearer <token>",
"zivio-tenant-id": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {Authorization: 'Bearer <token>', 'zivio-tenant-id': '<api-key>'}
};
fetch('https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_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://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}",
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>",
"zivio-tenant-id: <api-key>"
],
]);
$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://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("zivio-tenant-id", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
request["zivio-tenant-id"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"project_id": 123,
"conversation": {
"conversation_id": 31,
"subject": "Re: Website Redesign (Acme Consulting)",
"kind": "proposal",
"supplier": {
"id": 45,
"name": "Acme Consulting"
},
"message_count": 2,
"unread_count": 0,
"last_message_at": "2026-07-02T09:30:00Z"
},
"messages": [
{
"message_id": 87,
"sender": {
"id": 1,
"name": "Jane Smith",
"side": "client"
},
"body": "Could you confirm who leads accessibility testing?",
"sent_at": "2026-07-01T12:00:00Z",
"attachments": []
},
{
"message_id": 88,
"sender": {
"id": 77,
"name": "Sam Supplier",
"side": "supplier"
},
"body": "Our accessibility lead is Priya Shah.",
"sent_at": "2026-07-02T09:30:00Z",
"attachments": []
}
]
}{
"error": "invalid_token",
"error_description": "The access token provided is expired, revoked, malformed, or invalid for other reasons"
}{
"error": "insufficient_scope",
"error_description": "The request requires higher privileges than provided by the access token",
"required_scope": "project_conversations:read",
"provided_scopes": [
"welcome:read"
]
}{
"message": "Not found"
}Projects
Read a conversation's messages
Returns the thread’s messages oldest-first — sender (client or supplier side), body, sent time, and any attachments with time-limited download URLs. Reading a thread marks it as read for the acting user, as opening it in the web UI does.
GET
/
projects
/
{id}
/
conversations
/
{conversation_id}
Read a conversation's messages
curl --request GET \
--url https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id} \
--header 'Authorization: Bearer <token>' \
--header 'zivio-tenant-id: <api-key>'import requests
url = "https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}"
headers = {
"Authorization": "Bearer <token>",
"zivio-tenant-id": "<api-key>"
}
response = requests.get(url, headers=headers)
print(response.text)const options = {
method: 'GET',
headers: {Authorization: 'Bearer <token>', 'zivio-tenant-id': '<api-key>'}
};
fetch('https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_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://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}",
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>",
"zivio-tenant-id: <api-key>"
],
]);
$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://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("zivio-tenant-id", "<api-key>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}")
.header("Authorization", "Bearer <token>")
.header("zivio-tenant-id", "<api-key>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.zivio.net/api/v4/projects/{id}/conversations/{conversation_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
request["zivio-tenant-id"] = '<api-key>'
response = http.request(request)
puts response.read_body{
"project_id": 123,
"conversation": {
"conversation_id": 31,
"subject": "Re: Website Redesign (Acme Consulting)",
"kind": "proposal",
"supplier": {
"id": 45,
"name": "Acme Consulting"
},
"message_count": 2,
"unread_count": 0,
"last_message_at": "2026-07-02T09:30:00Z"
},
"messages": [
{
"message_id": 87,
"sender": {
"id": 1,
"name": "Jane Smith",
"side": "client"
},
"body": "Could you confirm who leads accessibility testing?",
"sent_at": "2026-07-01T12:00:00Z",
"attachments": []
},
{
"message_id": 88,
"sender": {
"id": 77,
"name": "Sam Supplier",
"side": "supplier"
},
"body": "Our accessibility lead is Priya Shah.",
"sent_at": "2026-07-02T09:30:00Z",
"attachments": []
}
]
}{
"error": "invalid_token",
"error_description": "The access token provided is expired, revoked, malformed, or invalid for other reasons"
}{
"error": "insufficient_scope",
"error_description": "The request requires higher privileges than provided by the access token",
"required_scope": "project_conversations:read",
"provided_scopes": [
"welcome:read"
]
}{
"message": "Not found"
}Authorizations
OAuth 2.0 client credentials. The access token from POST /oauth/token is sent as a bearer token. Request only the scopes you need.
Your Zivio organisation identifier. The regional API endpoints serve every Zivio organisation, so each request must identify yours.
Path Parameters
Project ID
Conversation id from GET /projects/{id}/conversations.
Response
The conversation and its messages
The response is of type object.

