exstru
Abrir en Telegram
← Resumen de la API

exstru API · v1

Documentación API.

Todo lo necesario para la integración: acceso y clave, parámetros del pedido, estados, archivo, errores, límites y reglas de cobro de créditos.

URL BASEhttps://exstru.com/api/v1
FORMATOJSON · UTF-8
AUTORIZACIÓNBearer sg_…
RESULTADOArchivo ZIP del sitio

Inicio rápido

Tres pasos de la clave al archivo terminado. Un sitio tarda de media alrededor de un minuto en generarse, por eso el pedido devuelve un ID de tarea y no el sitio: después consultas el estado y descargas el ZIP.

01Obtén una claveCompra el paquete Team, Holding o Kraken — la API se activa 30 días gratis. La clave se emite en el bot, en la sección «API».
02Pide un sitioEnvía el nicho, el idioma y el plan. La respuesta incluye el número de tarea y su posición en la cola.
03Descarga el archivoConsulta el estado cada 3–5 segundos. En cuanto el pedido esté listo, descarga el ZIP.
ciclo completo
# 1. Pedir un sitio
curl -X POST https://exstru.com/api/v1/generate \
  -H 'Authorization: Bearer sg_tu_clave' \
  -H 'Content-Type: application/json' \
  -d '{ "tier": "premium", "siteType": "local-business",
        "niche": "odontología", "language": "es", "country": "ES" }'

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

# 2. Consultar el estado cada 3–5 segundos
curl https://exstru.com/api/v1/status/V1StGXR8Z5jd \
  -H 'Authorization: Bearer sg_tu_clave'

# 3. Descargar el archivo cuando status = completed
curl -o site.zip https://exstru.com/api/v1/download/V1StGXR8Z5jd \
  -H 'Authorization: Bearer sg_tu_clave'

Acceso y clave

La API se conecta al equipo. Una clave del tipo sg_… la genera el propietario en la sección «API» del bot; allí también se regenera y se revoca. Los créditos de los sitios se descuentan del saldo común del equipo.

30 días gratisCon la primera compra del paquete Team, Holding o Kraken. Una vez por equipo. Te avisaremos 7 y 3 días antes del vencimiento y el último día.
$99 / 30 díasDespués del periodo de prueba. Se paga con el saldo estable en dólares, no con créditos.
Renovación automáticaSolo la activas tú. Si no hay dinero suficiente para renovar, el propietario recibe un aviso y la API sigue funcionando 24 horas más.
Sin suscripciónSolo se desactiva la API: el panel del equipo, los créditos y la generación en el bot siguen funcionando. La clave responde con 403 subscription_inactive.

Cómo enviar la clave

En cualquiera de los dos encabezados — son equivalentes. El segundo sirve si tu librería ya ocupa Authorization.

títulos
Authorization: Bearer sg_tu_clave
X-Api-Key: sg_tu_clave
La clave da acceso a los créditos del equipo.Guárdala en tu servidor, no en el navegador ni en una app móvil: de ahí es fácil extraerla. Si la clave se filtra, revócala o genera una nueva en el bot: la anterior deja de funcionar al instante.

Planes en la solicitud

El plan se indica en el campo tier y determina cuántos créditos se descuentan y qué recibe el sitio. La suscripción a la API no limita el plan: con una misma clave puedes pedir cualquiera.

Parámetrobasicpremiumelite
Créditos que se descuentan61025
Idiomas por sitio1hasta 3hasta 10
Color de marca propio—✓✓
Logotipo—únicoúnico
ImágenesstockIA según el nichoIA según el nicho
Formularioscontacto+ solicitud de llamada+ quiz
Páginas principales~5–7~7–10~10–15+
Artículos en el blog3–55–1010–15

La comparación completa de funciones está en la página «Precios».

POST/api/v1/generate

Pedir un sitio

Pone un sitio en cola y descuenta créditos según el plan. La respuesta llega al instante, con el ID de la tarea y el puesto en la cola.

Parámetros del cuerpo de la solicitud

