exstru
Открыть в Telegram
← Обзор API

exstru API · v1

Документация API.

Всё, что нужно для интеграции: доступ и ключ, параметры заказа, статусы, архив, ошибки, лимиты и правила списания кредитов.

БАЗОВЫЙ АДРЕСhttps://exstru.com/api/v1
ФОРМАТJSON · UTF-8
АВТОРИЗАЦИЯBearer sg_…
РЕЗУЛЬТАТZIP-архив сайта

Быстрый старт

Три шага от ключа до готового архива. Сайт собирается в среднем около минуты, поэтому заказ возвращает номер задания, а не сайт: дальше вы опрашиваете статус и скачиваете ZIP.

01Получите ключКупите пакет «Команда», «Холдинг» или «Кракен» — API включится на 30 дней бесплатно. Ключ выпускается в боте, в разделе «API».
02Закажите сайтОтправьте нишу, язык и тариф. В ответе — номер задания и место в очереди.
03Заберите архивОпрашивайте статус раз в 3–5 секунд. Как только заказ готов, скачайте ZIP.
полный цикл
# 1. Заказать сайт
curl -X POST https://exstru.com/api/v1/generate \
  -H 'Authorization: Bearer sg_ваш_ключ' \
  -H 'Content-Type: application/json' \
  -d '{ "tier": "premium", "siteType": "local-business",
        "niche": "стоматология", "language": "es", "country": "ES" }'

# → { "jobId": "V1StGXR8Z5jd", "queue": { "position": 3, … } }

# 2. Проверять статус раз в 3–5 секунд
curl https://exstru.com/api/v1/status/V1StGXR8Z5jd \
  -H 'Authorization: Bearer sg_ваш_ключ'

# 3. Скачать архив, когда status = completed
curl -o site.zip https://exstru.com/api/v1/download/V1StGXR8Z5jd \
  -H 'Authorization: Bearer sg_ваш_ключ'

Доступ и ключ

API подключается к команде. Ключ вида sg_… выпускает владелец в разделе «API» в боте — там же его перевыпускают и отзывают. Кредиты за сайты списываются с общего баланса команды.

30 дней бесплатноПри первой покупке пакета «Команда», «Холдинг» или «Кракен». Один раз на команду. Напомним за 7 и 3 дня до окончания и в последний день.
$99 / 30 днейПосле пробного периода. Оплата со стабильного баланса в долларах, а не из кредитов.
АвтопродлениеВключается только вами. Если на продление не хватило денег, владелец получает уведомление, а API работает ещё 24 часа.
Без подпискиОтключается только API: командный кабинет, кредиты и генерация в боте продолжают работать. Ключ отвечает 403 subscription_inactive.

Как передать ключ

В любом из двух заголовков — они равноценны. Второй нужен, если ваша библиотека уже занимает Authorization.

заголовки
Authorization: Bearer sg_ваш_ключ
X-Api-Key: sg_ваш_ключ
Ключ — это доступ к кредитам команды.Храните его на сервере, а не в браузере или мобильном приложении: оттуда его легко извлечь. Если ключ утёк, отзовите или перевыпустите его в боте — старый перестанет работать сразу.

Тарифы в запросе

Тариф передаётся в поле tier и определяет, сколько кредитов спишется и что получит сайт. Подписка на API тариф не ограничивает: по одному ключу можно заказывать любой.

Параметрbasicpremiumelite
Списывается кредитов61025
Языков на сайте1до 3до 10
Свой цвет бренда—✓✓
Логотип—уникальныйуникальный
ИзображениястокAI под нишуAI под нишу
Формыконтактная+ обратный звонок+ квиз
Основных страниц~5–7~7–10~10–15+
Статей в блоге3–55–1010–15

Полное сравнение возможностей — на странице «Тарифы».

POST/api/v1/generate

Заказать сайт

Ставит сайт в очередь и списывает кредиты по тарифу. Ответ приходит сразу — с номером задания и местом в очереди.

Параметры тела запроса

