curl --request GET \
--url https://api.flow.engineer/v1/conversations/{conversation_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/conversations/{conversation_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/conversations/{conversation_id}"
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/v1/conversations/{conversation_id}"
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))
}{
"id": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"app": "app_01JB8Z0A1C3E5G7J9K1M3P5R7T",
"channel": "telegram",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"contact": "ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0",
"livemode": true,
"opted_in": true,
"created_at": "2023-11-07T05:31:56Z",
"last_inbound_at": "2023-11-07T05:31:56Z",
"window_open_until": "2023-11-07T05:31:56Z",
"metadata": {}
}{
"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/v1/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"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 /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel_code": "<string>",
"request_id": "<string>"
}
}Get a conversation
Returns one conversation with its window state.
curl --request GET \
--url https://api.flow.engineer/v1/conversations/{conversation_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/conversations/{conversation_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/conversations/{conversation_id}"
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/v1/conversations/{conversation_id}"
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))
}{
"id": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"app": "app_01JB8Z0A1C3E5G7J9K1M3P5R7T",
"channel": "telegram",
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"contact": "ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0",
"livemode": true,
"opted_in": true,
"created_at": "2023-11-07T05:31:56Z",
"last_inbound_at": "2023-11-07T05:31:56Z",
"window_open_until": "2023-11-07T05:31:56Z",
"metadata": {}
}{
"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/v1/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}{
"error": {
"type": "invalid_request",
"message": "<string>",
"hint": "Send a template instead: POST /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"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 /v1/messages with content.type=template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"param": "<string>",
"retry_after": 1,
"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"
Response
The conversation.
One sender talking with one contact. Holds the window state and whether the contact opted in.
A conversation ID, conv_ and a ULID.
^conv_[0-9A-HJKMNP-TV-Z]{26}$"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
An app ID, app_ and a ULID.
^app_[0-9A-HJKMNP-TV-Z]{26}$"app_01JB8Z0A1C3E5G7J9K1M3P5R7T"
A messaging channel.
telegram, whatsapp, imessage A sender ID, snd_ and a ULID.
^snd_[0-9A-HJKMNP-TV-Z]{26}$"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
A contact ID, ct_ and a ULID.
^ct_[0-9A-HJKMNP-TV-Z]{26}$"ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0"
Whether the conversation belongs to live mode.
Whether the contact has agreed to receive messages (wrote first, joined the sandbox, or you recorded consent).
When the conversation began.
When the contact last wrote. Absent if they never have.
WhatsApp only. Until when free-form messages may be sent; after it, only templates. Absent when the window is closed or the channel has none.
Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.
Show child attributes
Show child attributes