# eaipostou > Gerador de imagens de posts para redes sociais. Cria cards no estilo tweet ou nota de celular, divide texto longo em carrossel com IA e renderiza imagens 1080px prontas para o feed do Instagram. Interface web em https://eaipostou.com.br/studio e API REST documentada abaixo. Uso responsavel: por padrao as imagens carregam um aviso de simulacao ("Simulacao criada para fins ilustrativos"). O conteudo gerado e ilustrativo e nao deve ser usado para se passar por publicacoes reais de terceiros. ## Base da API - Base URL: https://eaipostou.com.br/api - Formato: JSON (Content-Type: application/json) - Erros: sempre {"detail": "mensagem em portugues"} - Envie um User-Agent proprio (ex.: "MeuAgente/1.0"). Clientes com User-Agent generico de biblioteca podem ser barrados na borda. - OpenAPI: https://eaipostou.com.br/api/openapi.json - Swagger UI: https://eaipostou.com.br/api/docs ## Autenticacao Duas opcoes, ambas via header `Authorization: Bearer `: 1. Chave de API (recomendada para agentes): formato `sps_live_...`. O usuario gera em Studio > Conta e equipe > Chaves de API. Nao expira; pode ser revogada. 2. Token JWT: `POST /auth/login` com {"email": "...", "password": "..."} devolve {"access_token": "..."} valido por 7 dias. Registro: `POST /auth/register` com {"email", "name", "password"}. `GET /auth/me` devolve o usuario atual: {"id", "email", "name", "plan": "free|pro", "role": "user|admin"}. ## Planos e limites - Free: 15 exportacoes/mes, 5 geracoes de IA/mes, carrossel de ate 5 cards, 3 projetos na nuvem. Imagens saem com a assinatura "feito com eaipostou". - Pro: sem limites mensais, carrossel de ate 20 cards, sem assinatura. - Ha um teto global mensal de geracoes de IA na instancia (protecao de custo). Quando atingido, `POST /ai/carousel` responde 503. ## Endpoints principais ### POST /ai/carousel — dividir texto em cards com IA Body: {"text": "50 a 30000 caracteres", "max_cards": 2-20 (opcional, padrao 10), "instructions": "ate 500 chars (opcional)"} Resposta 200: {"cards": ["texto do card 1", ...], "usage": {"plan", "month", "used", "limit", "remaining"}} Erros: 403 limite mensal do plano Free atingido; 503 IA indisponivel ou teto global atingido; 422 conteudo recusado. ### POST /render — renderizar imagem de um projeto Body: {"project": , "mode": "carousel"|"single", "ratio": "4:5"|"1:1"|"livre", "style": "cheio"|"janela", "margin": 0-120, "show_counter": bool, "show_hint": bool} - mode carousel: um slide 1080px por card. Resposta: image/png (1 card) ou application/zip (varios). - mode single: uma imagem unica com todos os cards empilhados. Respeita o ratio: 4:5 = 1080x1350, 1:1 = 1080x1080, "livre" = altura automatica do conteudo. Resposta: image/png. - Para Instagram, ambos os modos com ratio 4:5 dao 1080x1350; para 1 card tanto faz carousel ou single. - style cheio (padrao): o conteudo ocupa a imagem toda, melhor leitura no feed. ### POST /render/batch — varios posts de uma vez Body: {"csv": "texto csv"} OU {"rows": [{...}]}, mais os mesmos campos de estilo do /render e {"theme": "light"|"gray"|"dark", "notice": "simulacao"|..., "profile": {...} opcional}. Colunas/chaves de cada linha: nome, usuario, conteudo, data, horario, origem, visualizacoes, respostas, compartilhamentos, curtidas, salvamentos. Cada linha vira um card. Resposta: application/zip com as imagens. ### Projetos (nuvem) - GET /projects — lista {"id", "name", "workspace_id", "owner_name", "updated_at"} - POST /projects — body {"name", "data": , "workspace_id": null|id} - GET /projects/{id} | PUT /projects/{id} | DELETE /projects/{id} ### Chaves de API - GET /keys — lista as chaves do usuario (sem o valor completo) - POST /keys — body {"label": "nome"}; resposta inclui "key" (valor completo, exibido so nesta resposta) - DELETE /keys/{id} — revoga ### Uso - GET /usage/export — contador de exportacoes do mes - GET /ai/usage — contador de geracoes de IA do mes ## O objeto Projeto Mesmo JSON usado pelo studio. Campos ausentes ganham valores padrao na renderizacao, entao o projeto MINIMO valido e: {"name": "meu post", "themeId": "dark", "posts": [{"text": "card 1"}, {"text": "card 2"}]} Atencao aos defaults: sem "date"/"time" a linha de data NAO aparece (bom), mas sem "metrics" os cards saem com numeros de exemplo e sem "profile" saem como "Sua Marca". Para controle total, envie o objeto completo: { "id": "string", "name": "string", "updatedAt": "ISO-8601", "cardStyle": "tweet" | "notas", // visual do card (ausente = tweet) "themeId": "light" | "gray" | "dark" | "custom", "customTheme": {"appBg", "cardBg", "accent", "textPrimary", "textSecondary", "border", "radius"}, "notice": "simulacao" | "educativo" | "patrocinado" | "ficticio" | "estudo-de-caso" | "opiniao" | "none", "noticeInCard": true, "canvasPreset": "auto", "posts": [ { "id": "string", "profile": {"name", "username", "role", "avatarDataUrl": null|dataURL, "badge": "none|check|star|shield", "badgeColor": "#hex"}, "text": "conteudo do card; \n para quebras. No estilo notas, ==palavra== vira marca-texto amarelo", "fontSize": 17, "media": [{"id", "dataUrl", "alt"}], "date": "8 de ago. de 2026", "time": "12:00", "client": "", "metrics": {"views", "replies", "reposts", "likes", "bookmarks"} // numero ou null (oculta) } ], "exportSettings": {"format": "png", "scale": 2, "quality": 0.95, "fileName": "post", "transparent": false, "margin": 48} } Notas sobre cardStyle "notas": renderiza como nota de celular (barra "< Notas", texto grande, @username discreto). Ignora metrics, date, badge e avatar. O tema controla o fundo: dark = nota preta, light = nota branca. Tipografia adaptativa: quando "fontSize" e omitido ou 17 (padrao), a renderizacao aumenta a fonte automaticamente para textos curtos (ate 90 chars -> 26px; ate 160 -> 22px; ate 260 -> 19px), para a frase preencher bem a arte. Para controle manual, envie um fontSize diferente de 17 (ex.: frase de impacto: 24-28; texto medio: 19-21; texto longo: 17). Regras de exibicao importantes: - Ocultar data e horario: envie "date": "" e "time": "" (linha some do card). Nao invente datas se o usuario nao pedir. - Ocultar uma metrica: valor null. Ocultar todas: todas null. - Foto de perfil (avatarDataUrl): e um data URL base64. NAO tem como inventar; ela so existe dentro de um projeto ja salvo pelo usuario. Para usar a foto, SEMPRE parta de um projeto salvo (fluxo abaixo). ## Fluxo recomendado: partir de um projeto salvo do usuario Se o usuario tem um projeto salvo (ex.: "MDN") com foto, nome e @, NAO monte o Projeto do zero. Reaproveite o salvo, trocando apenas os textos: 1. GET /projects e encontre o item com o "name" que o usuario citou. Guarde o "id". 2. GET /projects/{id}. O campo "data" e o Projeto completo, com o perfil e a foto (avatarDataUrl) intactos. 3. Monte os novos posts copiando um post existente de data.posts como base (preserva profile com a foto) e trocando so o "text" de cada card. Para N cards, replique a base N vezes com ids diferentes. 4. Ajuste o que o usuario pedir (ex.: "date": "" e "time": "" para sair sem data, metricas null para sair sem numeros). 5. Renderize com o payload do passo seguinte. ## Receita para Instagram (feed) Para gerar imagens no formato que o Instagram usa, mande exatamente: POST /render {"project": , "mode": "carousel", "ratio": "4:5", "style": "cheio"} - mode "carousel" + ratio "4:5": um slide de 1080x1350 por card (o formato do feed). ratio "1:1" da 1080x1080. - style "cheio": o conteudo ocupa a imagem inteira (recomendado; e o que os perfis grandes usam). style "janela" poe o card como uma moldura flutuando sobre o fundo do tema: evite, a leitura no celular fica pior. - A resposta e image/png com 1 card ou application/zip com varios (publique as imagens na ordem). ## Exemplo completo (agente que cria um carrossel do zero) 1. Divida o texto: POST /ai/carousel {"text": "...", "max_cards": 5} 2. Se o usuario tem projeto salvo, siga o "Fluxo recomendado" acima para montar o Projeto com o perfil real. Senao, monte com o objeto de referencia. 3. Renderize com a "Receita para Instagram": POST /render {"project": ..., "mode": "carousel", "ratio": "4:5", "style": "cheio"} e salve o ZIP. 4. Opcional: salve na nuvem com POST /projects (ou PUT /projects/{id} para atualizar) para o usuario abrir no studio depois. ```python import json, urllib.request BASE = "https://eaipostou.com.br/api" KEY = "sps_live_SUA_CHAVE" def req(path, data=None): r = urllib.request.Request( BASE + path, data=json.dumps(data).encode() if data else None, headers={"Content-Type": "application/json", "Authorization": f"Bearer {KEY}", "User-Agent": "MeuAgente/1.0"}) return urllib.request.urlopen(r, timeout=120) cards = json.load(req("/ai/carousel", {"text": "seu texto longo...", "max_cards": 5}))["cards"] ``` ## Links - Studio (interface web): https://eaipostou.com.br/studio - Guia da API para humanos: https://eaipostou.com.br/docs - OpenAPI: https://eaipostou.com.br/api/openapi.json