TEASEDocs
На русском

Лендинги

Создайте link-in-bio воронку для каждого домена — гео-сегменты, стопки кнопок, баннер-уведомление и фон — затем сделайте предпросмотр и опубликуйте.

Лендинг — это публичная воронка, которую TEASE отдаёт на одном из ваших доменов. Вы собираете её из упорядоченных гео-сегментов, стопки кнопок для каждого сегмента, необязательного баннера-уведомления и фона — всё это редактируется как черновик, просматривается вживую, а затем публикуется одним атомарным шагом.

Любое изменение, которое вы делаете через API, записывается только в состояние черновика. Боевая страница не меняется, пока вы не вызовете /publish. Это даёт безопасный цикл «редактирование — предпросмотр — выпуск» с единым глобальным откатом (/discard).

Концепции

КонцепцияЧто это
ДоменХост, на котором отдаётся ваша публичная страница (например, links.creator.com). Любой другой ресурс на этой странице привязан к домену.
Гео-сегментУпорядоченная корзина аудитории, сопоставляемая по стране (и, опционально, по устройству, ОС, времени или языку). У каждого сегмента своя стопка кнопок. Ровно один сегмент является дефолтным catch-all.
КнопкаПомеченная ссылка внутри сегмента, с видимым текстом, иконкой и URL назначения. Кнопки упорядочены внутри сегмента.
Всплывающая подсказкаНеобязательная карточка у конкретной кнопки (фото + короткий текст), которая выезжает под кнопкой после задержки.
Баннер-уведомлениеPush-подобный баннер (аватар, заголовок, текст, призыв к действию), который появляется на странице после небольшой задержки.
ФонПодложка страницы — мобильная картинка, десктопная картинка и сплошной цвет холста за карточкой на десктопе.
UI-стиль страницыВнешний вид кнопок на всём лендинге, вид карточки профиля плюс необязательный гейт 18+ — применяется, пока домен использует встроенный (платформенный) дизайн.
Черновик / ОпубликованноеДва снимка всей страницы. Вы всегда редактируете черновик; /publish копирует черновик → опубликованное; /discard копирует опубликованное → черновик (откат).

Аутентификация

Каждый endpoint на этой странице находится по адресу https://app.tease.link и требует Bearer-ключ со scope write (чтения принимают любой ключ). См. Аутентификацию. Несколько endpoint-ов только для владельца отмечены прямо в тексте.

Домены

Запись домена — это якорь для всего лендинга. Получите список доменов, которыми вы владеете, создавайте новые и копируйте готовую страницу на другой домен.

Список доменов

curl https://app.tease.link/api/admin/domains \
  -H "Authorization: Bearer $TEASE_API_KEY"
const res = await fetch('https://app.tease.link/api/admin/domains', {
  headers: { Authorization: `Bearer ${process.env.TEASE_API_KEY}` },
});
const { items } = await res.json();
import os, requests

res = requests.get(
    "https://app.tease.link/api/admin/domains",
    headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
)
items = res.json()["items"]
{
  "items": [
    {
      "hostname": "links.creator.com",
      "display_name": "Instagram bio",
      "created_at": 1751280000,
      "button_count": 4,
      "infra_state": "ssl_active",
      "provisioning_error": null,
      "infra_attempted_at": 1751280000
    }
  ]
}

Каждая запись несёт infra_state, который управляет статус-бейджем в дашборде:

infra_stateЗначение
unmanagedГолая запись домена без управляемого сертификата.
provisioningНастройка выполняется (выпуск TLS) сразу после создания.
pending_dnsОжидание, пока DNS укажет на TEASE — см. кастомные домены.
ssl_activeСертификат выпущен, и страница отдаётся по HTTPS.
failedПоследняя попытка настройки не удалась; provisioning_error содержит сообщение.

Создать домен

curl -X POST https://app.tease.link/api/admin/domains \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "hostname": "links.creator.com", "display_name": "Instagram bio" }'
const res = await fetch('https://app.tease.link/api/admin/domains', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TEASE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ hostname: 'links.creator.com', display_name: 'Instagram bio' }),
});
const domain = await res.json();
res = requests.post(
    "https://app.tease.link/api/admin/domains",
    headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
    json={"hostname": "links.creator.com", "display_name": "Instagram bio"},
)
domain = res.json()

Параметры

ПолеТипОбязательноОписание
hostnamestringдаВалидный хост (my-site.com), 1–253 символа, в нижнем регистре. Без схемы, без пути.
display_namestringнетДружелюбная метка «источника трафика», показываемая в отчётах (например, FB Agency). Пустое значение очищает её.

Новый домен создаётся с infra_state: "provisioning" и засеивается тремя дефолтными гео-сегментами плюс пустыми записями уведомления/фона, так что он сразу доступен для редактирования. Повторное создание хоста, которым вы уже владеете, в течение минуты возвращает существующую запись (идемпотентный повтор); иначе дубликат возвращает 409 domain_taken.

Лимиты тарифа

Каждый тариф ограничивает количество доменов, которыми вы можете владеть. Создание сверх лимита возвращает 409 domain_cap_reached.

Переименовать или удалить домен

PATCH обновляет display_name (это только отчётные метаданные, и они вступают в силу без публикации). DELETE удаляет домен и каскадно удаляет его кнопки, сегменты, баннер и фон.

# Rename
curl -X PATCH https://app.tease.link/api/admin/domains/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "display_name": "TikTok bio" }'

# Delete
curl -X DELETE https://app.tease.link/api/admin/domains/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY"
await fetch('https://app.tease.link/api/admin/domains/links.creator.com', {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${process.env.TEASE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ display_name: 'TikTok bio' }),
});
requests.patch(
    "https://app.tease.link/api/admin/domains/links.creator.com",
    headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
    json={"display_name": "TikTok bio"},
)

Скопировать страницу на другой домен

copy-from заменяет черновые кнопки и сегменты целевого домена копиями из домена-source — полный клон черновика, который вы затем публикуете. Страница пересобирается со свежими идентичностями кнопок, чтобы боевая страница обновилась чисто.

curl -X POST https://app.tease.link/api/admin/domains/new-site.com/copy-from \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "source": "links.creator.com" }'
ПолеТипОбязательноОписание
sourcestringдаХост, с которого копируется черновая страница. Должен отличаться от целевого.

Сопутствующие endpoint-ы копируют одну часть между доменами: copy-notification-from (баннер) и copy-bg-from (фон). POST /api/admin/bulk/copy-content копирует выбранные части (buttons_segments, bg, notification, canvas_color) из одного источника на множество целей за один вызов.

Кастомные домены

Чтобы отдавать страницу на собственном домене, подключите его и подтвердите DNS. Подключение — это маленький конечный автомат, построенный на infra_state: запрос на подключение открывает домен в pending_dns, а успешная проверка переводит его в активное состояние.

Начните подключение

POST /api/admin/domains/connect регистрирует хост и возвращает точную DNS-запись, которую нужно добавить. Поддомен (например, links.creator.com) получает инструкцию для CNAME; голый apex (например, creator.com) получает инструкцию для A-записи. Ответ также включает URL для вызова проверки.