CampoDescripción
tierobligatoriostring · basic | premium | elitePlan del sitio: se descontarán 6, 10 o 25 créditos.
siteTypeobligatoriostring · local-business | blogSitio de empresa o blog. En el blog, el número de artículos depende del plan: 3–5, 5–10 o 10–15.
nicheobligatoriostring · 2–100 caracteresEl nicho con tus propias palabras, por ejemplo «odontología» o «reparación de lavadoras». Solo generamos nichos blancos: el resto recibe un rechazo 422 niche_refused con opciones cercanas, y no se cobran créditos.
languageobligatoriostring · código ISO 639-1Idioma principal del sitio: código de dos letras de uno de los 14 admitidos — en, de, ru, es, fr, it, pt, nl, pl, cs, ro, sv, da, no.
extraLanguagesopcionalstring[]Idiomas adicionales; el sitio tendrá un selector de idioma. Premium — hasta 2, Elite — hasta 9: con el principal, hasta 3 y hasta 10. Basic — solo el principal. Duplicados, límite e idiomas incompatibles — en las reglas de abajo.
countryobligatoriostring · código ISO 3166-1País del negocio: moneda de los precios, formato de teléfono y dirección, región en el marcado y páginas legales obligatorias, por ejemplo el imprint para DE, AT y CH. Campo obligatorio. La lista, en las reglas de abajo.
archiveFormatopcionalstring · html | phpFormato del archivo: html — sitio estático para cualquier hosting, php — los formularios envían las solicitudes al correo por sí solos. Sin el campo, html. Más detalles en las reglas de abajo.
baseUrlopcionalstring · dominioDominio del futuro sitio: con él, el archivo incluye sitemap.xml, canonical y hreflang. Formato — en las reglas de abajo.
brandColoropcionalstring · #rrggbbColor de marca: en Premium y Elite; la paleta se construye a su alrededor. El formato, en las reglas de abajo.
keywordsopcionalstring[] · hasta 8 frasesFrases clave que entrarán en los títulos y los textos.
companyInfoopcionalobjectNombre, contactos y datos de la empresa. Si no los envías, el generador los inventa; cuantos más datos, más precisos los textos. Esquema — en las reglas de abajo.

Reglas de los campos

Los errores de formato se devuelven todos a la vez: 400 invalid_request, la lista está en data.issues. No se cobra ningún crédito. Los campos desconocidos se ignoran.

companyInfoobject

Si envías el objeto, name, email y phone son obligatorios. Sin el objeto, el generador inventará el nombre y los contactos. Todos los campos son cadenas.

name2–200 · obligatorioNombre de la empresa, tal como aparece en el rótulo.
emailemail · obligatorioDirección para la página de contacto y los formularios.
phone5–30 · obligatorioTeléfono en formato internacional: +34 600 000 000.
addresshasta 300Dirección de la oficina o del local.
descriptionhasta 1000A qué se dedica la empresa: 1–3 frases.
legalInfohasta 500Razón social y datos fiscales para las páginas legales.
foundedYearhasta 20Año de fundación: «2014» o «desde 2014».
teamSizehasta 20Tamaño del equipo: «12» o «10–15».
founderNamehasta 120Nombre del fundador para la página «Sobre nosotros».
founderRolehasta 120Cargo del fundador.
serviceAreahasta 160Zona de servicio: «Madrid y alrededores».
brandColorstring
  • Formato — #rrggbb o el formato corto #rgb, sin distinguir mayúsculas; los espacios de los extremos se eliminan. #1E6FD9 y #1e6fd9 son el mismo color, #16d se lee como #1166dd.
  • Cadena vacía o campo ausente: la paleta se elige según el nicho.
  • Cualquier otro formato — rgb(), nombres de colores, un código sin # — error 400 invalid_request.
  • El color no se copia tal cual: cada sitio recibe un tono cercano propio, para que los sitios de un mismo equipo no se repitan entre sí.
  • En Basic el campo se acepta, pero no se aplica — aviso brand_color_not_in_tier.
baseUrlstring · hasta 253 caracteres
  • Dominio en caracteres latinos: letras, cifras y guiones, con al menos un punto. Los dominios en cirílico, en punycode: xn--…
  • El esquema es opcional: http:// y https:// se aceptan; los enlaces del sitio siempre usarán https.
  • www se conserva: tú decides qué host es el canónico. Se admite una ruta para un sitio en una subcarpeta.
  • Barra final, parámetros ?… y el ancla #… se descartan.
  • No se admiten: espacios, puerto, dirección IP, usuario en la dirección (user@) — error 400 invalid_request.
  • Sin dominio, el sitio se genera sin sitemap.xml, canonical, og:url y hreflang: necesitan una dirección completa.
