exstru
Abrir no Telegram
← Visão geral da API

exstru API · v1

Documentação API.

Tudo o que é preciso para a integração: acesso e chave, parâmetros do pedido, status, arquivo, erros, limites e regras de débito de créditos.

URL BASEhttps://exstru.com/api/v1
FORMATOJSON · UTF-8
AUTORIZAÇÃOBearer sg_…
RESULTADOArquivo ZIP do site

Início rápido

Três passos da chave ao arquivo pronto. Um site leva em média cerca de um minuto para ser gerado, por isso o pedido retorna o número da tarefa, e não o site: depois você consulta o status e baixa o ZIP.

01Obtenha uma chaveCompre o pacote Team, Holding ou Kraken — a API é ativada por 30 dias grátis. A chave é emitida no bot, na seção “API”.
02Peça um siteEnvie o nicho, o idioma e o plano. A resposta traz o número da tarefa e a posição na fila.
03Baixe o arquivoConsulte o status a cada 3–5 segundos. Assim que o pedido ficar pronto, baixe o ZIP.
ciclo completo
# 1. Pedir um site
curl -X POST https://exstru.com/api/v1/generate \
  -H 'Authorization: Bearer sg_sua_chave' \
  -H 'Content-Type: application/json' \
  -d '{ "tier": "premium", "siteType": "local-business",
        "niche": "odontologia", "language": "es", "country": "ES" }'

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

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

# 3. Baixar o arquivo quando status = completed
curl -o site.zip https://exstru.com/api/v1/download/V1StGXR8Z5jd \
  -H 'Authorization: Bearer sg_sua_chave'

Acesso e chave

A API é vinculada à equipe. Uma chave no formato sg_… é emitida pelo dono na seção “API” do bot — lá mesmo ela é reemitida e revogada. Os créditos dos sites são debitados do saldo compartilhado da equipe.

30 dias grátisNa primeira compra do pacote Team, Holding ou Kraken. Uma vez por equipe. Avisamos 7 e 3 dias antes do fim e no último dia.
$99 / 30 diasDepois do período de teste. Pagamento com o saldo estável em dólares, não com créditos.
Renovação automáticaSó você pode ativar. Se faltar dinheiro para a renovação, o dono recebe uma notificação e a API continua funcionando por mais 24 horas.
Sem assinaturaSó a API é desativada: o painel da equipe, os créditos e a geração no bot continuam funcionando. A chave responde 403 subscription_inactive.

Como enviar a chave

Em qualquer um dos dois cabeçalhos — eles são equivalentes. O segundo serve para quando a sua biblioteca já ocupa Authorization.

títulos
Authorization: Bearer sg_sua_chave
X-Api-Key: sg_sua_chave
A chave dá acesso aos créditos da equipe.Guarde-a no servidor, e não no navegador ou em um app móvel: de lá ela é fácil de extrair. Se a chave vazar, revogue-a ou emita outra no bot — a antiga para de funcionar na hora.

Planos na requisição

O plano é enviado no campo tier e define quantos créditos serão debitados e o que o site recebe. A assinatura da API não limita o plano: com uma mesma chave, dá para pedir qualquer um.

Parâmetrobasicpremiumelite
Créditos debitados61025
Idiomas no site1até 3até 10
Cor da marca própria—✓✓
Logotipo—exclusivoexclusivo
Imagensbanco de imagensIA para o nichoIA para o nicho
Formuláriosde contato+ pedido de retorno de ligação+ quiz
Páginas principais~5–7~7–10~10–15+
Artigos no blog3–55–1010–15

A comparação completa dos recursos está na página “Preços”.

POST/api/v1/generate

Pedir um site

Coloca um site na fila e debita os créditos conforme o plano. A resposta chega na hora — com o número da tarefa e a posição na fila.

Parâmetros do corpo da requisição