ПолеОписание
tierобязательноstring · basic | premium | eliteТариф сайта: спишется 6, 10 или 25 кредитов.
siteTypeобязательноstring · local-business | blogСайт компании или блог. В блоге число статей зависит от тарифа: 3–5, 5–10 или 10–15.
nicheобязательноstring · 2–100 символовНиша своими словами, например «стоматология» или «ремонт стиральных машин». Генерируем только белые ниши: на остальные — отказ 422 niche_refused с вариантами рядом, кредиты не списываются.
languageобязательноstring · код ISO 639-1Основной язык сайта: двухбуквенный код одного из 14 поддерживаемых — en, de, ru, es, fr, it, pt, nl, pl, cs, ro, sv, da, no.
extraLanguagesнеобязательноstring[]Дополнительные языки, на сайте появится переключатель. Premium — до 2, Elite — до 9: вместе с основным до 3 и до 10. На Basic — только основной. Повторы, лимит и несовместимые языки — в правилах ниже.
countryобязательноstring · код ISO 3166-1Страна бизнеса: валюта цен, формат телефона и адреса, регион в разметке и обязательные юридические страницы, например импринт для DE, AT и CH. Обязательное поле. Список — в правилах ниже.
archiveFormatнеобязательноstring · html | phpФормат архива: html — статический сайт для любого хостинга, php — формы сами отправляют заявки на почту. Без поля — html. Подробнее — в правилах ниже.
baseUrlнеобязательноstring · доменДомен будущего сайта: с ним в архиве будут sitemap.xml, canonical и hreflang. Формат — в правилах ниже.
brandColorнеобязательноstring · #rrggbbЦвет бренда — на Premium и Elite, палитра строится вокруг него. Формат — в правилах ниже.
keywordsнеобязательноstring[] · до 8 фразКлючевые фразы, которые войдут в заголовки и тексты.
companyInfoнеобязательноobjectНазвание, контакты и факты о компании. Если не передать, генератор придумает их сам; чем больше данных, тем точнее тексты. Схема — в правилах ниже.

Правила полей

Ошибки формата возвращаются все сразу: 400 invalid_request, перечень — в data.issues. Кредиты при этом не списываются. Неизвестные поля игнорируются.

companyInfoobject

Если объект передан, name, email и phone обязательны. Без объекта название и контакты придумает генератор. Все поля — строки.

name2–200 · обязательноНазвание компании, как на вывеске.
emailemail · обязательноАдрес для страницы контактов и форм.
phone5–30 · обязательноТелефон в международном формате: +34 600 000 000.
addressдо 300Адрес офиса или точки.
descriptionдо 1000Чем занимается компания: 1–3 предложения.
legalInfoдо 500Юридическое название и реквизиты для юридических страниц.
foundedYearдо 20Год основания: «2014» или «с 2014».
teamSizeдо 20Размер команды: «12» или «10–15».
founderNameдо 120Имя основателя для страницы «О компании».
founderRoleдо 120Должность основателя.
serviceAreaдо 160География работы: «Мадрид и пригороды».
brandColorstring
  • Формат — #rrggbb или короткий #rgb, регистр не важен, пробелы по краям обрезаются. #1E6FD9 и #1e6fd9 — один цвет, #16d читается как #1166dd.
  • Пустая строка или отсутствие поля — палитра подбирается под нишу.
  • Другие записи — rgb(), названия цветов, код без # — ошибка 400 invalid_request.
  • Цвет не копируется один в один: у каждого сайта свой близкий оттенок, чтобы сайты одной команды не повторяли друг друга.
  • На Basic поле принимается, но не применяется — предупреждение brand_color_not_in_tier.
baseUrlstring · до 253 символов
  • Домен латиницей: буквы, цифры и дефис, хотя бы одна точка. Кириллические домены — в punycode: xn--…
  • Схема необязательна: http:// и https:// принимаются, в ссылках сайта всегда будет https.
  • www сохраняется — какой хост канонический, решаете вы. Путь допускается для сайта в подпапке.
  • Завершающий слэш, параметры ?… и якорь #… отбрасываются.
  • Нельзя: пробелы, порт, IP-адрес, логин в адресе (user@) — ошибка 400 invalid_request.
  • Без домена сайт собирается без sitemap.xml, canonical, og:url и hreflang: им нужен полный адрес.
ПередалиПолучится
Example.COM/https://example.com
http://www.example.comhttps://www.example.com
https://example.com/clinic/?utm=1https://example.com/clinic
xn--80aswg.xn--p1aihttps://xn--80aswg.xn--p1ai
example.com:8080400 invalid_request
мой сайт.рф400 invalid_request
extraLanguagesstring[]
  • Коды — как в language: двухбуквенные ISO 639-1 в нижнем регистре из списка поддерживаемых. Региональные варианты (en-GB, pt-BR) не принимаются.
  • Основной язык лежит в корне сайта и отмечен как x-default. Дополнительные — в подпапках /en/, /de/ в порядке массива.
  • Повторы и основной язык внутри extraLanguages пропускаются и в лимит не считаются.
  • Лимит тарифа — Premium 2, Elite 9 дополнительных, Basic 0. Лишние языки отбрасываются с конца массива, цена заказа не меняется — предупреждение language_limit.
  • Неподдерживаемый код в language или extraLanguages — ошибка 400 invalid_request.
  • Если нишу нельзя делать на одном из языков (например, VPN на русском) — 422 niche_language_refused, заказ не создаётся. Уберите этот язык и повторите.