curl -X POST https://app.tease.link/api/admin/domains/connect \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "hostname": "links.creator.com" }'
{
  "domain_id": 42,
  "hostname": "links.creator.com",
  "is_apex": false,
  "state": "pending_dns",
  "instructions": { "record_type": "CNAME", "name": "links", "value": "…" },
  "verify_url": "/api/admin/domains/42/verify"
}
ПолеТипОбязательноОписание
hostnamestringдаКастомный хост для подключения. Уже занятый хост возвращает 409 domain_taken.
providerstringнетПодсказка о DNS-провайдере, чтобы возвращаемые инструкции совпадали с интерфейсом вашего регистратора.

Добавьте DNS-запись

В вашем DNS-провайдере создайте запись точно так, как она возвращена в instructions. CNAME-записи могут распространяться несколько минут; apex A-записи могут занять больше времени.

Проверьте

Вызовите verify_url (или POST /api/admin/domains/{domain_id}/verify). Пока DNS ещё не подхватился, ответ остаётся в pending_dns и перечисляет, чего ещё не хватает, в issues:

{
  "domain_id": 42,
  "hostname": "links.creator.com",
  "state": "pending_dns",
  "issues": ["CNAME not found"]
}

Как только запись разрешается корректно, проверка переводит домен в активное состояние и возвращает боевой URL:

{
  "domain_id": 42,
  "hostname": "links.creator.com",
  "state": "active",
  "url": "https://links.creator.com"
}

Конечный автомат намеренно мал — из pending_dns есть только два исхода:

СостояниеКак вы туда попадаетеЧто это значит
pending_dnsПосле connect и после любого verify, пока DNS ещё не корректен.TEASE ждёт вашу DNS-запись.
activeПосле verify, где DNS-запись разрешается корректно.Страница отдаётся по HTTPS на вашем домене.

Перезапускайте verify сколько угодно — он идемпотентен и безопасен для опроса, пока распространяется DNS.

Сегменты

Гео-сегмент — это корзина аудитории. Посетители сопоставляются с первым сегментом, чьи условия подходят, проваливаясь к единственному дефолтному catch-all. У каждого сегмента своя упорядоченная стопка кнопок, так что вы можете показывать разную воронку, скажем, мобильному трафику из США, и всем остальным.

Сегмент сопоставляется в первую очередь по стране. Опционально вы можете сузить его условиями отображения по устройству, ОС или времени суток и пометить целевым языком для авто-перевода.

У сегментов своя вкладка «Сегменты» в хабе домена (/domains/<домен>/segments), рядом с «Кнопками». Там все сегменты — карточками в порядке приоритета (кто выше, тот матчится первым): их страны и условия, флаги «по умолчанию» / «блок», A/B-набор кнопок и стрелки приоритета. Сами кнопки сегмента по-прежнему настраиваются во вкладке «Кнопки».

Тиры стран

У аккаунта есть три переиспользуемых тира стран, общих для всех доменов:

  • Tier 1 — ваши топовые платящие рынки.
  • Tier 2 — средние рынки.
  • Блок-лист — страны, которым вы показываете 403 (они не попадают в воронку).

Они делают две вещи: пресеты T1 / T2 в редакторе сегмента добавляют страны из вашего Tier 1 / Tier 2 в собираемый сегмент, а трафик автоматически делится по тиру в A/B (Tier 1 сильнее склоняется к платному офферу, чем Tier 2).

Тиры остаются «за кулисами» — они питают пресет-чипы и A/B-деление, а не отдельный экран настроек. У каждого аккаунта разумные значения по умолчанию; чтобы их изменить, используйте API/MCP get_config / set_config (ключ geo_classify{ "tier1": [...], "tier2": [...], "blocklist": [...] } из ISO-3166 alpha-2 кодов). Ваши изменения касаются только вашего аккаунта.

Список сегментов

curl https://app.tease.link/api/admin/segments/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "domain": "links.creator.com",
  "items": [
    {
      "segment_id": "s_1a2b3c4d",
      "domain": "links.creator.com",
      "name": "US mobile",
      "countries": ["US"],
      "position": 0,
      "is_default": false,
      "match": [{ "type": "device", "op": "is", "values": ["mobile"] }],
      "ab": null,
      "lang": ""
    },
    {
      "segment_id": "s_default",
      "domain": "links.creator.com",
      "name": "Everyone",
      "countries": [],
      "position": 1,
      "is_default": true,
      "match": null,
      "ab": null,
      "lang": ""
    }
  ]
}
ПолеТипОписание
segment_idstringСтабильный id (s_<hex>). Используется как tier при управлении кнопками этого сегмента.
namestringМетка, которую вы выбираете.
countriesstring[]Коды ISO-3166 alpha-2, на которые нацелен этот сегмент. Пусто = без ограничения по стране.
positionintПорядок, в котором рассматриваются сегменты.
is_defaultboolЯвляется ли этот сегмент catch-all. Ровно один сегмент на домен является дефолтным.
matchobject[] | nullНеобязательные условия отображения (устройство / ОС / время). null = только страна.
abobject | nullНеобязательная A/B-конфигурация набора кнопок для сегмента.
langstringНеобязательный целевой язык (ISO-код) для авто-перевода, или "".

Создать сегмент

curl -X POST https://app.tease.link/api/admin/segments/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "US mobile",
    "countries": ["US"],
    "match": { "all": [{ "type": "device", "op": "is", "values": ["mobile"] }] }
  }'

Параметры

ПолеТипОбязательноОписание
namestringда1–64 символа.
countriesstring[]нетКоды ISO-3166 alpha-2 (US, GB). Дедуплицируются и приводятся к верхнему регистру. Пусто = без ограничения по стране.
is_defaultboolнетСделать этот сегмент catch-all. Первый сегмент на домене всегда становится дефолтным.
matchobjectнетУсловия отображения, { "all": [<clause>, …] }. Условия объединяются через AND. Опустите для сопоставления только по стране.
langstringнетКод целевого языка для авто-перевода (см. переводы).
Условия match

Условие match сужает сегмент за пределы страны. Каждое условие — одно из:

УсловиеФормаДопустимые значения
device{ "type": "device", "op": "is" | "is_not", "values": [...] }mobile, tablet, desktop
os{ "type": "os", "op": "is" | "is_not", "values": [...] }ios, android, windows, macos, other
time{ "type": "time", "tz": "<IANA tz>", "days": [0–6], "hours": [[start, end]] }days 0=Пн…6=Вс; hours — полуоткрытые диапазоны [start, end), где start меньше end, оба 0–24

Внутри условия values объединяются через OR; между условиями в all условия объединяются через AND.

Дефолтный сегмент — это catch-all

Каждый домен держит ровно один дефолтный сегмент. Повышение другого сегмента до дефолтного (is_default: true) автоматически снимает флаг с предыдущего; вы не можете снять единственный дефолтный напрямую.

Редактировать, переупорядочить, удалить

PATCH принимает любое подмножество полей создания. Опущенное поле остаётся неизменным; отправка явного пустого набора условий очищает его.

