TEASEDocs
На русском

Чат и рассылки

Читайте входящие DM «ожидающие первыми», назначайте цену фанату и проводите размеренные, безопасные для бана массовые рассылки.

TEASE даёт вам две поверхности для обмена сообщениями над одним подключённым аккаунтом: единые входящие DM, которые поднимают наверх фанатов, ждущих ответа, и рассылки — размеренные, безопасные для бана массовые кампании с предпросмотром аудитории и ROI по каждой кампании. Обе читаются и управляются целиком через ваш ключ al_live_*.

Безопасность — это продукт, а не настройка

Каждое исходящее сообщение — ответ 1-на-1 или отправка кампании — проходит через контент- скрин и размеренный, gated-движок доставки, прежде чем что-либо вообще могло бы покинуть здание. Боевая доставка выключена по умолчанию: сегодня путь отправки скринит и логирует намерение, не контактируя с платформой. Endpoint-ы ниже стабильны; те два, что реально доставляют, помечены Beta / 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-параметры

ПолеТипОбязательноОписание
statusstringнетФильтр по статусу треда (например, open). Опустите для всех.
assigned_operator_idintнетТолько треды, назначенные этому участнику команды.
limitintнетМакс. число возвращаемых тредов. 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_idstringСтабильный идентификатор фаната в этом треде.
platformstringПлатформа-источник треда (например, of).
last_msg_tsintUnix-секунды самого недавнего сообщения в любую сторону.
last_inbound_tsintUnix-секунды последнего сообщения фаната вам.
last_outbound_tsintUnix-секунды вашего последнего сообщения фанату.
unread_countintНепрочитанные входящие сообщения в треде.
assigned_operator_idint | nullУчастник команды, назначенный на тред, если есть.
statusstringСтатус треда (например, open).
waiting_secondsintСекунды, которые фанат ждёт ответа; 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"
ПолеТипОбязательноОписание
limitintнетМакс. число возвращаемых сообщений. 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_idstringИдентификатор сообщения.
tsintUnix-секунды, когда сообщение было создано.
directionstringin (от фаната) или out (от вас).
textstringТело сообщения, прочитанное вживую. Пусто для сообщений только с медиа.
price_centsintЦена на платном (PPV) сообщении, в центах; 0, когда бесплатно.
is_openedboolРазблокировано ли платное сообщение фанатом.
can_purchaseboolДоступно ли сообщение ещё для покупки.
mediaarrayПрикреплённое медиа как { 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
}
ПолеТипОписание
tierstringТир трат фаната (newwhale).
suggested_centsintРекомендуемая цена PPV для этого фаната, в центах.
min_centsintПредлагаемый нижний предел цены.
max_centsintПредлагаемый верхний предел цены.

Как формируется предложение

Предлагаемая цена основана на собственных тратах фаната, зажатых в допустимый диапазон. Точный вывод намеренно не является частью публичного контракта — относитесь к возвращаемым 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_minintнетТолько фанаты, ждущие как минимум столько минут. По умолчанию 0.
limitintнетМакс. число возвращаемых фанатов. 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"
    }
  ]
}
ПолеТипОписание
waitingintВсего фанатов, ждущих сейчас.
longest_wait_minintСамое долгое текущее ожидание, в минутах.
fansarrayЖдущие фанаты, самое долгое ожидание первым, с приоритетом китов.

Отправить 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_idstringдаФанат, которому пишем. 1–64 символа.
textstringнетТело сообщения. До 20 000 символов; пусто для только медиа.
media_idsstring[]нетМедиа из хранилища для прикрепления.
price_centsintнетЦена сообщения как PPV, в центах. Опустите или 0 для бесплатного DM.
operator_idintнетАтрибутировать отправку участнику команды.

Ответ

{
  "status": "shadow",
  "firewall": {
    "state": "ok",
    "reasons": [],
    "policy_version": "v3"
  },
  "outcome": {
    "mode": "shadow",
    "ok": true,
    "result": "shadow"
  }
}
ПолеТипОписание
statusstringВердикт: blocked, shadow или sent.
firewall.statestringПрошёл ли контент-скрин (ok) или отказал сообщению.
firewall.reasonsarrayПочему скрин отказал, когда отказал. Пусто при прохождении.
outcomeobjectРезультат движка для отправки (режим, подтверждение, статус).

Что гарантирует контент-скрин

Скрин выполняется до того, как что-либо маршрутизируется. Отказ останавливает сообщение наглухо — ничего не ставится в очередь, не логируется как отправленное и не атрибутируется. Конкретные категории, которые он обеспечивает, являются частью слоя безопасности для бана и не публикуются; что гарантируется — это что вердикт 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"]

Параметры тела

ПолеТипОбязательноОписание
titlestringдаНазвание кампании. 1–255 символов.
modestringнетsegmented, tiered, drip или online_trigger. По умолчанию segmented.
audienceobjectнетСпецификация аудитории (тир, сегмент и другие фильтры фанатов).
messageobjectнетТело сообщения, или steps для drip-последовательности.
scheduleobjectнетПодсказки тайминга для планировщика.
operator_idintнетАтрибутировать кампанию участнику команды.
of_account_idstringнетНацелить на конкретный подключённый аккаунт.

Ответ — это 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
  }
}
ПолеТипОписание
matchedintФанаты, подходящие под спецификацию аудитории.
selectedintФанаты, которые фактически получили бы отправку после применения eligibility.
histogramobjectВыбранные фанаты по корзинам тиров трат — форма охвата, без 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_idintЗапланированная кампания.
recipientsintУникальные фанаты в плане.
planned_sendsintВсего спланированных отправок (больше, чем получателей, для многошаговых drip).
histogramobjectГистограмма тиров получателей.
start_tsintUnix-секунды, когда план начинается.

Вызов 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 }
  ]
}
ПолеТипОписание
statusstringdraft, scheduled, running, paused, done или cancelled.
recipientsintУникальные фанаты в кампании.
sentintПодтверждённые отправки.
failedintОтправки, которые сбойнули.
skippedintСброшенные отправки — например, шаг drip, пропущенный после того, как фанат уже конвертировался.
purchasesintКонверсии, атрибутированные кампании.
revenue_centsintВыручка, атрибутированная кампании, в центах.
send_statusobjectСчётчики каждой отправки по статусу.
by_steparrayПошаговая воронка: step, total и счётчики по статусу для каждого шага.

Чтение drip-воронки

В drip следите за ростом skipped на каждом более позднем шаге в by_step: это фанаты, которые конвертировались раньше и были авто-остановлены до следующего нуджа. Здоровый drip приземляет большую часть своей выручки рано и пропускает остальное — это работа авто-стопа, а не потерянный охват.


Что значит «безопасно для бана» здесь

Каждый исходящий путь в этом руководстве построен вокруг одной гарантии: вы не можете случайно получить флаг на свой аккаунт через TEASE. Качественно это значит, что отправки скринятся на контент перед движением, доставляются в человекоподобном темпе с естественными интервалами, придерживаются во время тихих часов и маршрутизируются через gate, который выключен по умолчанию. Точные правила темпа, тайминга и скрининга являются частью слоя безопасности и намеренно не публикуются — контракт, под который вы строите, — это вердикт (blocked / shadow / sent) и статус кампании, а не механизм за ними.

Дальнейшие шаги

On this page