Чат и рассылки
Читайте входящие DM «ожидающие первыми», назначайте цену фанату и проводите размеренные, безопасные для бана массовые рассылки.
TEASE даёт вам две поверхности для обмена сообщениями над одним подключённым аккаунтом: единые входящие DM,
которые поднимают наверх фанатов, ждущих ответа, и рассылки — размеренные,
безопасные для бана массовые кампании с предпросмотром аудитории и ROI по каждой кампании. Обе
читаются и управляются целиком через ваш ключ al_live_*.
Безопасность — это продукт, а не настройка
Каждое исходящее сообщение — ответ 1-на-1 или отправка кампании — проходит через контент- скрин и размеренный, gated-движок доставки, прежде чем что-либо вообще могло бы покинуть здание. Боевая доставка выключена по умолчанию: сегодня путь отправки скринит и логирует намерение, не контактируя с платформой. Endpoint-ы ниже стабильны; те два, что реально доставляют, помечены Beta / gated и описаны честно.
Как всё устроено
Входящие
Список тредов, живой просмотр треда и ценообразование по фанату — только для чтения, ожидающие первыми.
Отправить DM
Одно сообщение 1-на-1. Заскринено и gated; возвращает вердикт. Beta.
Рассылки
Сегментированные / по тирам / drip / online-trigger кампании с предпросмотром и ROI.
Запланировать и запустить
Развернуть кампанию в спланированный список отправок. Воркер gated.
Входящие
Входящие — это поверхность чтения. Она перечисляет диалоги, ожидающие-новейшими первыми, позволяет открыть отдельный тред вживую и возвращает предлагаемую цену для любого фаната, которому вы собираетесь выставить счёт.
Тела сообщений не хранятся
TEASE держит метаданные диалога — кто ждёт, как долго, число непрочитанных, последнюю активность — но никогда не хранит текст DM. Просмотр треда заново читает сообщения вживую из вашего подключённого аккаунта каждый раз, когда вы его открываете. Это чтение безопасно для бана по дизайну.
Список диалогов
GET /api/admin/inbox/conversations
Возвращает ваши треды, упорядоченные так, что фанаты, ждущие ответа, поднимаются наверх (самое долгое ожидание первым), затем всё остальное по самой недавней активности.
curl "https://app.tease.link/api/admin/inbox/conversations?status=open&limit=100" \
-H "Authorization: Bearer $TEASE_API_KEY"const res = await fetch(
'https://app.tease.link/api/admin/inbox/conversations?status=open&limit=100',
{ headers: { Authorization: `Bearer ${process.env.TEASE_API_KEY}` } },
);
const { conversations, count } = await res.json();import os, requests
res = requests.get(
"https://app.tease.link/api/admin/inbox/conversations",
headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
params={"status": "open", "limit": 100},
)
data = res.json()Query-параметры
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
status | string | нет | Фильтр по статусу треда (например, open). Опустите для всех. |
assigned_operator_id | int | нет | Только треды, назначенные этому участнику команды. |
limit | int | нет | Макс. число возвращаемых тредов. 1–1000, по умолчанию 200. |
Ответ
{
"conversations": [
{
"fan_id": "f_91kd2",
"of_account_id": "acct_main",
"platform": "of",
"last_msg_ts": 1751290800,
"last_inbound_ts": 1751290800,
"last_outbound_ts": 1751280000,
"unread_count": 2,
"assigned_operator_id": null,
"status": "open",
"waiting_seconds": 10800
}
],
"count": 1
}| Поле | Тип | Описание |
|---|---|---|
fan_id | string | Стабильный идентификатор фаната в этом треде. |
platform | string | Платформа-источник треда (например, of). |
last_msg_ts | int | Unix-секунды самого недавнего сообщения в любую сторону. |
last_inbound_ts | int | Unix-секунды последнего сообщения фаната вам. |
last_outbound_ts | int | Unix-секунды вашего последнего сообщения фанату. |
unread_count | int | Непрочитанные входящие сообщения в треде. |
assigned_operator_id | int | null | Участник команды, назначенный на тред, если есть. |
status | string | Статус треда (например, open). |
waiting_seconds | int | Секунды, которые фанат ждёт ответа; 0, когда не ждёт. |
SLA «ожидающие первыми»
Тред считается ожидающим, когда он открыт, имеет непрочитанные входящие, и последнее
сообщение фаната новее вашего последнего ответа. waiting_seconds — это как долго этот фанат
оставлен висеть — единственное число, по которому отсортированы ваши входящие. Разбирайте самых долго ждущих фанатов
первыми, и SLA позаботится о себе сам.
Прочитать тред
GET /api/admin/inbox/conversations/{fan_id}/messages
Открывает один тред и возвращает его сообщения, прочитанные вживую из вашего подключённого аккаунта и нормализованные к стабильной форме. Поскольку тела не хранятся, это всегда отражает истинное текущее состояние чата.
curl "https://app.tease.link/api/admin/inbox/conversations/f_91kd2/messages?limit=50" \
-H "Authorization: Bearer $TEASE_API_KEY"| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
limit | int | нет | Макс. число возвращаемых сообщений. 1–100, по умолчанию 50. |
Ответ
{
"fan_id": "f_91kd2",
"error": false,
"messages": [
{
"msg_id": "m_88210",
"ts": 1751290800,
"direction": "in",
"text": "hey is the new set out yet?",
"price_cents": 0,
"is_opened": true,
"can_purchase": false,
"media": []
}
]
}| Поле | Тип | Описание |
|---|---|---|
msg_id | string | Идентификатор сообщения. |
ts | int | Unix-секунды, когда сообщение было создано. |
direction | string | in (от фаната) или out (от вас). |
text | string | Тело сообщения, прочитанное вживую. Пусто для сообщений только с медиа. |
price_cents | int | Цена на платном (PPV) сообщении, в центах; 0, когда бесплатно. |
is_opened | bool | Разблокировано ли платное сообщение фанатом. |
can_purchase | bool | Доступно ли сообщение ещё для покупки. |
media | array | Прикреплённое медиа как { id, type }; пусто, когда только текст. |
Этот endpoint никогда не бросает исключение
Чтение из подключённого аккаунта может временно сбоить. Когда это происходит, ответ деградирует до
{ "messages": [], "error": true, "fan_id": "…" } с 200 — он никогда не возвращает
500 и никогда не откатывается к чату другого аккаунта. Считайте error: true как
«повторить вскоре», а не как «нет сообщений».
Назначить цену фанату
GET /api/admin/chatters/fan-pricing?fan_id={fan_id}
Возвращает предлагаемую цену PPV и тир трат для одного фаната, выведенные из собственной истории покупок этого фаната на вашем аккаунте. Входящие вызывают это, когда вы собираетесь отправить платное сообщение, чтобы цена подходила фанату перед вами.
curl "https://app.tease.link/api/admin/chatters/fan-pricing?fan_id=f_91kd2" \
-H "Authorization: Bearer $TEASE_API_KEY"Ответ
{
"fan_id": "f_91kd2",
"tier": "medium",
"suggested_cents": 2000,
"min_cents": 1400,
"max_cents": 3200
}| Поле | Тип | Описание |
|---|---|---|
tier | string | Тир трат фаната (new … whale). |
suggested_cents | int | Рекомендуемая цена PPV для этого фаната, в центах. |
min_cents | int | Предлагаемый нижний предел цены. |
max_cents | int | Предлагаемый верхний предел цены. |
Как формируется предложение
Предлагаемая цена основана на собственных тратах фаната, зажатых в допустимый диапазон.
Точный вывод намеренно не является частью публичного контракта — относитесь к возвращаемым
suggested_cents, min_cents и max_cents как к интерфейсу и позвольте им двигаться по мере
изменения истории фаната.
Очередь ожидающих фанатов
GET /api/admin/chatters/waiting
Командно-ориентированный срез того же SLA: открытые треды с непрочитанными сообщениями фанатов, самое долгое ожидание первым, с приоритетом для китов, чтобы высокоценный фанат не сидел в очереди.
curl "https://app.tease.link/api/admin/chatters/waiting?min_wait_min=5&limit=50" \
-H "Authorization: Bearer $TEASE_API_KEY"| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
min_wait_min | int | нет | Только фанаты, ждущие как минимум столько минут. По умолчанию 0. |
limit | int | нет | Макс. число возвращаемых фанатов. 1–500, по умолчанию 50. |
Ответ
{
"waiting": 1,
"longest_wait_min": 180,
"fans": [
{
"fan_id": "f_91kd2",
"of_account_id": "acct_main",
"unread_count": 2,
"last_inbound_ts": 1751290800,
"minutes_waiting": 180,
"assigned_operator_id": null,
"lifetime_net_cents": 6400,
"tier": "medium"
}
]
}| Поле | Тип | Описание |
|---|---|---|
waiting | int | Всего фанатов, ждущих сейчас. |
longest_wait_min | int | Самое долгое текущее ожидание, в минутах. |
fans | array | Ждущие фанаты, самое долгое ожидание первым, с приоритетом китов. |
Отправить DM (Beta)
POST /api/admin/inbox/send
Только контракт — боевая доставка gated
Этот endpoint — стабильный контракт, но боевая доставка выключена по умолчанию. Сегодня он
скринит ваше сообщение и логирует намерение, ничего не отправляя — эффективный режим
shadow. Стройте под формы запроса и ответа уже сейчас; когда доставка будет включена, тот же
вызов вернёт sent вместо shadow. В вашей интеграции ничего не меняется.
Каждый вызов скринится, затем маршрутизируется через gated-движок. Ответ говорит вам ровно,
что произошло, единым вердиктом status:
status | Значение |
|---|---|
blocked | Контент-скрин отказал сообщению. Ничего не было маршрутизировано и ничего не было залогировано. |
shadow | Сообщение прошло скрин, но боевая доставка gated. Намерение залогировано; ничего не отправлено. Это сегодняшний дефолт. |
sent | Сообщение доставлено вживую и подтверждено. Возможно только когда gate включён. |
curl -X POST https://app.tease.link/api/admin/inbox/send \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fan_id": "f_91kd2",
"text": "new set just dropped — want it?",
"media_ids": ["vault_55012"],
"price_cents": 2000
}'Параметры тела
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
fan_id | string | да | Фанат, которому пишем. 1–64 символа. |
text | string | нет | Тело сообщения. До 20 000 символов; пусто для только медиа. |
media_ids | string[] | нет | Медиа из хранилища для прикрепления. |
price_cents | int | нет | Цена сообщения как PPV, в центах. Опустите или 0 для бесплатного DM. |
operator_id | int | нет | Атрибутировать отправку участнику команды. |
Ответ
{
"status": "shadow",
"firewall": {
"state": "ok",
"reasons": [],
"policy_version": "v3"
},
"outcome": {
"mode": "shadow",
"ok": true,
"result": "shadow"
}
}| Поле | Тип | Описание |
|---|---|---|
status | string | Вердикт: blocked, shadow или sent. |
firewall.state | string | Прошёл ли контент-скрин (ok) или отказал сообщению. |
firewall.reasons | array | Почему скрин отказал, когда отказал. Пусто при прохождении. |
outcome | object | Результат движка для отправки (режим, подтверждение, статус). |
Что гарантирует контент-скрин
Скрин выполняется до того, как что-либо маршрутизируется. Отказ останавливает сообщение наглухо — ничего не
ставится в очередь, не логируется как отправленное и не атрибутируется. Конкретные категории, которые он
обеспечивает, являются частью слоя безопасности для бана и не публикуются; что гарантируется — это что вердикт blocked
означает, что сообщение никогда не проходит дальше скрина.
Рассылки
Рассылка — это кампания: выберите аудиторию, напишите сообщение, просмотрите охват, затем запланируйте её в размеренный план отправок. Вы строите и осматриваете кампании через API; воркер доставки, который опустошает план, gated (см. ниже).
Режимы кампании
Задайте mode, когда создаёте кампанию. Четыре режима определяют, как выбирается аудитория и
как секвенируются отправки.
| Режим | Что он делает | Типичное применение |
|---|---|---|
segmented | Одно сообщение одному сегменту аудитории, сопоставленному по атрибутам фаната. | Дроп, объявленный всем, кто подходит. |
tiered | Аудитория делится по тиру трат, чтобы каждый тир мог нести предложение, подходящее тиру. | Назначить тот же дроп дороже для китов. |
drip | Многошаговая последовательность с авто-стопом: как только фанат конвертируется на раннем шаге, его поздние шаги пропускаются. | 3-касательный нудж, который останавливается, как только сработал. |
online_trigger | Отправки выравниваются по моменту, когда фанаты активны, а не выстреливаются все разом. | Достичь каждого фаната в момент, когда он это увидит. |
Создать кампанию
POST /api/admin/broadcasts
curl -X POST https://app.tease.link/api/admin/broadcasts \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "June drop",
"mode": "drip",
"audience": { "tier": ["medium", "large", "whale"] },
"message": {
"steps": [
{ "text": "new set is live", "ppv_cents": 0 },
{ "text": "still time to grab it", "ppv_cents": 2500 }
]
},
"schedule": {}
}'const res = await fetch('https://app.tease.link/api/admin/broadcasts', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TEASE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'June drop',
mode: 'drip',
audience: { tier: ['medium', 'large', 'whale'] },
message: {
steps: [
{ text: 'new set is live', ppv_cents: 0 },
{ text: 'still time to grab it', ppv_cents: 2500 },
],
},
schedule: {},
}),
});
const { id } = await res.json();import os, requests
res = requests.post(
"https://app.tease.link/api/admin/broadcasts",
headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
json={
"title": "June drop",
"mode": "drip",
"audience": {"tier": ["medium", "large", "whale"]},
"message": {"steps": [
{"text": "new set is live", "ppv_cents": 0},
{"text": "still time to grab it", "ppv_cents": 2500},
]},
"schedule": {},
},
)
campaign_id = res.json()["id"]Параметры тела
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
title | string | да | Название кампании. 1–255 символов. |
mode | string | нет | segmented, tiered, drip или online_trigger. По умолчанию segmented. |
audience | object | нет | Спецификация аудитории (тир, сегмент и другие фильтры фанатов). |
message | object | нет | Тело сообщения, или steps для drip-последовательности. |
schedule | object | нет | Подсказки тайминга для планировщика. |
operator_id | int | нет | Атрибутировать кампанию участнику команды. |
of_account_id | string | нет | Нацелить на конкретный подключённый аккаунт. |
Ответ — это id новой кампании:
{ "id": 42 }Перечислите кампании с GET /api/admin/broadcasts, а прочитайте одну с
GET /api/admin/broadcasts/{campaign_id} (см. ROI & drip-воронка).
Отредактируйте черновик с PATCH /api/admin/broadcasts/{campaign_id}.
Просмотреть аудиторию
POST /api/admin/broadcasts/preview
Перед планированием просмотрите охват. Предпросмотр разрешает только счётчики и гистограмму тиров — он ничего не записывает и не возвращает никаких PII: ни id фанатов, ни имён, только сколько фанатов подходит.
curl -X POST https://app.tease.link/api/admin/broadcasts/preview \
-H "Authorization: Bearer $TEASE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "audience": { "tier": ["medium", "large", "whale"] } }'Ответ
{
"matched": 1840,
"selected": 1720,
"histogram": {
"medium": 1100,
"large": 480,
"whale": 140
}
}| Поле | Тип | Описание |
|---|---|---|
matched | int | Фанаты, подходящие под спецификацию аудитории. |
selected | int | Фанаты, которые фактически получили бы отправку после применения eligibility. |
histogram | object | Выбранные фанаты по корзинам тиров трат — форма охвата, без PII. |
Запланировать кампанию (Beta)
POST /api/admin/broadcasts/{campaign_id}/schedule
Планирование разворачивает кампанию в конкретный, спланированный список отправок 1-на-1 и переводит
кампанию в scheduled. Оно возвращает, сколько получателей и спланированных отправок было произведено.
План построен; воркер gated
Планирование реально — оно материализует спланированные отправки — но воркер, который доставляет их, выключен по умолчанию (Beta). Запланированная кампания сидит с готовым планом; ничего не уходит, пока gate доставки не включён. Вы можете строить, просматривать, планировать и осматривать кампании от начала до конца уже сегодня без того, чтобы что-либо отправлялось.
curl -X POST https://app.tease.link/api/admin/broadcasts/42/schedule \
-H "Authorization: Bearer $TEASE_API_KEY"Ответ
{
"campaign_id": 42,
"recipients": 1720,
"planned_sends": 3440,
"histogram": { "medium": 1100, "large": 480, "whale": 140 },
"start_ts": 1751299200
}| Поле | Тип | Описание |
|---|---|---|
campaign_id | int | Запланированная кампания. |
recipients | int | Уникальные фанаты в плане. |
planned_sends | int | Всего спланированных отправок (больше, чем получателей, для многошаговых drip). |
histogram | object | Гистограмма тиров получателей. |
start_ts | int | Unix-секунды, когда план начинается. |
Вызов schedule возвращает 409, если кампания не может быть запланирована из её текущего статуса, или
если у платного сообщения отсутствует его медиа.
Пауза, возобновление, отмена
После запланирования кампания управляема:
| Endpoint | Эффект |
|---|---|
POST /api/admin/broadcasts/{campaign_id}/pause | Остановить запланированную или работающую кампанию. Её план сохраняется. |
POST /api/admin/broadcasts/{campaign_id}/resume | Возобновить приостановленную кампанию обратно к работающей (или запланированной). |
POST /api/admin/broadcasts/{campaign_id}/cancel | Остановить кампанию и сбросить каждую ещё ожидающую отправку. |
curl -X POST https://app.tease.link/api/admin/broadcasts/42/pause \
-H "Authorization: Bearer $TEASE_API_KEY"Каждый возвращает { "ok": true }, или 404, если кампания не существует в вашем аккаунте.
ROI и drip-воронка
GET /api/admin/broadcasts/{campaign_id}
Чтение кампании возвращает полную запись плюс два свода: подсчёт send_status и
пошаговую воронку by_step — ровно то, что нужно, чтобы увидеть, как drip отваливается шаг за шагом.
{
"id": 42,
"title": "June drop",
"mode": "drip",
"status": "running",
"recipients": 1720,
"sent": 1610,
"failed": 12,
"skipped": 98,
"purchases": 143,
"revenue_cents": 357500,
"send_status": {
"sent": 1610,
"pending": 0,
"failed": 12,
"skipped": 98
},
"by_step": [
{ "step": 0, "total": 1720, "sent": 1700, "failed": 8, "skipped": 12 },
{ "step": 1, "total": 1720, "sent": 1100, "failed": 4, "skipped": 616 }
]
}| Поле | Тип | Описание |
|---|---|---|
status | string | draft, scheduled, running, paused, done или cancelled. |
recipients | int | Уникальные фанаты в кампании. |
sent | int | Подтверждённые отправки. |
failed | int | Отправки, которые сбойнули. |
skipped | int | Сброшенные отправки — например, шаг drip, пропущенный после того, как фанат уже конвертировался. |
purchases | int | Конверсии, атрибутированные кампании. |
revenue_cents | int | Выручка, атрибутированная кампании, в центах. |
send_status | object | Счётчики каждой отправки по статусу. |
by_step | array | Пошаговая воронка: step, total и счётчики по статусу для каждого шага. |
Чтение drip-воронки
В drip следите за ростом skipped на каждом более позднем шаге в by_step: это фанаты, которые
конвертировались раньше и были авто-остановлены до следующего нуджа. Здоровый drip приземляет большую часть
своей выручки рано и пропускает остальное — это работа авто-стопа, а не потерянный охват.
Что значит «безопасно для бана» здесь
Каждый исходящий путь в этом руководстве построен вокруг одной гарантии: вы не можете случайно
получить флаг на свой аккаунт через TEASE. Качественно это значит, что отправки скринятся на
контент перед движением, доставляются в человекоподобном темпе с естественными интервалами, придерживаются
во время тихих часов и маршрутизируются через gate, который выключен по умолчанию. Точные правила темпа,
тайминга и скрининга являются частью слоя безопасности и намеренно не публикуются —
контракт, под который вы строите, — это вердикт (blocked / shadow / sent) и
статус кампании, а не механизм за ними.
Дальнейшие шаги
- Смарт-ссылки — отслеживаемые ссылки воронки и поссылочная выручка.
- Атрибуция — выручка по источнику, стране и фанату.
- Аутентификация — выпустите scoped-ключ
al_live_*. - Справочник API — каждый endpoint входящих и рассылок.
Meta Pixel и Ad Platforms
Полный гайд по отслеживанию рекламы в TEASE — Meta Pixel, серверный CAPI, смарт-линки, Ad Platforms, воронка и логи. Вся аналитика у вас, экспорт в чужие трекеры не нужен.
Твой адрес для эфира
Один адрес для любого приложения — OBS, Moblin, Larix, Streamlabs. Мы принимаем поток, показываем превью и раздаём на площадки по кнопке.