# Edit
curl -X PATCH https://app.tease.link/api/admin/segments/links.creator.com/s_1a2b3c4d \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "countries": ["US", "CA"] }'

# Reorder — the list must be a permutation of the domain's current segment ids
curl -X PUT https://app.tease.link/api/admin/segments/links.creator.com/order \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "order": ["s_1a2b3c4d", "s_default"] }'

# Delete — pass ?force=true to also remove the segment's buttons
curl -X DELETE "https://app.tease.link/api/admin/segments/links.creator.com/s_1a2b3c4d" \
  -H "Authorization: Bearer $TEASE_API_KEY"

Порядок важен: сегменты рассматриваются сверху вниз, поэтому размещайте наиболее специфичные сегменты выше catch-all. Переупорядочивание проверяет, что ваш массив order — это в точности текущий набор id сегментов (иначе order_mismatch). Удаление сегмента, у которого ещё есть кнопки, возвращает 409 segment_has_buttons, если только вы не передадите ?force=true; удаление дефолтного возвращает 400 segment_default_required, пока вы сначала не повысите другой сегмент.

Прямые редиректы

Иногда лендинг — лишний слой для аудитории: посетитель нужен сразу на назначении. Это закрывают два уровня прямых 307-редиректов, и оба оставляют каждый переход учтённым и атрибутированным, как обычный клик.

Сегменты-редиректы

Сегмент может быть помечен как сегмент-редирект: совпавший с ним посетитель не видит лендинг — его сразу 307-редиректит на назначение главной кнопки этого сегмента (самой нижней — той же, что лендинг красит основным CTA). Переход записывается как клик со своим источником, поэтому редиректнутые страны видны в отчётах трафика и питают TG-атрибуцию. Блок-сегмент всегда сильнее редиректа — заблокированная страна по-прежнему получает 403. Сам флаг включает платформа для гео-маршрутов в мессенджер; в редакторе сегментов такого переключателя пока нет.

Адрес живёт в КНОПКЕ (исправлено 2026-07-27)

До 27 июля 2026 адрес брался из серверной настройки TG_DIRECT_ACCOUNT_USERNAME — один Telegram-аккаунт на всю платформу, и только для доменов владельца платформы: у арендатора сегмент-редирект не работал вовсе, а кнопки сегмента не участвовали вообще (правка кнопки не меняла на сайте ничего). Теперь цель — та же главная кнопка, что и у доменного direct-redirect: свой адрес у каждого креатора, видимый и правимый из панели. Нет видимой кнопки с адресом → отдаётся лендинг (fail-safe).

В панели у такой аудитории метка «→ редирект», над списком кнопок — плашка с настоящим адресом, целевая кнопка подписана, остальные погашены.

Режим direct-redirect (на домен)

Целый домен может пропускать свой лендинг: при включённом режиме direct-redirect TEASE как обычно сопоставляет посетителя с гео-сегментом и затем 307-редиректит его прямо на назначение кнопки этого сегмента — для смартлинк-кнопки это /r/<slug> смарт-ссылка домена, так что лог кликов, привязка клик-id и атрибуция выручки продолжают работать насквозь. Режим создан для размещений, где промежуточная страница только теряет клики (например, adult-трафик из X/Twitter).

curl -X POST https://app.tease.link/api/admin/domains/links.creator.com/direct-redirect \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "enabled": true, "ab_pct": 0 }'
{ "domain": "links.creator.com", "direct_redirect": true, "ab_pct": 0 }
ПолеТипОбязательноОписание
enabledboolдаВключить или выключить режим. Выключение также сбрасывает сохранённый ab_pct в 0, чтобы повторное включение стартовало чисто (редирект всем).
ab_pctintнетДоля A/B, 0–100 — см. ниже. Опустите, чтобы оставить сохранённое значение; игнорируется, пока enabled равен false.

Все привычные предохранители остаются включёнными:

  • Цель редиректа берётся из опубликованной страницы, поэтому переключатель не требует перепубликации и вступает в силу примерно за минуту. В панели он живёт кнопкой «Прямой редирект» рядом с «Импорт», над списком кнопок.
  • Цель — главная кнопка аудитории, то есть самая нижняя (её же лендинг красит основной CTA). Настройка доменная: она действует во ВСЕХ аудиториях, и каждая уводит на свою главную кнопку.
  • Сегменты-редиректы и блок-сегменты по-прежнему сильнее: совпавший сегмент-редирект шлёт свой 307 (например, в Telegram), а страна из блок-листа по-прежнему получает 403.
  • Боты и сканеры назначение не видят — им не отдаётся ничего, ровно как в слое клоакинга.
  • In-app webview (встроенные браузеры Instagram / Facebook / TikTok) всё же получает лендинг: внутри «закрытого» webview назначение не откроется, поэтому там должен отработать клиентский «выход» со страницы.
  • Если у совпавшего сегмента нет назначения для редиректа — отдаётся лендинг (fail-safe, мёртвых редиректов не бывает).

Панель показывает судьбу каждой аудитории (с 2026-07-27)

Пока режим включён, список кнопок больше не выглядит как обычная страница: у аудитории стоит метка «→ редирект» (или «→ N%» при A/B), над списком — плашка «посетители НЕ видят страницу, они уходят на …» с настоящим адресом, целевая кнопка подписана «сюда уходит редирект», а остальные погашены с подписью «посетитель не увидит». До этого панель рисовала все кнопки одинаково, и было не видно, что достаётся посетителю ровно одна.

Сменить цель можно в том же диалоге: выбранная кнопка переносится в главные. Остальные кнопки при этом остаются на месте — при A/B их видит плечо со страницей.

Цель выбирается для ОТКРЫТОЙ аудитории (2026-07-28). Флаг доменный, поэтому в диалоге рядом перечислены все остальные аудитории домена и адрес, куда уйдёт их посетитель — чтобы выбор не выглядел общим на весь домен. Хотите поменять цель другой аудитории — откройте её на рельсе и выберите кнопку там.

A/B: лендинг vs сразу-на-оффер

Тестируется здесь ровно ОДНО: страница с кнопками против прямого перехода по адресу кнопки — не «смартлинк против чего-то». Адрес может быть любым: смарт-ссылка, Telegram, инстаграм, собственный сайт; движок читает его из кнопки.

ab_pct превращает вкл/выкл в живой эксперимент на включённом домене: N% посетителей получают прямой редирект (плечо B), остальные — обычную лендинг-воронку (плечо A). 0 = редирект всем (без A/B); 100 — то же самое, сказанное явно. Сплит липкий на посетителя и без кук, а входной клик несёт метку плеча, так что конверсии атрибутируются по плечу — вы измеряете, что конвертит лучше, вместо того чтобы коммититься на 100%. Строки доменов в GET /api/admin/domains отдают direct_redirect и direct_redirect_ab_pct.

Кнопки

Кнопки живут внутри сегмента. При управлении кнопками segment_id сегмента является path-параметром tier — так что buttons/{domain}/{segment_id} — это «кнопки, показываемые этой аудитории».

Список кнопок сегмента