EnviadoResultado
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[]
  • Códigos — igual que en language: códigos ISO 639-1 de dos letras en minúscula de la lista de admitidos. Las variantes regionales (en-GB, pt-BR) no se aceptan.
  • El idioma principal va en la raíz del sitio y se marca como x-default. Los idiomas adicionales van en subcarpetas /en/, /de/ en el orden del array.
  • Los duplicados y el idioma principal dentro de extraLanguages se omiten y no cuentan para el límite.
  • Límite del plan — Premium 2, Elite 9 adicionales, Basic 0. Los idiomas sobrantes se descartan desde el final del array y el precio del pedido no cambia — aviso language_limit.
  • Código no admitido en language o extraLanguages — error 400 invalid_request.
  • Si el nicho no se puede hacer en uno de los idiomas (por ejemplo, VPN en ruso) — 422 niche_language_refused, y no se crea el pedido. Quita ese idioma y vuelve a intentarlo.
ejemplo · premium
"tier": "premium",
"language": "es",
"extraLanguages": ["es", "en", "en", "de", "fr"]

→ idiomas del sitio: es (raíz), /en/, /de/
→ "warnings": [{
    "code": "language_limit",
    "field": "extraLanguages",
    "message": "Premium: hasta 3 idiomas, fr no añadido"
  }]
countrystring · 2 letras
  • Código ISO 3166-1, sin distinguir mayúsculas: mx y MX son el mismo país.
  • Compatibles: 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.
  • El país no cambia el idioma del sitio; lo define language. Un sitio en inglés para una empresa alemana es "language": "en", "country": "DE": precios en euros, teléfono +49, imprint en inglés.
  • Sin el campo o con un código fuera de la lista: error 400 invalid_request con el campo country, no se descuentan créditos.
ejemplo
"language": "es",
"country": "MX"

→ precios en pesos
→ teléfono +52 55 1234 5678
→ <html lang="es-MX">
archiveFormatstring · html | php
  • html (por defecto) — sitio estático: cualquier hosting, Netlify, GitHub Pages.
  • php — las mismas páginas, más un gestor de solicitudes: los formularios las envían a companyInfo.email. Requiere hosting con PHP 7.0 o superior en el que funcione el envío de correo (mail()).
  • Sin companyInfo.email el sitio recibe contactos de demostración y no hay correo para las solicitudes: los formularios no las aceptan hasta que escribas una dirección al principio del archivo PHP.
  • El precio no depende del formato. Cualquier otro valor es un error 400 invalid_request.

Ejemplo

solicitud
POST /api/v1/generate
Authorization: Bearer sg_tu_clave
Content-Type: application/json

{
  "tier": "premium",
  "siteType": "local-business",
  "niche": "odontología",
  "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"
  }
}
respuesta · 200
{
  "success": true,
  "jobId": "V1StGXR8Z5jd",
  "queue": {
    "position": 3,
    "etaSeconds": 90
  },
  "warnings": []
}

Campos de la respuesta

jobIdNúmero de tarea: necesario para el estado, la cancelación y la descarga.
queuePosición en la cola (position, 1 = el siguiente) y espera estimada hasta el inicio en segundos (etaSeconds). null si la generación empezó de inmediato.
warningsLo que de la solicitud no se aplicó; el pedido se ejecuta igualmente. Array de objetos { code, field, message }: language_limit — idiomas por encima del plan, brand_color_not_in_tier — color de marca en Basic.
GET/api/v1/status/{jobId}

Consultar el estado

Indica en qué etapa está el pedido. Consulta cada 3–5 segundos hasta que el estado sea final: completed, failed o cancelled.

statusUno de los cinco estados — ver abajo.
queuePositionPosición en la cola mientras el pedido espera. Si no, null.
etaSecondsEspera aproximada hasta el inicio, mientras el pedido aguarda.
progressProgreso de 0 a 100.
stepLa etapa actual de la generación, en texto.
errorEl motivo, si la generación falló.
readytrue — el archivo se puede descargar.
respuesta · 200
{
  "jobId": "V1StGXR8Z5jd",
  "status": "processing",
  "queuePosition": null,
  "etaSeconds": null,
  "progress": 55,
  "step": "Textos listos, buscando fotos…",
  "error": null,
  "ready": false
}

Estados

pendingEn cola. Se puede cancelar.
processingCompilándose.
completedListo — descarga el archivo.
failedLa generación falló. Los créditos se devolvieron automáticamente.
cancelledCancelado en la cola. Créditos devueltos.
POST/api/v1/cancel/{jobId}

Cancelar un pedido

Funciona mientras el pedido espera en la cola (pending). Los créditos vuelven al saldo al instante. Si la generación ya empezó, no se puede cancelar — la respuesta es 409 not_waiting.

