curl --request GET \
--url https://api.flow.engineer/v1/senders/{sender_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/senders/{sender_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/senders/{sender_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/senders/{sender_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": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel": "telegram",
"kind": "shared",
"livemode": true,
"status": "pending",
"address": {
"phone": "<string>",
"username": "<string>",
"handle": "<string>",
"link": "<string>"
},
"limits": {
"new_contacts_per_day": 123,
"new_contacts_per_hour": 123,
"whatsapp_tier": "<string>"
},
"created_at": "2023-11-07T05:31:56Z",
"display_name": "<string>",
"throttled_until": "2023-11-07T05:31:56Z",
"quality_rating": "green",
"join_code": "join brave-otter-40718263"
}{
"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 sender
Returns one sender with its status, limits and, on WhatsApp, its quality rating.
curl --request GET \
--url https://api.flow.engineer/v1/senders/{sender_id} \
--header 'Authorization: Bearer <token>'const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.flow.engineer/v1/senders/{sender_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.flow.engineer/v1/senders/{sender_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/senders/{sender_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": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T",
"channel": "telegram",
"kind": "shared",
"livemode": true,
"status": "pending",
"address": {
"phone": "<string>",
"username": "<string>",
"handle": "<string>",
"link": "<string>"
},
"limits": {
"new_contacts_per_day": 123,
"new_contacts_per_hour": 123,
"whatsapp_tier": "<string>"
},
"created_at": "2023-11-07T05:31:56Z",
"display_name": "<string>",
"throttled_until": "2023-11-07T05:31:56Z",
"quality_rating": "green",
"join_code": "join brave-otter-40718263"
}{
"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 sender's ID.
A sender ID, snd_ and a ULID.
^snd_[0-9A-HJKMNP-TV-Z]{26}$"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
Response
The sender.
What your agent talks from: a Telegram bot, a WhatsApp number or an iMessage
line. shared senders are Flow's sandbox, used by many apps in test mode;
dedicated senders are yours alone. Each sender has its own limits and
warm-up state.
A sender ID, snd_ and a ULID.
^snd_[0-9A-HJKMNP-TV-Z]{26}$"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
A messaging channel.
telegram, whatsapp, imessage shared (the sandbox) or dedicated (yours).
shared, dedicated false for sandbox senders, true for dedicated senders used in live mode.
pending: requested, being provisioned.active: sending normally.warming_up: active, with a new-contact budget that grows day by day.throttled: the gate slowed it after an abuse signal; it recovers by itself.flagged: the channel or Flow flagged it; starts are paused. A Telegram bot is alsoflaggedwhen Telegram rejects its token (revoked in @BotFather): it then sends nothing, new sends answer403 permission, and queued messages wait until you connect the bot again with its new token (POST /v1/senders). They wait at most 72 hours after Flow accepted them; older ones fail withoutside_window(channel_codequeued_too_long) inmessage.failedinstead of going out late.banned: it cannot send or receive: the channel banned it, you disconnected it (DELETE /v1/senders/{sender_id}), or its bot or line was connected to another app.
pending, active, warming_up, throttled, flagged, banned How contacts reach the sender. Which fields are set depends on the channel.
Show child attributes
Show child attributes
The sender's current budget for starting conversations.
Show child attributes
Show child attributes
When the sender was created.
The name contacts see, where the channel shows one.
With status throttled, when starts are allowed again. Recovery is automatic.
WhatsApp only. Meta's quality rating for the number.
green, yellow, red, unknown Shared senders only. The whole message a contact sends to this sender to join your app: join, a space, then the app's sandbox_join_code (from GET /v1/app), for example join brave-otter-40718263. Show it to testers as is.
"join brave-otter-40718263"