пример · premium
"tier": "premium",
"language": "es",
"extraLanguages": ["es", "en", "en", "de", "fr"]

→ языки сайта: es (корень), /en/, /de/
→ "warnings": [{
    "code": "language_limit",
    "field": "extraLanguages",
    "message": "Premium: до 3 языков, fr не добавлен"
  }]
countrystring · 2 буквы
  • Код ISO 3166-1, регистр не важен: mx и MX — одна страна.
  • Поддерживаются: US GB CA AU IE NZ DE AT CH ES MX CO CL FR BE RU KZ IT PT BR NL PL CZ RO SE DK NO.
  • Язык сайта страна не меняет — его задаёт language. Английский сайт для немецкой компании — "language": "en", "country": "DE": цены в евро, телефон +49, импринт на английском.
  • Без поля или с кодом не из списка — ошибка 400 invalid_request с полем country, кредиты не списываются.
пример
"language": "es",
"country": "MX"

→ цены в песо
→ телефон +52 55 1234 5678
→ <html lang="es-MX">
archiveFormatstring · html | php
  • html (по умолчанию) — статический сайт: любой хостинг, Netlify, GitHub Pages.
  • php — страницы те же, рядом обработчик заявок: формы отправляют их на companyInfo.email. Нужен хостинг с PHP 7.0 или новее, где работает отправка почты (mail()).
  • Без companyInfo.email сайт получает демо-контакты, и почты для заявок нет: формы не принимают их, пока вы не впишете адрес в начало PHP-файла.
  • Цена от формата не зависит. Другое значение — ошибка 400 invalid_request.

Пример

запрос
POST /api/v1/generate
Authorization: Bearer sg_ваш_ключ
Content-Type: application/json

{
  "tier": "premium",
  "siteType": "local-business",
  "niche": "стоматология",
  "language": "es",
  "country": "ES",
  "extraLanguages": ["en", "de"],
  "baseUrl": "sonrisa-clinica.es",
  "brandColor": "#1e6fd9",
  "keywords": ["implantes", "ortodoncia"],
  "companyInfo": {
    "name": "Sonrisa",
    "email": "hola@sonrisa.es",
    "phone": "+34 600 000 000"
  }
}
ответ · 200
{
  "success": true,
  "jobId": "V1StGXR8Z5jd",
  "queue": {
    "position": 3,
    "etaSeconds": 90
  },
  "warnings": []
}

Поля ответа

jobIdНомер задания: нужен для статуса, отмены и скачивания.
queueМесто в очереди (position, 1 — следующий) и примерное ожидание до старта в секундах (etaSeconds). null — если сборка началась сразу.
warningsЧто из запроса не применилось — заказ при этом выполняется. Массив объектов { code, field, message }: language_limit — языки сверх тарифа, brand_color_not_in_tier — цвет бренда на Basic.
GET/api/v1/status/{jobId}

Узнать статус

Показывает, на каком этапе заказ. Опрашивайте раз в 3–5 секунд, пока статус не станет конечным: completed, failed или cancelled.

statusОдин из пяти статусов — см. ниже.
queuePositionМесто в очереди, пока заказ ждёт. Иначе null.
etaSecondsПримерное ожидание до старта, пока заказ ждёт.
progressГотовность от 0 до 100.
stepТекущий этап сборки текстом.
errorПричина, если сборка не удалась.
readytrue — архив можно скачивать.
ответ · 200
{
  "jobId": "V1StGXR8Z5jd",
  "status": "processing",
  "queuePosition": null,
  "etaSeconds": null,
  "progress": 55,
  "step": "Тексты готовы, подбираем фото…",
  "error": null,
  "ready": false
}

Статусы

pendingЖдёт в очереди. Можно отменить.
processingСобирается.
completedГотов — скачивайте архив.
failedСборка не удалась. Кредиты вернулись автоматически.
cancelledОтменён в очереди. Кредиты вернулись.
POST/api/v1/cancel/{jobId}