curl https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "domain": "links.creator.com",
  "tier": "s_1a2b3c4d",
  "items": [
    {
      "button_id": "main",
      "domain": "links.creator.com",
      "tier": "s_1a2b3c4d",
      "position": 0,
      "label": "Subscribe",
      "text_value": "Subscribe",
      "url": "https://example.com/offer",
      "icon": "heart.svg",
      "hidden": false,
      "match": null,
      "variants": null,
      "popup": null
    }
  ]
}
ПолеТипОписание
button_idstringСтабильный id внутри сегмента. Генерируется сервером, если вы опускаете его при создании.
positionintПорядок внутри сегмента.
text_valuestringВидимый текст кнопки.
labelstringВнутренний алиас для логов/отчётов; по умолчанию равен text_value.
urlstringНазначение, на которое указывает кнопка.
iconstringИмя файла ассета иконки (name.svg) — см. Иконки.
hiddenboolСкрыта ли кнопка на боевой странице.
matchobject[] | nullНеобязательные условия отображения для конкретной кнопки (те же формы условий, что у сегментов).
variantsobject[] | nullНеобязательные A/B-варианты URL для кнопки.
popupobject | nullВсплывающая подсказка кнопки, или null, если выключена.

Создать кнопку

curl -X POST https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "text_value": "Subscribe",
    "url": "https://example.com/offer",
    "icon": "heart.svg"
  }'

Параметры

ПолеТипОбязательноОписание
text_valuestringдаВидимый текст кнопки, 1–64 символа.
urlstringдаНазначение, http(s)://, до 2048 символов.
iconstringдаИмя файла иконки, соответствующее [A-Za-z0-9_-].svg.
labelstringнетВнутренний алиас для отчётов. По умолчанию равен text_value.
button_idstringнетУкажите свой id, иначе он будет сгенерирован.
matchobjectнетУсловия отображения для конкретной кнопки, { "all": [<clause>, …] }.
variantsobjectнетНабор A/B URL, { "variants": [{ "id", "weight", "url" }, …] } (2 или больше вариантов).
popupobjectнетВсплывающая подсказка для кнопки.

Редактирование и упорядочивание повторяют сегменты:

# Edit any subset of fields
curl -X PATCH https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d/main \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "text_value": "Join now" }'

# Reorder within the segment
curl -X PUT https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d/order \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "order": ["main", "secondary"] }'

# Delete
curl -X DELETE https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d/main \
  -H "Authorization: Bearer $TEASE_API_KEY"

A/B вкратце

Передача двух или более variants превращает кнопку в A/B-тест по URL назначения, взвешенный по weight. TEASE берёт на себя отдачу и удержание конкретного посетителя на одном и том же варианте — вы лишь объявляете варианты и читаете результаты в своих отчётах.

Всплывающая подсказка

Любая кнопка может нести всплывающую подсказку — небольшую карточку с фото и текстом до 160 символов, которая выезжает под кнопкой после задержки. Клик по карточке нажимает саму кнопку. Подсказка показывается не более одного раза за просмотр страницы, а посетитель, закрывший её, не увидит её снова до конца сессии.

Настройка в два шага: загрузите фото (авто-обрезка в WebP-карточку 480×360), затем задайте объект popup на кнопке при создании или через PATCH.

# 1. Загрузить фото карточки (multipart, до 5 MB)
curl -X POST https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d/main/popup-photo \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -F "file=@teaser.jpg"
{ "filename": "popup_9f2c1a7b3d4e.webp", "url": "/notification/links.creator.com/popup_9f2c1a7b3d4e.webp" }
# 2. Привязать подсказку к кнопке
curl -X PATCH https://app.tease.link/api/admin/buttons/links.creator.com/s_1a2b3c4d/main \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "popup": {
      "enabled": true,
      "text": "Сегодняшний сет — скидка 50%, только 2 часа",
      "delay_ms": 4000,
      "photo": "popup_9f2c1a7b3d4e.webp"
    }
  }'

Поля подсказки

ПолеТипОбязательноОписание
enabledboolдаfalse (или пустой text) очищает подсказку.
textstringдаТекст карточки, до 160 символов.
delay_msintнетЗадержка перед выездом карточки, 500–30000 мс (по умолчанию 4000).
photostringнетИмя файла, возвращённое загрузкой popup-photo.

Объект popup заменяет сохранённую подсказку целиком. Повторная загрузка идентичных байтов фото идемпотентна (одинаковое содержимое → одинаковое имя файла), поэтому повторы безопасны.

Иконки

Каждая кнопка ссылается на иконку по имени файла. Библиотека иконок поставляется с ~290 встроенными иконками — бренд-марки плюс общие глифы, с поиском и категориями в пикере иконок панели — и держит рядом ваши собственные загрузки. Встроенные общие; всё, что вы загружаете или генерируете, приватно для вашего воркспейса.

# Список всего доступного (встроенные + ваши)
curl https://app.tease.link/api/admin/icons \
  -H "Authorization: Bearer $TEASE_API_KEY"

# Загрузить свой SVG (санитизируется, до 1 MB)
curl -X POST https://app.tease.link/api/admin/icons \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -F "file=@custom.svg"

Сгенерировать иконку через ИИ

Не нашли нужный глиф? POST /api/admin/icons/generate рисует новую иконку в фирменном стиле — белая на прозрачном фоне, так что она встаёт рядом со встроенными без швов — и сохраняет её прямо в вашу приватную библиотеку.

curl -X POST https://app.tease.link/api/admin/icons/generate \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "бумажный самолётик", "style": "line" }'
{ "filename": "gen_7c2f91d3a4b5.svg", "builtin": false, "uploaded_at": 1752537600 }
ПолеТипОбязательноОписание
promptstringдаКонцепт иконки на любом языке, до 200 символов.
stylestringнетline (контур штрихом, по умолчанию) или solid (залитый глиф).

Используйте возвращённое filename как icon кнопки. Генерация ограничена 6 в минуту (429 icon_gen_rate_limited); неудачная попытка возвращает 502 icon_ai_failed — просто повторите с переформулированным запросом.

Баннер-уведомление

Баннер — это push-подобная карточка для каждого домена (аватар, заголовок, текст и ссылка-призыв к действию), которая появляется на странице после небольшой задержки. На домен приходится один баннер — его можно редактировать руками, а можно вести из переиспользуемой библиотеки уведомлений (две и больше включённых карточек превращают его в креативный A/B-тест).

Прочитать и отредактировать

curl https://app.tease.link/api/admin/notification/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "domain": "links.creator.com",
  "enabled": true,
  "avatar_filename": "av_9f.png",
  "sound_filename": null,
  "title": "New drop",
  "body": "Tap to see today's set",
  "link_text": "Open",
  "target_url": "https://example.com/offer",
  "delay_ms": 2500,
  "translations": {},
  "style": null,
  "preset_id": null,
  "assignment": null
}

PATCH принимает любое подмножество редактируемых полей:

curl -X PATCH https://app.tease.link/api/admin/notification/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "title": "New drop",
    "body": "Tap to see today’s set",
    "link_text": "Open",
    "target_url": "https://example.com/offer",
    "delay_ms": 2500
  }'

Параметры

