curl --request GET \
--url https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript"
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))
}{
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"data": [
{
"id": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"direction": "in",
"status": "received",
"content": {
"kind": "basic",
"text": "<string>",
"media": {
"type": "image",
"url": "<string>",
"file_id": "file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5",
"filename": "<string>",
"mime_type": "<string>",
"size_bytes": 123
},
"reply_to": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"link_preview": true,
"telegram": {
"parse_mode": "HTML",
"disable_notification": true,
"protect_content": true,
"show_caption_above_media": true,
"has_spoiler": true
},
"imessage": {
"styles": [
{
"start": 1,
"length": 2,
"style": "bold"
}
],
"subject": "<string>"
},
"metadata": {}
},
"livemode": true,
"created_at": "2023-11-07T05:31:56Z",
"from": "ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0",
"network": "imessage",
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
},
"channel_message_id": "<string>",
"sms": {
"segments": 2,
"encoding": "gsm7"
},
"reply_to": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"metadata": {},
"updated_at": "2023-11-07T05:31:56Z"
}
],
"has_more": true
}{
"error": {
"type": "invalid_request",
"message": "limit must be between 1 and 100.",
"hint": "Pass limit between 1 and 100 (default 20), and page with after or before.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request",
"param": "limit"
}
}{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}Read a simulated conversation, both ways
Test keys only. Lists a simulated conversation’s messages, both directions,
oldest first, so a test can page forward with after (the last message
ID it has) to see what your agent sent back to the simulated contact. Each
entry is a Message; a sent message’s content is exactly what the
simulated contact’s phone shows, since Flow converts nothing.
A conversation that is not simulated answers 403 permission with
channel_code not_simulated; a live key answers 403 permission with
channel_code test_mode_only.
curl --request GET \
--url https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.flow.engineer/v0/test/conversations/{conversation_id}/transcript"
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))
}{
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"data": [
{
"id": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"direction": "in",
"status": "received",
"content": {
"kind": "basic",
"text": "<string>",
"media": {
"type": "image",
"url": "<string>",
"file_id": "file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5",
"filename": "<string>",
"mime_type": "<string>",
"size_bytes": 123
},
"reply_to": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"link_preview": true,
"telegram": {
"parse_mode": "HTML",
"disable_notification": true,
"protect_content": true,
"show_caption_above_media": true,
"has_spoiler": true
},
"imessage": {
"styles": [
{
"start": 1,
"length": 2,
"style": "bold"
}
],
"subject": "<string>"
},
"metadata": {}
},
"livemode": true,
"created_at": "2023-11-07T05:31:56Z",
"from": "ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0",
"network": "imessage",
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
},
"channel_message_id": "<string>",
"sms": {
"segments": 2,
"encoding": "gsm7"
},
"reply_to": "msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2",
"metadata": {},
"updated_at": "2023-11-07T05:31:56Z"
}
],
"has_more": true
}{
"error": {
"type": "invalid_request",
"message": "limit must be between 1 and 100.",
"hint": "Pass limit between 1 and 100 (default 20), and page with after or before.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request",
"param": "limit"
}
}{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"channel": "telegram",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}Authorizations
An API key of one app, sent as Authorization: Bearer <key>. Keys start with
fk_test_ (test mode: sandbox senders and test data only) or fk_live_
(live mode). Keep live keys on your server; never ship them in an app or page.
Headers
The API version to use, as a date. Without it, the version pinned to your app when it was created is used.
"2026-11-01"
Path Parameters
The conversation's ID.
A conversation ID, conv_ and a ULID.
^conv_[0-9A-HJKMNP-TV-Z]{26}$"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
Query Parameters
An item ID. Returns the items that come after it in the list's order.
64How many items to return, 1 to 100.
1 <= x <= 100Response
A page of the transcript, oldest first.
A page of a simulated conversation, both directions, oldest first.