Быстрый старт
Три шага от ключа до готового архива. Сайт собирается в среднем около минуты, поэтому заказ возвращает номер задания, а не сайт: дальше вы опрашиваете статус и скачиваете 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» в боте — там же его перевыпускают и отзывают. Кредиты за сайты списываются с общего баланса команды.
Как передать ключ
В любом из двух заголовков — они равноценны. Второй нужен, если ваша библиотека уже занимает Authorization.
Authorization: Bearer sg_ваш_ключ X-Api-Key: sg_ваш_ключ
Тарифы в запросе
Тариф передаётся в поле tier и определяет, сколько кредитов спишется и что получит сайт. Подписка на API тариф не ограничивает: по одному ключу можно заказывать любой.
basicpremiumeliteПолное сравнение возможностей — на странице «Тарифы».
Заказать сайт
Ставит сайт в очередь и списывает кредиты по тарифу. Ответ приходит сразу — с номером задания и местом в очереди.
Параметры тела запроса
Правила полей
Ошибки формата возвращаются все сразу: 400 invalid_request, перечень — в data.issues. Кредиты при этом не списываются. Неизвестные поля игнорируются.
companyInfoobjectЕсли объект передан, name, email и phone обязательны. Без объекта название и контакты придумает генератор. Все поля — строки.
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: им нужен полный адрес.
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, заказ не создаётся. Уберите этот язык и повторите.
"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 | phphtml(по умолчанию) — статический сайт: любой хостинг, 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"
}
}{
"success": true,
"jobId": "V1StGXR8Z5jd",
"queue": {
"position": 3,
"etaSeconds": 90
},
"warnings": []
}Поля ответа
Узнать статус
Показывает, на каком этапе заказ. Опрашивайте раз в 3–5 секунд, пока статус не станет конечным: completed, failed или cancelled.
{
"jobId": "V1StGXR8Z5jd",
"status": "processing",
"queuePosition": null,
"etaSeconds": null,
"progress": 55,
"step": "Тексты готовы, подбираем фото…",
"error": null,
"ready": false
}Статусы
Отменить заказ
Работает, пока заказ ждёт в очереди (pending). Кредиты сразу возвращаются на баланс. Если сборка уже началась, отменить её нельзя — ответ 409 not_waiting.
{ "jobId": "V1StGXR8Z5jd", "status": "cancelled", "refunded": true }Скачать архив
Отдаёт application/zip потоком, когда статус — completed. Архив хранится 14 дней, скачивать его можно сколько угодно раз. Позже ответ — 410 gone.
Ошибки
Машинный код ошибки — в data.code. Опирайтесь на него: текст сообщения может меняться.
{
"statusCode": 422,
"message": "Эту нишу мы не генерируем: …",
"data": {
"code": "niche_refused",
"category": "gambling",
"reason": "азартные игры",
"alternatives": [
{ "label": "клуб настольных игр", "canonical": null }
]
}
}Чужое задание отвечает тем же 404, что и несуществующее, — так номера заданий нельзя проверить перебором.
Лимиты и очередь
При 429 приходит заголовок Retry-After с числом секунд. Дождитесь его: повтор раньше срока не обходит лимит, а продлевает его. Лимиты считаются по ключу, а не по IP-адресу.