ПолеТипОбязательноОписание
enabledboolнетПоказывается ли баннер на боевой странице.
titlestringнетЗаголовок баннера, до 128 символов.
bodystringнетТекст баннера, до 256 символов.
link_textstringнетМетка призыва к действию, до 64 символов.
target_urlstringнетКуда ведёт призыв к действию (http(s)://). Для включения обязателен только в режиме «Своя ссылка»; в смартлинк-режиме — лишь последний фолбэк. Пустое значение очищает его.
link_modestringнетКуда ведёт клик: "" (по умолчанию) = «Смартлинк» — зеркало главной кнопки сегмента; "manual" = «Своя ссылка»target_url побеждает. См. ниже.
delay_msintнетЗадержка перед появлением баннера, 500–10000 мс.
translationsobjectнетПереопределения публичного текста по локалям — см. переводы.
assignmentobjectнетКакие пресеты библиотеки показывает этот баннер, { "items": [...] } — см. Библиотека уведомлений и A/B. { "items": [] } очищает назначение.
styleobjectнетПереопределения внешнего вида баннера — см. Внешний вид. {} сбрасывает к стоковому виду.

У призыва к действию баннера два режима, переключаемые link_mode:

  • «Смартлинк» ("", по умолчанию) — клик зеркалит главную кнопку сегмента, в который попал посетитель, следуя тому же tier-aware роутингу (и A/B-плечу), что и сами кнопки. URL для включения баннера в этом режиме не нужен; сохранённый target_url служит лишь последним фолбэком, когда у сегмента нет кнопки для зеркала.
  • «Своя ссылка» ("manual") — баннер ведёт ровно туда, куда вы указали: target_url обязателен (включение без него вернёт 400 notification_incomplete) и побеждает зеркало сегмента.

Внешний вид

Вид баннера настраивается независимо от его содержимого: объект style в том же PATCH несёт ручки внешнего вида. Хранятся только заданные вами ключи; отправьте {}, чтобы сбросить баннер к стоковому виду. Текущее значение возвращается в поле style при чтении.

curl -X PATCH https://app.tease.link/api/admin/notification/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "style": {
      "theme": "glass",
      "opacity": 0.9,
      "radius": 18,
      "avatar_shape": "circle",
      "position": "top",
      "accent": "#e0426e"
    }
  }'
КлючТипОписание
themestringlight, dark или glass.
opacityfloatПрозрачность карточки, 0.3–1.
radiusintРадиус скругления в px, 0–32.
avatar_shapestringcircle, rounded или square.
positionstringtop или bottom — край, из которого выезжает баннер.
accentstringАкцентный цвет призыва к действию, #rrggbb.
dimfloatЗатемнение-скрим под текстом баннера для читаемости, 0–0.8. Не задан = автоматический скрим 0.22 на стеклянных темах; явный 0 выключает его.
text_sizefloatМножитель размера текста баннера, 0.85–1.3.
fontstringШрифт баннера — тот же список шрифтов, что у font кнопок.

Аватар и звук

Изображение аватара и необязательный звук уведомления загружаются как файлы и могут быть удалены:

# Upload an avatar (multipart)
curl -X POST https://app.tease.link/api/admin/notification/links.creator.com/avatar \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -F "file=@avatar.png"

# Remove the sound
curl -X DELETE https://app.tease.link/api/admin/notification/links.creator.com/sound \
  -H "Authorization: Bearer $TEASE_API_KEY"

Библиотека уведомлений и A/B

Вместо ручной правки каждого домена держите креативы баннера как переиспользуемые пресеты в библиотеке уведомлений и назначайте их на домены. В панели вкладка «Уведомление» — это стена карточек-пресетов с галочками: отмеченная карточка — это то, что домен показывает, две и больше галочек запускают креативный A/B-тест, а вес карточки задаёт её долю показов. Конкретный посетитель держится одного варианта (ротация sticky по подсети), так что тест остаётся чистым.

Пресет несёт креатив целиком — тексты, ссылку-призыв, задержку, переводы, плюс собственные мастер-файлы (аватар/звук), которые хранятся в notification/_preset_<id>/ и раздаются как /notification/_preset_<id>/<filename>. Когда пресет ставится на домен, мастера копируются в папку домена — боевой баннер никогда не ссылается на файл, которого нет.

# Список библиотеки
curl https://app.tease.link/api/admin/library/notifications \
  -H "Authorization: Bearer $TEASE_API_KEY"

# Сохранить текущий баннер домена в библиотеку — вместе с файлами
curl -X POST https://app.tease.link/api/admin/library/notifications/from-domain \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domain": "links.creator.com", "name": "July drop" }'

from-domain снимает слепок черновика баннера домена в новый пресет вместе с файлами аватара/звука и штампует новый preset_id обратно на домен, так что карточка показывает свою привязку к библиотеке. Ошибки: 400 name_required / 400 notification_empty (нечего сохранять), 409 preset_name_taken, 404 domain_not_found.

Назначить пресеты на домен

Объект assignment в PATCH баннера — это API за галочками. Он заменяет сохранённое назначение целиком; { "items": [] } очищает его (назад к баннеру, отредактированному руками).

curl -X PATCH https://app.tease.link/api/admin/notification/links.creator.com \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "assignment": {
      "items": [
        { "preset_id": 7, "weight": 2, "enabled": true },
        { "preset_id": 9, "weight": 1, "enabled": true },
        { "preset_id": 4, "enabled": false }
      ]
    }
  }'
ПолеТипОбязательноОписание
preset_idintдаId пресета из GET /api/admin/library/notifications.
weightintнетОтносительная доля показов в A/B из 2+ пресетов (по умолчанию 1). Здесь пресет 7 достаётся ~2/3 посетителей.
enabledboolнетГалочка (по умолчанию true). Выключенный пункт остаётся в списке, но никогда не показывается.

Каждый включённый пресет валидируется при сохранении: неизвестный id возвращает 404 preset_not_found, а пресет без текстов, без аватара или (в режиме «Своя ссылка») без ссылки — 400 preset_incomplete, так что сломанное плечо никогда молча не съест долю трафика. Первый включённый пресет штампуется в баннер домена (тексты, файлы и preset_id), а мастер-файлы всех включённых пресетов копируются в папку домена — назначение из одного пресета начинает показывать свой креатив сразу.

Аватары пресетов

У каждого пресета свой мастер-аватар, управляемый на самом пресете (multipart-изображение до 5 MB, центр-кроп в квадрат 192 px, WebP с content-hash именем):

# Загрузить / заменить мастер-аватар
curl -X POST https://app.tease.link/api/admin/library/notifications/7/avatar \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -F "file=@avatar.jpg"

# Удалить (привязанные домены тоже теряют его, и их баннеры выключаются)
curl -X DELETE https://app.tease.link/api/admin/library/notifications/7/avatar \
  -H "Authorization: Bearer $TEASE_API_KEY"

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

Правка и применение пресетов