CampoDescrição
tierobrigatóriostring · basic | premium | elitePlano do site: serão debitados 6, 10 ou 25 créditos.
siteTypeobrigatóriostring · local-business | blogSite de empresa ou blog. No blog, o número de artigos depende do plano: 3–5, 5–10 ou 10–15.
nicheobrigatóriostring · 2–100 caracteresO nicho com suas palavras, por exemplo “odontologia” ou “conserto de máquinas de lavar”. Geramos só nichos white: os demais recebem a recusa 422 niche_refused com opções parecidas, e nenhum crédito é debitado.
languageobrigatóriostring · código ISO 639-1Idioma principal do site: código de duas letras, um dos 14 suportados — en, de, ru, es, fr, it, pt, nl, pl, cs, ro, sv, da, no.
extraLanguagesopcionalstring[]Idiomas adicionais; o site ganha um seletor de idioma. Premium — até 2, Elite — até 9: com o principal, até 3 e até 10. No Basic — só o principal. Repetições, limite e idiomas incompatíveis — nas regras abaixo.
countryobrigatóriostring · código ISO 3166-1País da empresa: moeda dos preços, formato de telefone e endereço, região na marcação e páginas legais obrigatórias, como o Impressum para DE, AT e CH. Campo obrigatório. A lista está nas regras abaixo.
archiveFormatopcionalstring · html | phpFormato do arquivo: html — site estático para qualquer hospedagem, php — os formulários enviam as solicitações direto para o e-mail. Sem o campo — html. Mais detalhes nas regras abaixo.
baseUrlopcionalstring · domínioDomínio do futuro site: com ele, o arquivo inclui sitemap.xml, canonical e hreflang. O formato está nas regras abaixo.
brandColoropcionalstring · #rrggbbCor da marca — no Premium e no Elite; a paleta é montada em torno dela. O formato está nas regras abaixo.
keywordsopcionalstring[] · até 8 frasesFrases-chave que vão entrar nos títulos e nos textos.
companyInfoopcionalobjectNome, contatos e fatos sobre a empresa. Se não forem enviados, o gerador os inventa; quanto mais dados, mais precisos os textos. O esquema está nas regras abaixo.

Regras dos campos

Os erros de formato são retornados todos de uma vez: 400 invalid_request, listados em data.issues. Nenhum crédito é debitado. Campos desconhecidos são ignorados.

companyInfoobject

Se o objeto for enviado, name, email e phone são obrigatórios. Sem o objeto, o gerador inventa o nome e os contatos. Todos os campos são strings.

name2–200 · obrigatórioNome da empresa, como na fachada.
emailemail · obrigatórioEndereço para a página de contato e os formulários.
phone5–30 · obrigatórioTelefone no formato internacional: +34 600 000 000.
addressaté 300Endereço do escritório ou da loja.
descriptionaté 1000O que a empresa faz: 1–3 frases.
legalInfoaté 500Razão social e dados da empresa para as páginas legais.
foundedYearaté 20Ano de fundação: “2014” ou “desde 2014”.
teamSizeaté 20Tamanho da equipe: “12” ou “10–15”.
founderNameaté 120Nome do fundador para a página “Sobre”.
founderRoleaté 120Cargo do fundador.
serviceAreaaté 160Área de atuação: “Madri e região”.
brandColorstring
  • Formato — #rrggbb ou o curto #rgb, sem diferenciar maiúsculas e minúsculas; espaços nas pontas são removidos. #1E6FD9 e #1e6fd9 — a mesma cor, #16d é lido como #1166dd.
  • String vazia ou campo ausente — a paleta é escolhida para o nicho.
  • Outros formatos — rgb(), nomes de cores, código sem # — erro 400 invalid_request.
  • A cor não é copiada exatamente: cada site recebe um tom próximo, só dele, para que os sites de uma mesma equipe não se repitam.
  • No Basic, o campo é aceito, mas não aplicado — aviso brand_color_not_in_tier.
baseUrlstring · até 253 caracteres
  • Domínio em caracteres latinos: letras, números e hífen, com pelo menos um ponto. Domínios em cirílico — em punycode: xn--…
  • O esquema é opcional: http:// e https:// são aceitos; os links do site sempre usarão https.
  • www é mantido — você decide qual host é o canônico. Um caminho é permitido para um site em subpasta.
  • Barra no final, parâmetros ?… e a âncora #… são descartados.
  • Não são aceitos: espaços, porta, endereço IP, login no endereço (user@) — erro 400 invalid_request.
  • Sem domínio, o site é gerado sem sitemap.xml, canonical, og:url e hreflang: eles precisam do endereço completo.
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
meu site.com.br400 invalid_request
extraLanguagesstring[]
  • Códigos — como em language: códigos ISO 639-1 de duas letras, em minúsculas, da lista de idiomas suportados. Variantes regionais (en-GB, pt-BR) não são aceitos.
  • O idioma principal fica na raiz do site e é marcado como x-default. Os idiomas adicionais ficam em subpastas /en/, /de/ na ordem do array.
  • Repetições e o idioma principal dentro de extraLanguages são ignorados e não contam para o limite.
  • Limite do plano — Premium 2, Elite 9 adicionais, Basic 0. Os idiomas excedentes são descartados a partir do fim do array, e o preço do pedido não muda — aviso language_limit.
  • Código não suportado em language ou extraLanguages — erro 400 invalid_request.
  • Se o nicho não puder ser feito em um dos idiomas (por exemplo, VPN em russo) — 422 niche_language_refused, e o pedido não é criado. Remova esse idioma e tente de novo.