respuesta · 200
{ "jobId": "V1StGXR8Z5jd", "status": "cancelled", "refunded": true }
GET/api/v1/download/{jobId}

Descargar el archivo

Devuelve application/zip en streaming cuando el estado es completed. El archivo se guarda 14 días y puedes descargarlo tantas veces como quieras. Después, la respuesta es 410 gone.

HTML · CSS · imágenesUn sitio estático listo para cualquier hosting — sin CMS ni compilación.
robots.txt · página 404El mínimo técnico, en todos los planes.
sitemap.xml · canonicalSi el pedido incluye un dominio en baseUrl.
Páginas legalesEn los idiomas del sitio, en todos los planes.

Errores

El código de error legible por máquina está en data.code. Básate en él: el texto del mensaje puede cambiar.

ejemplo · 422
{
  "statusCode": 422,
  "message": "Este nicho no lo generamos: …",
  "data": {
    "code": "niche_refused",
    "category": "gambling",
    "reason": "juegos de azar",
    "alternatives": [
      { "label": "club de juegos de mesa", "canonical": null }
    ]
  }
}
HTTPdata.codeQué significa y qué hacer
400invalid_requestLa solicitud no pasó la validación. Todos los problemas a la vez, en data.issues.
401no_keyNo se envió la clave. Añade la cabecera Authorization o X-Api-Key.
401unknown_keyLa clave no es válida. Compárala con la clave del bot.
402insufficient_creditsNo hay créditos suficientes en el saldo del equipo. Recarga el saldo o activa la recarga automática.
403key_blockedLa clave fue revocada. Emite una nueva en el bot.
403subscription_inactiveLa suscripción a la API está inactiva. El propietario la renueva en el bot: $99 cada 30 días.
404not_foundLa tarea no existe o pertenece a otro equipo.
409not_waitingSolo se puede cancelar un pedido en cola; este ya se está generando o está listo.
409not_readyEl pedido aún no está listo. Espera al estado completed.
410goneEl archivo ya no se conserva: han pasado 14 días.
422niche_refusedEste nicho no lo generamos. El motivo está en data.category y data.reason; hasta 3 nichos blancos cercanos, en data.alternatives. No se descuentan créditos.
422niche_language_refusedHacemos este nicho, pero no en este idioma. Quita el idioma de language o extraLanguages. No se cobran créditos.
429queue_full_for_accountEl equipo ya tiene 30 pedidos en cola. Aceptaremos uno nuevo cuando se hayan generado algunos. No se cobran créditos.
429rate_limitedDemasiadas solicitudes. Espera los segundos que indique Retry-After.
503niche_unverifiedNo se pudo comprobar el nicho. Repite la solicitud: no se cobran créditos.

Una tarea ajena responde con el mismo 404 que un trabajo inexistente — así los ID de trabajo no se pueden adivinar probando uno tras otro.

Límites y cola

5 por minutopedidos por clave.
240 por minutodel resto de solicitudes: estado, cancelación, descarga.
30 en colapedidos de un mismo equipo a la vez. Aceptaremos nuevos cuando parte de ellos esté lista.
Cola justaLos pedidos de un equipo no retrasan a los demás: la respuesta siempre muestra la posición y la espera.

Con 429 llega la cabecera Retry-After con el número de segundos. Espera ese tiempo: repetir antes no evita el límite, lo prolonga. Los límites se cuentan por clave, no por dirección IP.

Cobros y reembolsos

Cuándo se cobranAl poner el pedido en cola, antes de que empiece la generación: 6, 10 o 25 créditos según el plan. Las llamadas a la API en sí no se pagan.
FalloSi la generación falla, los créditos se devuelven automáticamente.
CancelaciónMientras el pedido está en la cola, puedes cancelarlo: los créditos vuelven al instante.
Sin cobroUn nicho rechazado, un error en la solicitud o la cola llena: no se cobran créditos.
Sin cobros doblesEl cobro y el reembolso van ligados al ID de la tarea: un mismo pedido no se cobra ni se reembolsa dos veces.
Créditos de bonificaciónSi tienes créditos de bonificación en el saldo, se gastan primero.
Créditos compradosSe quedan en el saldo sin límite de tiempo.
Recarga automáticaPara equipos: cuando los créditos bajan del umbral fijado, el paquete elegido se compra automáticamente con el saldo estable y la integración no se detiene. Desactivada por defecto.
¿Necesitas ayuda con la integración?Escribe a soporte [@username] — te ayudamos con el código y el escenario.Obtener una clave en TelegramResumen de la API