Правки через PATCH /api/admin/library/notifications/{preset_id} доезжают сразу: каждый домен, чьё назначение включает этот пресет, перештамповывается, а его черновик перепекается — фикс текста или аватара доходит до всех привязанных черновиков одним вызовом; в бой всё выходит по-прежнему явным /publish. POST /api/admin/library/notifications/{preset_id}/apply (тело { "domains": [...] }) штампует пресет на домены целиком: пишет назначение из одного пресета, материализует мастер-файлы в папку каждого домена и включает баннер только когда пресет полностью заполнен (все тексты, аватар и — в режиме «Своя ссылка» — ссылка).

Включение следует готовности пресета. При каждой перештамповке enabled привязанных доменов выводится из самого пресета: галочка в назначении — это намерение показывать, а баннер включается автоматически, как только пресет становится полным (все тексты, аватар и — в режиме «Своя ссылка» — ссылка) — например, когда в карточку наконец докинули аватар, — и честно выключается, когда пресет перестаёт быть полным.

Фон

У каждого домена есть фон, состоящий максимум из трёх частей: мобильное изображение, десктопное изображение и сплошной цвет холста, нарисованный за карточкой на десктопе. Изображения проходят через шаг загрузки и шаг редактирования; цвет холста — это один вызов.

Быстрый выбор: в карточке «ник модели» (вкладка «Кнопки») клик по аватару открывает библиотеку фонов — выберите один (→ один фон) или несколько (→ случайная ротация), не уходя из редактора кнопок. Загрузка и обрезка новых фонов остаётся во вкладке «Дизайн».

Загрузить и отредактировать изображение

bg/upload сохраняет оригинальное изображение для пары (domain, variant), где variant — это mobile или desktop. bg/edit применяет ваше состояние дизайна обрезки/трансформации и регенерирует отдаваемые варианты.

# 1. Upload the source image for the mobile background
curl -X POST "https://app.tease.link/api/admin/bg/upload?domain=links.creator.com&variant=mobile" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -F "file=@bg-mobile.jpg"

# 2. Commit the editor design state
curl -X POST "https://app.tease.link/api/admin/bg/edit?domain=links.creator.com&variant=mobile" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "designState": { } }'
const form = new FormData();
form.append('file', file); // a Blob/File of the image
await fetch(
  'https://app.tease.link/api/admin/bg/upload?domain=links.creator.com&variant=mobile',
  { method: 'POST', headers: { Authorization: `Bearer ${process.env.TEASE_API_KEY}` }, body: form },
);
Query / телоТипОбязательноОписание
domainqueryдаДомен, для которого задаётся фон.
variantqueryдаmobile или desktop.
filemultipartда (загрузка)Исходное изображение.
designStateтелода (редактирование)Объект состояния обрезки/трансформации редактора. Передайте {}, чтобы использовать изображение как есть.

Цвет холста

curl -X POST "https://app.tease.link/api/admin/bg/canvas-color?domain=links.creator.com" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "color": "#0d0604" }'
ПолеТипОбязательноОписание
colorstringдаHex-цвет в формате #rrggbb.

Внешний вид кнопок

Встроенные (платформенные) дизайны дают стиль кнопок на всём лендинге — форма, заливка, прозрачность, цвета, контраст подписи, типографика, цвета иконок, выравнивание и idle-анимация. Он проходит тот же цикл черновик → публикация, что и всё остальное, и задаётся через POST /api/admin/bg/ui, который несёт три независимые секции: buttons (эта), profile и gate. В панели они живут в хабе домена («Дизайн» / «Лендинг»), с живым предпросмотром каждой ручки.

Объект секции заменяет сохранённую секцию целиком (отправляйте полный нужный стиль); null сбрасывает её к стоковому виду. Хранятся только заданные вами ключи — всё опущенное сохраняет дефолт дизайна.

curl -X POST "https://app.tease.link/api/admin/bg/ui?domain=links.creator.com" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "buttons": {
      "shape": "pill",
      "fill": "solid",
      "opacity": 0.95,
      "color": "#e0426e",
      "text": "auto",
      "animation": "breathe",
      "anim_speed": "slow",
      "font": "unbounded",
      "align": "icon_left"
    }
  }'

# Назад к стоковому виду
curl -X POST "https://app.tease.link/api/admin/bg/ui?domain=links.creator.com" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "buttons": null }'
КлючТипОписание
shapestringrounded, pill, square или sharp.
fillstringglass, solid, outline, soft_shadow или hard_shadow.
opacityfloatПрозрачность фона кнопки, 0.05–1.
colorstringЦвет кнопки, #rrggbb. Пустая строка возвращает к дефолту.
shadow_colorstringЦвет тени для теневых заливок, #rrggbb.
textstringРежим подписи: auto (подбор под цвет кнопки), dark или light.
animationstringnone, pulse, breathe, float, shake, glow, shine, wobble или heartbeat.
anim_speedstringslow, normal или fast.
fontstringШрифт подписи: wix (по умолчанию), gilroy, tiktok, satoshi, nunito, onest, clashdisplay, bebas, unbounded, prata, pacifico или greatvibes — см. Шрифты.
text_sizefloatМножитель размера подписи, 0.7–1.5.
text_colorstringСвой цвет надписей, #rrggbb — точный hex побеждает режим text. Пусто = авто (светлый/тёмный подбирается по светлоте поверхности).
icon_colorstringЦвет глифа иконки, #rrggbb. Пустая строка возвращает стоковый белый глиф.
icon_bgstringЦвет кружка-подложки под иконкой, #rrggbb, или none — без кружка. Пустая строка возвращает стоковый чёрный кружок.
alignstringcenter (иконка + подпись по центру одной группой), icon_left (иконка прижата к левому краю, подпись по центру) или left (вся строка влево).
fillsarray of stringДо 6 стилей заливки (тот же список, что у fill); при 2+ значениях кнопка циклически перебирает их вместо одной плоской заливки. Меньше 2 значений — сворачивается обратно в обычный fill.
hoverstringЭффект при наведении курсора на десктопе: lift, none, ink, glow, shine, tilt, press или border.
new_tabboolОткрывать ссылку каждой кнопки в новой вкладке вместо перехода — некоторые рекламные сети это требуют.
reveal_delayfloatСекунды перед появлением всего ряда кнопок при загрузке, 0–10 (0 = мгновенно). Для точечных триггеров по скроллу/задержке/касанию/уходу на отдельные элементы см. Правила появления.
widthintФиксированная ширина кнопки в px, 160–360.
pad_yintВертикальный отступ в px, 6–28.

Полный рабочий пример — Style every button on the landing page; свободный холст, стопка тизеров, закреплённая панель, споттлайт и правила появления, которые живут рядом с этой секцией — на странице Landing-page builder.

Шрифты

Один и тот же брендовый пак из двенадцати начертаний питает каждую типографическую ручку страницы — подписи кнопок (buttons.font), карточку профиля (name_font / bio_font) и баннер-уведомление (style.font):