exemplo · premium
"tier": "premium",
"language": "es",
"extraLanguages": ["es", "en", "en", "de", "fr"]

→ idiomas do site: es (raiz), /en/, /de/
→ "warnings": [{
    "code": "language_limit",
    "field": "extraLanguages",
    "message": "Premium: até 3 idiomas, fr não adicionado"
  }]
countrystring · 2 letras
  • Código ISO 3166-1, sem diferenciar maiúsculas e minúsculas: mx e MX — é o mesmo país.
  • Suportados: 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.
  • O país não muda o idioma do site — quem define é language. Um site em inglês para uma empresa alemã é "language": "en", "country": "DE": preços em euros, telefone +49, Impressum em inglês.
  • Campo ausente ou código fora da lista — erro 400 invalid_request com o campo country, e nenhum crédito é debitado.
exemplo
"language": "es",
"country": "MX"

→ preços em pesos
→ telefone +52 55 1234 5678
→ <html lang="es-MX">
archiveFormatstring · html | php
  • html (padrão) — site estático: qualquer hospedagem, Netlify, GitHub Pages.
  • php — as mesmas páginas, mais um processador de solicitações: os formulários as enviam para companyInfo.email. Precisa de hospedagem com PHP 7.0 ou mais recente, com envio de e-mail funcionando (mail()).
  • Sem companyInfo.email o site recebe contatos de demonstração e não há e-mail para as solicitações: os formulários não as aceitam até você colocar um endereço no início do arquivo PHP.
  • O preço não depende do formato. Qualquer outro valor é erro 400 invalid_request.

Exemplo

requisição
POST /api/v1/generate
Authorization: Bearer sg_sua_chave
Content-Type: application/json

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

Campos da resposta

jobIdNúmero da tarefa: necessário para status, cancelamento e download.
queuePosição na fila (position, 1 = o próximo) e espera estimada até o início, em segundos (etaSeconds). null — se a geração começou imediatamente.
warningsO que da requisição não foi aplicado — o pedido é executado mesmo assim. Array de objetos { code, field, message }: language_limit — idiomas além do plano, brand_color_not_in_tier — cor da marca no Basic.
GET/api/v1/status/{jobId}

Ver o status

Mostra em que etapa o pedido está. Consulte a cada 3–5 segundos, até o status ser final: completed, failed ou cancelled.

statusUm dos cinco status — veja abaixo.
queuePositionPosição na fila enquanto o pedido aguarda. Caso contrário, null.
etaSecondsEspera estimada até o início, enquanto o pedido aguarda.
progressProgresso de 0 a 100.
stepA etapa atual da geração, em texto.
errorO motivo, se a geração falhou.
readytrue — o arquivo pode ser baixado.
resposta · 200
{
  "jobId": "V1StGXR8Z5jd",
  "status": "processing",
  "queuePosition": null,
  "etaSeconds": null,
  "progress": 55,
  "step": "Textos prontos, escolhendo as fotos…",
  "error": null,
  "ready": false
}

Status

pendingAguardando na fila. Pode ser cancelado.
processingSendo gerado.
completedPronto — baixe o arquivo.
failedA geração falhou. Os créditos voltaram automaticamente.
cancelledCancelado na fila. Os créditos voltaram.
POST/api/v1/cancel/{jobId}

Cancelar um pedido

Funciona enquanto o pedido aguarda na fila (pending). Os créditos voltam para o saldo na hora. Se a geração já começou, não é possível cancelar — a resposta é 409 not_waiting.

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

Baixar o arquivo