Отменить заказ

Работает, пока заказ ждёт в очереди (pending). Кредиты сразу возвращаются на баланс. Если сборка уже началась, отменить её нельзя — ответ 409 not_waiting.

ответ · 200
{ "jobId": "V1StGXR8Z5jd", "status": "cancelled", "refunded": true }
GET/api/v1/download/{jobId}

Скачать архив

Отдаёт application/zip потоком, когда статус — completed. Архив хранится 14 дней, скачивать его можно сколько угодно раз. Позже ответ — 410 gone.

HTML · CSS · изображенияГотовый статический сайт для любого хостинга — без CMS и сборки.
robots.txt · страница 404Технический минимум — на всех тарифах.
sitemap.xml · canonicalЕсли в заказе указан домен в baseUrl.
Юридические страницыНа языках сайта — на всех тарифах.

Ошибки

Машинный код ошибки — в data.code. Опирайтесь на него: текст сообщения может меняться.

пример · 422
{
  "statusCode": 422,
  "message": "Эту нишу мы не генерируем: …",
  "data": {
    "code": "niche_refused",
    "category": "gambling",
    "reason": "азартные игры",
    "alternatives": [
      { "label": "клуб настольных игр", "canonical": null }
    ]
  }
}
HTTPdata.codeЧто значит и что делать
400invalid_requestЗапрос не прошёл проверку. Все проблемы сразу — в data.issues.
401no_keyКлюч не передан. Добавьте заголовок Authorization или X-Api-Key.
401unknown_keyКлюч неверный. Сверьте его с ключом в боте.
402insufficient_creditsНе хватает кредитов на балансе команды. Пополните баланс или включите автопополнение.
403key_blockedКлюч отозван. Выпустите новый в боте.
403subscription_inactiveПодписка на API неактивна. Владелец продлевает её в боте — $99 за 30 дней.
404not_foundЗадания нет или оно принадлежит другой команде.
409not_waitingОтменить можно только заказ в очереди — этот уже собирается или готов.
409not_readyЗаказ ещё не готов. Дождитесь статуса completed.
410goneАрхив больше не хранится: прошло 14 дней.
422niche_refusedЭту нишу не генерируем. Причина — в data.category и data.reason, до 3 белых ниш рядом — в data.alternatives. Кредиты не списываются.
422niche_language_refusedНишу делаем, но не на этом языке. Уберите язык из language или extraLanguages. Кредиты не списываются.
429queue_full_for_accountВ очереди уже 30 заказов команды. Новый примем, когда часть соберётся. Кредиты не списываются.
429rate_limitedСлишком частые запросы. Подождите столько секунд, сколько указано в Retry-After.
503niche_unverifiedНе удалось проверить нишу. Повторите запрос — кредиты не списываются.

Чужое задание отвечает тем же 404, что и несуществующее, — так номера заданий нельзя проверить перебором.

Лимиты и очередь

5 в минутузаказов на один ключ.
240 в минутуостальных запросов: статус, отмена, скачивание.
30 в очередизаказов одной команды одновременно. Новые примем, когда часть соберётся.
Честная очередьЗаказы одной команды не задерживают остальных: в ответе всегда видно место и ожидание.

При 429 приходит заголовок Retry-After с числом секунд. Дождитесь его: повтор раньше срока не обходит лимит, а продлевает его. Лимиты считаются по ключу, а не по IP-адресу.

Списания и возвраты

Когда списываютсяПри постановке в очередь, до начала сборки: 6, 10 или 25 кредитов по тарифу. За сами вызовы API платить не нужно.
СбойЕсли сборка не удалась, кредиты возвращаются автоматически.
ОтменаПока заказ в очереди, его можно отменить — кредиты вернутся сразу.
Без списанияОтказ по нише, ошибка в запросе или полная очередь — кредиты не списываются.
Без двойных списанийСписание и возврат привязаны к номеру задания: один заказ не спишется и не вернётся дважды.
Бонусные кредитыЕсли на балансе есть бонусные кредиты, они расходуются первыми.
Купленные кредитыОстаются на балансе без ограничения по времени.
АвтопополнениеДля команд: когда кредитов меньше заданного порога, выбранный пакет покупается со стабильного баланса автоматически, и интеграция не останавливается. Выключено по умолчанию.
Нужна помощь с интеграцией?Напишите в поддержку [@username] — ответим по коду и сценарию.Получить ключ в TelegramОбзор API