IdНачертаниеЗаметки
wixWix Madefor DisplayБрендовый дефолт — то, что вы получаете, когда шрифт не задан.
gilroyGilroyПремиум-гротеск «в стиле OnlyFans» (сам логотип OnlyFans — кастомный леттеринг; это ближайший по виду шрифт).
tiktokTikTok SansНастоящий фирменный шрифт TikTok (выпущен под OFL).
satoshiSatoshiСовременный гротеск. Только латиница.
nunitoNunitoОкруглый дружелюбный гротеск.
onestOnestЧистый геометрический гротеск.
clashdisplayClash DisplayФэшн-дисплейное начертание. Только латиница.
bebasBebas NeueВысокие узкие капсы. Только латиница.
unboundedUnboundedШирокий крипто-модерн дисплей.
prataPrataЭлегантная антиква.
pacificoPacificoЖирный кистевой скрипт.
greatvibesGreat VibesПарадный каллиграфический скрипт.

У латиница-only начертаний (satoshi, clashdisplay, bebas) нет кириллических глифов — кириллический текст в них автоматически падает в брендовый дефолт, так что русская подпись никогда не отрисуется «тофу». Id из снятого пака v1 продолжают читаться: они просто рендерятся дефолтом.

Смена font перерисовывает на сервере каждую подпись кнопок домена в новом начертании (подписи — заранее запечённые SVG); ответ возвращает их число в relabeled. Все шрифты самохостятся под свободными лицензиями и отдаются same-origin с вашего домена (/fonts/lf_<id>.woff2) — страница не делает ни одного стороннего запроса за шрифтами.

Только платформенные дизайны

Стиль применяется, пока домен использует встроенный дизайн. Загруженный кастомный HTML-дизайн владеет своим видом и никогда не наследует эти настройки — но ваша настройка сохраняется, так что возврат к платформенному дизайну её восстанавливает.

Бейдж бесплатного тарифа

Лендинги воркспейсов на бесплатном тарифе показывают маленький бейдж «tease.link» под кнопками (в том числе на кастомных дизайнах). Апгрейд убирает его автоматически — настраивать нечего.

Карточка профиля

Тот же endpoint bg/ui настраивает карточку профиля над кнопками — шрифт и размер ника, строку статуса «Active now • Responds in 5 mins» и необязательное био со своими шрифтом и размером — через вторую секцию, profile. Только платформенные дизайны, тот же цикл черновик → публикация, та же замена секции целиком: отправляйте полную нужную секцию, либо { "profile": null } для сброса к стоковой карточке.

curl -X POST "https://app.tease.link/api/admin/bg/ui?domain=links.creator.com" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "profile": {
      "name_font": "unbounded",
      "name_size": 1.2,
      "status_text": "Online now",
      "bio": "18+ • daily drops",
      "bio_font": "nunito",
      "bio_size": 0.9
    }
  }'
КлючТипОписание
name_fontstringШрифт ника — тот же список шрифтов, что у font кнопок.
name_sizefloatМножитель размера ника, 0.7–1.6.
statusboolПоказывать ли строку статуса. false скрывает её; опущено = показывается.
status_textstringСвой текст строки статуса, до 48 символов. Пусто возвращает стоковый.
biostringКороткое био под ником/статусом, до 160 символов. Пусто убирает его.
bio_fontstringШрифт био — тот же список шрифтов. Опущено = брендовый дефолт.
bio_sizefloatМножитель размера био, 0.7–1.6 (1 = сток).

Контентный гейт 18+

Тот же endpoint bg/ui несёт необязательный гейт 18+ для чувствительного контента — шаг подтверждения перед страницей: либо полноэкранная обложка (опционально с размытием страницы за ней), либо компактный лист сверху. Посетитель подтверждает один раз на браузер, и его больше не спрашивают. Только платформенные дизайны, тот же цикл черновик → публикация.

curl -X POST "https://app.tease.link/api/admin/bg/ui?domain=links.creator.com" \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "gate": {
      "enabled": true,
      "mode": "cover",
      "blur": true,
      "title": "Только для взрослых",
      "text": "Эта страница содержит контент для взрослых.",
      "ok": "Мне есть 18",
      "leave": "Уйти",
      "leave_url": "https://google.com"
    }
  }'
КлючТипОписание
enabledboolПоказывается ли гейт.
modestringcover — полноэкранное подтверждение; drop — лист сверху.
title / textstringСвой текст (64 / 300 символов). Опустите для стокового.
ok / leavestringПодписи кнопок (по 32 символа).
leave_urlstringКуда кнопка «уйти» отправляет отказавшихся. Пусто = нейтральный дефолт.
blurboolРазмыть страницу за гейтом в режиме cover.

Отправьте { "gate": null }, чтобы убрать гейт полностью.

Большинству креаторов это не нужно

Гейт — для людей, дополнительный слой консерватизма для строгих источников трафика. Боты, скраперы и in-app сканеры ссылок уже обработаны: клоакинг держит ваши контент-кнопки невидимыми для них, не беспокоя реальных фанатов.

Десктоп во весь экран, свободный холст, стопка, закреплённая панель и правила появления

bg/ui несёт ещё несколько секций помимо buttons/profile/gate — полные разборы живут в Landing-page builder (на английском, это интерфейсный раздел), здесь — сводка, чтобы вся поверхность bg/ui была в одном месте:

СекцияЧто делаетПолный гайд
desktopРаскладка на весь монитор на широких экранах вместо карточки-телефона. mode (phone/wide), align, width (280–560), dim (0–0.7), blur.Enable full-screen desktop mode
layoutmode: "free" переключает колонку кнопок на свободный холст; pos расставляет каждую кнопку/объект по id как {x, y, w, h}.Place elements freely on a canvas
objectsДополнительные элементы холста — items[] типов text/image/video/icon/shape/teaser/badge, до 40 штук.Place elements freely on a canvas
stackСвайпаемая/закреплённая стопка до 8 закрытых тизер-карточек.Build a teaser card stack/carousel
stickyПанель, остающаяся видимой при скролле, со своим стилем CTA-кнопки.Add a sticky call-to-action bar
appearПравила показа по элементам — реакция на скролл/задержку/касание/уход вместо мгновенного показа, плюс отложенное появление фона.Control when an element or background appears
exit / timerПопап при уходе посетителя и/или таймер срочности.Add an exit-intent popup and/or an urgency timer

Спотлайт — целый дизайн, а не секция bg/ui

POST /api/admin/bg/design {"design": "spotlight"} переключает страницу на второй встроенный дизайн (рядом с classic), который держит фото-героя зафиксированным за кнопками вместо скроллящейся колонки. Своя секция spotlight в bg/ui (blur 0–40, focus_x/focus_y 0–100, zoom 100–300) настраивает точку фокуса, зум и размытие снизу у этого фото. Свободный холст (layout.mode: "free" + objects) на дизайне Spotlight недоступен.

Языки и авто-перевод

Сегменты несут необязательную цель lang, а баннер-уведомление несёт карту translations, так что публичный текст может авто-переводиться по локалям. Объект translations индексируется по коду языка и хранит только публичные текстовые поля:

{
  "translations": {
    "es": { "title": "Nuevo drop", "body": "Toca para ver el set de hoy", "link_text": "Abrir" },
    "fr": { "title": "Nouveau drop", "link_text": "Ouvrir" }
  }
}

Поддерживаемые коды включают en, ru, pt, es, de, fr, it, nl, pl, tr, ar, hi, id, ja, ko, zh. Назначение призыва к действию никогда не является частью перевода — только видимые title, body и link_text.