Retorna application/zip em fluxo, quando o status é completed. O arquivo fica guardado por 14 dias e pode ser baixado quantas vezes quiser. Depois disso, a resposta é 410 gone.

HTML · CSS · imagensUm site estático pronto para qualquer hospedagem — sem CMS e sem build.
robots.txt · página 404O mínimo técnico — em todos os planos.
sitemap.xml · canonicalSe o pedido tiver um domínio em baseUrl.
Páginas legaisNos idiomas do site — em todos os planos.

Erros

O código de erro legível por máquina fica em data.code. Baseie-se nele: o texto da mensagem pode mudar.

exemplo · 422
{
  "statusCode": 422,
  "message": "Não geramos este nicho: …",
  "data": {
    "code": "niche_refused",
    "category": "gambling",
    "reason": "jogos de azar",
    "alternatives": [
      { "label": "clube de jogos de tabuleiro", "canonical": null }
    ]
  }
}
HTTPdata.codeO que significa e o que fazer
400invalid_requestA requisição não passou na validação. Todos os problemas de uma vez — em data.issues.
401no_keyA chave não foi enviada. Adicione o cabeçalho Authorization ou X-Api-Key.
401unknown_keyA chave está incorreta. Compare-a com a chave do bot.
402insufficient_creditsCréditos insuficientes no saldo da equipe. Recarregue o saldo ou ative a recarga automática.
403key_blockedA chave foi revogada. Emita uma nova no bot.
403subscription_inactiveA assinatura da API está inativa. O dono a renova no bot — $99 por 30 dias.
404not_foundA tarefa não existe ou pertence a outra equipe.
409not_waitingSó é possível cancelar um pedido na fila — este já está sendo gerado ou está pronto.
409not_readyO pedido ainda não está pronto. Aguarde o status completed.
410goneO arquivo não está mais guardado: passaram-se 14 dias.
422niche_refusedNão geramos este nicho. O motivo está em data.category e data.reason; até 3 nichos white parecidos — em data.alternatives. Nenhum crédito é debitado.
422niche_language_refusedFazemos este nicho, mas não neste idioma. Remova o idioma de language ou extraLanguages. Nenhum crédito é debitado.
429queue_full_for_accountA equipe já tem 30 pedidos na fila. Um novo será aceito quando parte deles ficar pronta. Nenhum crédito é debitado.
429rate_limitedRequisições frequentes demais. Aguarde a quantidade de segundos indicada em Retry-After.
503niche_unverifiedNão foi possível verificar o nicho. Repita a requisição — nenhum crédito é debitado.

A tarefa de outra equipe retorna o mesmo 404 de uma tarefa inexistente — assim não dá para descobrir números de tarefa por tentativa e erro.

Limites e fila

5 por minutopedidos por chave.
240 por minutodemais requisições: status, cancelamento, download.
30 na filapedidos de uma equipe ao mesmo tempo. Novos são aceitos quando parte deles ficar pronta.
Fila justaOs pedidos de uma equipe não atrasam os das outras: a resposta sempre mostra a posição e a espera.

Em caso de 429 a resposta traz o cabeçalho Retry-After com o número de segundos. Aguarde: repetir antes do prazo não contorna o limite, só o prolonga. Os limites são contados por chave, e não por endereço IP.

Débitos e reembolsos

Quando são debitadosQuando o pedido entra na fila, antes do início da geração: 6, 10 ou 25 créditos, conforme o plano. As chamadas à API em si não são cobradas.
FalhaSe a geração falhar, os créditos voltam automaticamente.
CancelamentoEnquanto o pedido está na fila, dá para cancelá-lo — os créditos voltam na hora.
Sem cobrançaNicho recusado, erro na requisição ou fila cheia — nenhum crédito é debitado.
Sem cobranças duplicadasO débito e o reembolso ficam vinculados ao número da tarefa: um pedido não é debitado nem reembolsado duas vezes.
Créditos bônusSe houver créditos bônus no saldo, eles são gastos primeiro.
Créditos compradosFicam no saldo sem limite de tempo.
Recarga automáticaPara equipes: quando os créditos ficam abaixo do limite mínimo definido, o pacote escolhido é comprado automaticamente com o saldo estável, e a integração não para. Desativado por padrão.
Precisa de ajuda com a integração?Escreva para o suporte [@username] — ajudamos com o código e o cenário.Obter chave no TelegramVisão geral da API