QR-коды

Каждый домен может раздавать печатные QR-коды — флаер, наклейку, визитку, — которые ведут прямо на лендинг и считаются как любой другой источник трафика, живут вне цикла черновик/публикация. Создание, дизайн, скачивание, чтение воронки кода и переименование или отключение без потери уже напечатанного — см. QR codes (страница на английском, это техническая справка API).

Черновик → предпросмотр → публикация

Всё вышеперечисленное пишется в черновик. Ничто не идёт в бой, пока вы не опубликуете. Рекомендуемый цикл:

Осмотрите состояние черновика и опубликованного

GET /api/admin/config возвращает оба снимка плюс то, какие домены «грязные»:

curl https://app.tease.link/api/admin/config \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "is_dirty": true,
  "dirty_domains": ["links.creator.com"],
  "draft": { "updated_at": 1751280600, "domains": {}, "segments": {}, "notifications": {}, "backgrounds": {} },
  "published": { "updated_at": 1751280000, "domains": {}, "segments": {}, "notifications": {}, "backgrounds": {} }
}
ПолеТипОписание
is_dirtyboolОтличается ли черновик какого-либо домена от его опубликованной страницы.
dirty_domainsstring[]Хосты с неопубликованными изменениями.
draft / publishedobjectМатрицы кнопок, сегментов, уведомлений и фонов по доменам для каждого состояния.

Просмотрите боевую аудиторию

Запросите подписанный токен предпросмотра, затем откройте с ним страницу предпросмотра. Вы можете симулировать точную аудиторию — страну, устройство, ОС, час и язык — так что увидите, что увидел бы мобильный посетитель из США в 21:00, ничего не меняя в бою.

В панели предпросмотр лендинга управляется одним селектором «Аудитория»: выберите сегмент (каждый вариант показывает флаги стран и число кнопок), и предпросмотр отрисует эту аудиторию. Под капотом селектор закрепляет сегмент через force_segment, так что даже дефолтный catch-all без стран предпросматривается точно. Он двусторонне синхронизирован с рейкой сегментов, а точечные оверрайды страны / ОС / часа / языка живут под «ещё…».

curl "https://app.tease.link/api/admin/preview-token?domain=links.creator.com&force_country=US&force_device=mobile" \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "token": "…",
  "public_url": "https://links.creator.com",
  "frame_path": "/preview-frame/"
}
QueryТипОписание
domainstringДомен для предпросмотра.
force_countrystringСимулировать страну (ISO alpha-2, верхний регистр).
force_devicestringmobile или desktop.
force_osstringios, android, windows, macos или other.
force_hourintСимулировать час суток, 0–23.
force_langstringСимулировать 2-буквенный язык.
force_segmentstringОтрисовать ровно этот сегмент (по segment_id), минуя гео-классификатор. Неизвестные id игнорируются; блок-сегмент по-прежнему показывает свой 403.

Возвращаемый token короткоживущий и авторизует только предпросмотр вашего собственного черновика. Откройте public_url, соединённый с frame_path, передав токен, чтобы отрендерить симулируемую страницу.

Только для владельца

preview-token ограничен владельцем аккаунта.

Опубликуйте (или отмените)

Когда предпросмотр выглядит правильно, опубликуйте черновик на боевую страницу. Отмена выбрасывает черновик и восстанавливает его из опубликованной страницы — ваш единственный глобальный откат.

Публикация и отмена

POST /api/admin/publish атомарно копирует черновик на боевую страницу. Без тела он публикует каждый грязный домен; передайте массив domains, чтобы опубликовать только некоторые.

# Publish everything that changed
curl -X POST https://app.tease.link/api/admin/publish \
  -H "Authorization: Bearer $TEASE_API_KEY"

# Publish only one domain
curl -X POST https://app.tease.link/api/admin/publish \
  -H "Authorization: Bearer $TEASE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "domains": ["links.creator.com"] }'
await fetch('https://app.tease.link/api/admin/publish', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.TEASE_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ domains: ['links.creator.com'] }),
});
requests.post(
    "https://app.tease.link/api/admin/publish",
    headers={"Authorization": f"Bearer {os.environ['TEASE_API_KEY']}"},
    json={"domains": ["links.creator.com"]},
)
ПолеТипОбязательноОписание
domainsstring[]нетХосты для публикации. Опустите (или не отправляйте тело), чтобы опубликовать все грязные домены. Явный пустой список отклоняется.
{ "ok": true, "bg_files_by_domain": {}, "domains": ["links.creator.com"] }

Публикация без изменений возвращает 400 nothing_to_publish. POST /api/admin/discard принимает такой же необязательный выбор domains и восстанавливает черновик из опубликованного; если откатывать нечего, он возвращает { "ok": true, "noop": true }.

discard разрушителен для ваших правок в черновике — он заменяет черновик тем, что сейчас в бою. Ваша опубликованная страница не затрагивается.

Лента аудита

Каждое изменение выше журналируется. GET /api/admin/audit возвращает самые свежие записи (новые первыми), полезно для ленты активности или журнала изменений.

curl "https://app.tease.link/api/admin/audit?limit=50" \
  -H "Authorization: Bearer $TEASE_API_KEY"
{
  "items": [
    {
      "id": 9012,
      "ts": 1751280600,
      "actor": "owner",
      "action": "publish",
      "payload": "{\"tiers_updated\": true}"
    }
  ]
}
ПолеТипОписание
limitqueryКоличество возвращаемых записей, 1–500 (по умолчанию 100).
idintМонотонный id записи.
tsintUnix-метка времени.
actorstringКто внёс изменение.
actionstringТип изменения (например, segment_create, publish).
payloadstring | nullJSON-строка с деталями, специфичными для действия.

FAQ

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

On this page

КонцепцииДоменыСписок доменовСоздать доменПараметрыПереименовать или удалить доменСкопировать страницу на другой доменКастомные доменыНачните подключениеДобавьте DNS-записьПроверьтеСегментыТиры странСписок сегментовСоздать сегментПараметрыУсловия matchРедактировать, переупорядочить, удалитьПрямые редиректыСегменты-редиректыРежим direct-redirect (на домен)A/B: лендинг vs сразу-на-офферКнопкиСписок кнопок сегментаСоздать кнопкуПараметрыВсплывающая подсказкаПоля подсказкиИконкиСгенерировать иконку через ИИБаннер-уведомлениеПрочитать и отредактироватьПараметрыКуда ведёт кликВнешний видАватар и звукБиблиотека уведомлений и A/BНазначить пресеты на доменАватары пресетовПравка и применение пресетовФонЗагрузить и отредактировать изображениеЦвет холстаВнешний вид кнопокШрифтыКарточка профиляКонтентный гейт 18+Десктоп во весь экран, свободный холст, стопка, закреплённая панель и правила появленияЯзыки и авто-переводQR-кодыЧерновик → предпросмотр → публикацияОсмотрите состояние черновика и опубликованногоПросмотрите боевую аудиториюОпубликуйте (или отмените)Публикация и отменаЛента аудитаFAQДальнейшие шаги