# AppKlub Builder API — llms-full > Documentação IA-friendly. Você é um agente/LLM lendo isto para construir um app de > membros AppKlub do zero, sem intervenção humana, via HTTP. Tudo aqui mapeia 1:1 para > endpoints reais da superfície pública `/api/v1`. Não há proxy genérico: a v1 é uma > fachada estável e curada sobre a lógica de domínio do AppKlub (multi-tenant, plan-gating, > quotas, URLs assinadas). Última atualização: 2026-05-30. ================================================================================ 0. O QUE VOCÊ CONSEGUE FAZER ================================================================================ Com uma API key válida (plano BUSINESS), você consegue, programaticamente: - Criar um app de membros (PWA), configurar tema/cor/idioma e publicá-lo. - Criar produtos (cursos), módulos (seções) e aulas (conteúdos: vídeo, PDF, texto, embed). - Criar trilhas (learning paths) que agrupam produtos numa ordem. - Vincular um produto a uma plataforma de pagamento (Hotmart, Kiwify, etc.) para liberação automática de acesso. - Adicionar membros (alunos) ao app. - Fazer TUDO acima numa ÚNICA chamada atômica: `POST /api/v1/apps/compose`. A árvore do recurso é: app ├── trail (agrupa products numa ordem) ├── product (curso / oferta) │ ├── module (seção que agrupa lessons) │ ├── lesson (Content: VIDEO/PDF/TEXT/YOUTUBE/…) │ └── integration (vínculo product ↔ plataforma de pagamento) └── member (aluno com acesso ao app) ================================================================================ 1. BASE URL E VERSIONAMENTO ================================================================================ Base URL de produção: https://seuapp.digital/api/v1 Todos os caminhos abaixo são relativos a essa base. A v1 é um contrato congelado: o shape de resposta e os campos `error.type` são estáveis. Mudanças incompatíveis = nova versão (`/api/v2`). Formato: JSON em request e response. Header `Content-Type: application/json` em todo POST/PATCH com body. ================================================================================ 2. AUTENTICAÇÃO — API KEY (Bearer) ================================================================================ A v1 NÃO usa cookies nem login com senha. Toda requisição é autenticada com uma API key de longa duração no header Authorization: Authorization: Bearer ak_live_<64 hex> Exemplo de header: Authorization: Bearer ak_live_9f3c2a...a3f9 Como obter a chave: - A chave é emitida pelo creator humano no dashboard do AppKlub (plano BUSINESS), em Configurações → API Keys. Não é possível criar chave via API — isso é deliberado (só o creator logado emite chave). - A chave é exibida UMA ÚNICA VEZ no momento da criação. Guarde-a com segurança. O AppKlub só armazena o hash SHA-256 da chave (banco vazado = chave inútil). Se você perdê-la, o creator gera uma nova e revoga a antiga. - O prefixo `ak_live_` identifica o ambiente (live). `ak_test_` é reservado para um futuro sandbox. Regras de auth: - Sem `Authorization` ou com chave malformada (não começa com `ak_live_`) → 401. - Chave revogada ou expirada → 401 com mensagem genérica `API key inválida` (anti-enumeração: o mesmo erro cobre ausente/inválida/revogada/expirada). - A chave resolve exatamente UM creator. Todo recurso que você cria/lê pertence a esse creator. Você nunca consegue tocar dados de outro creator (isolamento multi-tenant). Gate de plano: - A Builder API inteira fica atrás da feature de plano `apiAccess`. Hoje, na prática, isso significa plano BUSINESS. Se a chave pertence a um creator cujo plano não tem `apiAccess`, TODA chamada v1 retorna 403 `plan_feature_required` apontando upgrade para BUSINESS. (Se o creator cair de plano, a chave para de funcionar imediatamente.) ================================================================================ 3. CONVENÇÕES TRANSVERSAIS ================================================================================ -------------------------------------------------------------------------------- 3.1 Envelope de resposta (sucesso) -------------------------------------------------------------------------------- Sucesso de recurso único: { "data": { ...recurso... }, "meta": { "request_id": "req_abc123", "idempotent_replay": false } } Listas (paginadas): { "data": [ ...itens... ], "pagination": { "next_cursor": "eyJ...", "has_more": true, "limit": 25 } } -------------------------------------------------------------------------------- 3.2 Paginação (cursor-based) -------------------------------------------------------------------------------- Toda lista aceita query params: ?limit=<1..100> (default 25, max 100) ?cursor= (next_cursor da resposta anterior; base64 do id do último item) Para iterar, repita a chamada passando `cursor = pagination.next_cursor` até `has_more = false` (ou `next_cursor = null`). -------------------------------------------------------------------------------- 3.3 Idempotência (CRÍTICO para agentes) -------------------------------------------------------------------------------- Toda mutação (POST/PATCH/DELETE) na v1 EXIGE o header: Idempotency-Key: Comportamento: - 1ª chamada com uma key: executa a operação e grava (key, hash-do-body, resposta). - Replay com a MESMA key e o MESMO body: devolve a resposta gravada, com o status original, e `meta.idempotent_replay = true`. NÃO cria um segundo recurso. - Mesma key com body DIFERENTE: erro 422 `idempotency_key_reuse`. - TTL do registro de idempotência: 24h. Por que isso importa: se sua chamada der timeout e você fizer retry, sem a Idempotency-Key você criaria 2 apps / 2 produtos. Com ela, o retry é seguro — gere um UUID por operação lógica e reuse-o em todos os retries dessa operação. GET não usa Idempotency-Key (é naturalmente idempotente; o header é ignorado). -------------------------------------------------------------------------------- 3.4 Formato de erro (consistente) -------------------------------------------------------------------------------- Todo erro tem o mesmo shape: { "error": { "type": "validation_error", "message": "primaryColor deve ser #RRGGBB", "fields": { "primaryColor": ["formato inválido"] }, "doc_url": "https://docs.seuapp.digital/api/errors#validation_error", "request_id": "req_abc123" } } `fields` só aparece em erros de validação. `type` é estável e machine-readable. Mapa `type` → HTTP status: validation_error 400 ou 422 unauthorized 401 plan_feature_required 403 (feature não disponível no plano → upgrade BUSINESS) plan_limit_reached 403 (quota do plano estourada: maxApps, maxProducts, …) not_found 404 (recurso inexistente OU de outro tenant — anti-enum) conflict 409 (slug/subdomínio/unique já em uso) insufficient_credits 402 (operação que debita créditos de IA sem saldo) quota_exceeded 413 (storage acima de maxStorageBytes) idempotency_key_reuse 422 (mesma Idempotency-Key, body diferente) rate_limited 429 (rate limit por chave) internal 500 IMPORTANTE sobre 404 vs 403: se você passar um ID de recurso que não pertence ao seu creator, a API responde 404 (não 403). Isso é intencional (não vaza existência de IDs alheios). Trate 404 como "não existe para você". -------------------------------------------------------------------------------- 3.5 Rate limit -------------------------------------------------------------------------------- O rate limit é POR CHAVE (não por IP — agentes costumam rodar de IP fixo/serverless). Limites de referência: Leitura (GET): 600 req/min por chave Mutação (POST/…): 60 req/min por chave Ao estourar: 429 `rate_limited` + header `Retry-After` (segundos) + headers `RateLimit-*`. Faça backoff e tente de novo após `Retry-After`. -------------------------------------------------------------------------------- 3.6 Mídia (imagens, vídeos, PDFs) -------------------------------------------------------------------------------- Para campos de mídia (`logoUrl`, `thumbnailUrl`, `url`, `fileUrl`), forneça URLs `https://` já hospedadas. A v1 aceita URLs externas diretamente — você NÃO precisa fazer upload pelo AppKlub. Embeds de vídeo (YouTube/Vimeo/Loom/etc.) vão no campo `url` e são normalizados automaticamente pelo servidor. ================================================================================ 4. RECURSOS — ENDPOINTS ================================================================================ Legenda de IDs nos caminhos: `{appId}`, `{productId}`, `{moduleId}`, `{contentId}`, `{trailId}`, `{integrationId}`, `{memberId}` são CUIDs retornados na criação. -------------------------------------------------------------------------------- 4.1 APP (raiz da árvore) -------------------------------------------------------------------------------- POST /api/v1/apps Criar app GET /api/v1/apps Listar apps (paginado) GET /api/v1/apps/{appId} Obter app PATCH /api/v1/apps/{appId} Atualizar config do app POST /api/v1/apps/{appId}/publish Publicar (exige logoUrl) DELETE /api/v1/apps/{appId} Deletar app (cascade) GET /api/v1/apps/subdomain-available?value= Checar disponibilidade de subdomínio Gates herdados: criar app respeita `maxApps` do plano e exige email do creator verificado. Publicar exige `logoUrl` setado. Payload POST /api/v1/apps: { "name": "Finanças Pessoais", // obrigatório, 1..80 chars, sem < > "slug": "financas-pessoais", // opcional; vira subdomínio. 409 se em uso "primaryColor": "#6366f1", // opcional, #RRGGBB (default #6366f1) "logoUrl": "https://cdn.exemplo.com/logo.png", // opcional "theme": "NETFLIX", // LIGHT | DARK | NETFLIX | CUSTOM "language": "pt-BR" // pt-BR | es | en | fr | it | de } Resposta 201: { "data": { "id": "clx9a...", "name": "Finanças Pessoais", "slug": "financas-pessoais", "subdomain": "financas-pessoais.seuapp.digital", "primaryColor": "#6366f1", "theme": "NETFLIX", "language": "pt-BR", "published": false, "createdAt": "2026-05-30T12:00:00.000Z" }, "meta": { "request_id": "req_...", "idempotent_replay": false } } Payload PATCH /api/v1/apps/{appId} (campos opcionais; envie só o que mudar): { "name": "Novo nome", "description": "Descrição até 500 chars", "theme": "DARK", "primaryColor": "#10b981", "supportedLocales": ["pt-BR", "en"] // requer feature de tradução no plano } Nota: algumas mudanças disparam gate de feature/crédito (ex.: ativar tradução automática ou listagem pública). O gate dispara por MUDANÇA de estado, não por presença do campo. -------------------------------------------------------------------------------- 4.2 TRAIL (trilha / learning path) -------------------------------------------------------------------------------- GET /api/v1/apps/{appId}/trails POST /api/v1/apps/{appId}/trails PATCH /api/v1/apps/{appId}/trails/{trailId} DELETE /api/v1/apps/{appId}/trails/{trailId} Payload POST: { "name": "Trilha do Iniciante", // obrigatório "description": "Comece por aqui", // opcional, pode ser null "thumbnailUrl": "https://...", // opcional, pode ser null "productIds": ["clxProd1", "clxProd2"] // produtos do MESMO app, ordem preservada } Se algum `productId` não pertencer ao seu app, retorna erro genérico (anti-enum) sem revelar de quem é o ID. -------------------------------------------------------------------------------- 4.3 PRODUCT (curso / oferta) -------------------------------------------------------------------------------- GET /api/v1/apps/{appId}/products POST /api/v1/apps/{appId}/products GET /api/v1/apps/{appId}/products/{productId} PATCH /api/v1/apps/{appId}/products/{productId} DELETE /api/v1/apps/{appId}/products/{productId} Gate: criar produto respeita `maxProductsPerApp`. A leitura de um product já traz os contents aninhados. Payload POST: { "name": "Curso de Investimentos", // obrigatório "description": "Do zero ao avançado", "thumbnailUrl": "https://...", "accessType": "MEMBER_ONLY", // default MEMBER_ONLY "dripDays": 0, // liberação gotejada em dias; 0/omitido = imediato "offerType": "MAIN", // MAIN | BONUS | ORDER_BUMP | UPSELL (default MAIN) "salesPageUrl": "https://...", // opcional "requiresPurchase": false // default false } -------------------------------------------------------------------------------- 4.4 MODULE (seção que agrupa aulas) -------------------------------------------------------------------------------- GET /api/v1/apps/{appId}/products/{productId}/modules POST /api/v1/apps/{appId}/products/{productId}/modules PATCH /api/v1/apps/{appId}/products/{productId}/modules/{moduleId} DELETE /api/v1/apps/{appId}/products/{productId}/modules/{moduleId} Sem gate de plano (CRUD ilimitado). Payload POST: { "name": "Módulo 1 — Fundamentos", // obrigatório "description": "Conceitos básicos", // opcional; HTML é removido (vira texto puro) "thumbnailUrl": "https://..." // opcional } -------------------------------------------------------------------------------- 4.5 LESSON (Content / aula) -------------------------------------------------------------------------------- POST /api/v1/apps/{appId}/products/{productId}/contents PATCH /api/v1/apps/{appId}/products/{productId}/contents/{contentId} DELETE /api/v1/apps/{appId}/products/{productId}/contents/{contentId} (A leitura das aulas vem aninhada no GET do product.) Gate: criar aula respeita `maxContentsPerProduct`. Criar uma aula dispara automaticamente a automação `NEW_CONTENT` (notificação aos membros). Payload POST: { "name": "Aula 1 — Como começar", // obrigatório "type": "YOUTUBE", // default VIDEO; ver enum abaixo "url": "https://youtube.com/watch?v=...", // para embeds/links; normalizado "fileUrl": "https://.../arquivo.pdf", // para PDF/AUDIO/VIDEO hospedados "bodyText": "Conteúdo em texto puro", // para type=TEXT "bodyHtml": "

HTML rico

", // sanitizado no servidor "durationSec": 600, // opcional "dripDays": 0, // opcional "moduleId": "clxModule1" // vincula a um módulo DO MESMO produto (senão 404) } Enum de `type`: VIDEO, PDF, AUDIO, TEXT, LINK, YOUTUBE, VIMEO, LOOM, VTURB, PANDA, WISTIA, EMBED Dicas: - VÍDEO de plataforma (YouTube/Vimeo/Loom/VTurb/Panda/Wistia): use o `type` correspondente e ponha o link em `url`. - PDF/AUDIO/arquivo de vídeo próprio: use `fileUrl` com a URL `https://` hospedada. - Texto: use `type: "TEXT"` + `bodyText` (ou `bodyHtml` para formatação). -------------------------------------------------------------------------------- 4.6 INTEGRATION (vínculo product ↔ plataforma de pagamento) -------------------------------------------------------------------------------- GET /api/v1/platforms Catálogo de plataformas suportadas GET /api/v1/apps/{appId}/products/{productId}/integrations POST /api/v1/apps/{appId}/products/{productId}/integrations DELETE /api/v1/apps/{appId}/products/{productId}/integrations/{integrationId} A v1 expõe APENAS o mapeamento produto↔plataforma — nunca segredos de webhook (HMAC) ou credenciais. A configuração de segredos é feita pelo creator humano no dashboard. Isso é deliberado (configurar segredo via API é risco de vazamento). GET /api/v1/platforms retorna o catálogo (ids válidos para o campo `platform`), ex.: `hotmart`, `kiwify`, `greenn`, `hubla`, `cakto`, `eduzz`, `perfectpay`, `ticto`, `custom`, … Payload POST integration: { "platform": "hotmart", // id do catálogo; validado "externalProductId": "12345" // id do produto NA plataforma de origem } O par `(platform, externalProductId)` é único globalmente — se já estiver em uso, retorna 409 `conflict` com mensagem genérica. Esse vínculo é o que permite que um webhook de compra da plataforma libere acesso ao produto automaticamente. -------------------------------------------------------------------------------- 4.7 MEMBER (aluno) -------------------------------------------------------------------------------- GET /api/v1/apps/{appId}/members Listar (paginado, suporta ?search= e ?status=) POST /api/v1/apps/{appId}/members Adicionar membro DELETE /api/v1/apps/{appId}/members/{memberId} Remover (soft-delete → INACTIVE) Gate: adicionar membro respeita `maxMembersPerMonth` / `maxMembersTotal`. Criar membro dispara a automação WELCOME + email de convite. Payload POST: { "email": "aluno@exemplo.com", // obrigatório, formato email, até 254 chars "name": "Maria Silva" // opcional, pode ser null } Email duplicado no mesmo app → 409 `conflict`. Remover é soft-delete (status INACTIVE), idempotente (remover de novo → no-op 200). Nota: esta operação concede acesso ao APP. Acesso a um PRODUTO específico hoje só é concedido via webhook de compra (não há endpoint CRUD para `MemberProductAccess` na v1). ================================================================================ 5. COMPOSE — CRIAR O APP INTEIRO DE UMA VEZ (caminho feliz) ================================================================================ Em vez de encadear 30 chamadas, use o compose: uma única requisição atômica que cria app + products + modules + contents + trails + vínculos de integração. Tudo numa transação: se falhar no meio, NADA é criado (zero órfãos). POST /api/v1/apps/compose Authorization: Bearer ak_live_... Idempotency-Key: // OBRIGATÓRIO — retry não duplica o app inteiro Content-Type: application/json -------------------------------------------------------------------------------- 5.1 Refs locais -------------------------------------------------------------------------------- Você não conhece os IDs reais antes de criar. Use "refs" locais (strings que você inventa) para ligar as coisas dentro do mesmo payload: - `ref` em cada product / module → identifica localmente. - `moduleRef` em um content → liga a aula ao module daquele product. - `productRefs` em uma trail → liga a trilha aos products. O servidor resolve os refs para IDs reais dentro da transação e ecoa o mapeamento na resposta (`{ "ref": "p1", "id": "clx..." }`), para você correlacionar. -------------------------------------------------------------------------------- 5.2 Payload completo de exemplo -------------------------------------------------------------------------------- { "app": { "name": "Finanças Pessoais", "primaryColor": "#6366f1", "theme": "NETFLIX", "language": "pt-BR" }, "products": [ { "ref": "p1", "name": "Curso de Investimentos", "thumbnailUrl": "https://cdn.exemplo.com/curso.png", "offerType": "MAIN", "modules": [ { "ref": "m1", "name": "Módulo 1 — Fundamentos" }, { "ref": "m2", "name": "Módulo 2 — Renda Fixa" } ], "contents": [ { "name": "Aula 1 — Boas-vindas", "type": "YOUTUBE", "url": "https://youtube.com/watch?v=abc", "moduleRef": "m1" }, { "name": "Aula 2 — Juros compostos", "type": "YOUTUBE", "url": "https://youtube.com/watch?v=def", "moduleRef": "m1" }, { "name": "Aula 3 — Tesouro Direto", "type": "VIDEO", "fileUrl": "https://cdn.exemplo.com/aula3.mp4", "moduleRef": "m2" } ], "integrations": [ { "platform": "hotmart", "externalProductId": "12345" } ] } ], "trails": [ { "name": "Trilha do Iniciante", "productRefs": ["p1"] } ], "publish": false } -------------------------------------------------------------------------------- 5.3 Resposta -------------------------------------------------------------------------------- { "data": { "app": { "id": "clxApp...", "slug": "financas-pessoais", "subdomain": "financas-pessoais.seuapp.digital", "published": false }, "products": [ { "ref": "p1", "id": "clxProd...", "modules": [ { "ref": "m1", "id": "clxMod1..." }, { "ref": "m2", "id": "clxMod2..." } ], "contents": [ { "name": "Aula 1 — Boas-vindas", "id": "clxC1..." }, { "name": "Aula 2 — Juros compostos", "id": "clxC2..." }, { "name": "Aula 3 — Tesouro Direto", "id": "clxC3..." } ], "integrations": [ { "platform": "hotmart", "externalProductId": "12345", "id": "clxInt...", "webhookUrl": "https://seuapp.digital/api/webhooks/hotmart/clxInt..." } ] } ], "trails": [ { "name": "Trilha do Iniciante", "id": "clxTrail..." } ] }, "meta": { "request_id": "req_...", "idempotent_replay": false } } -------------------------------------------------------------------------------- 5.4 Regras do compose -------------------------------------------------------------------------------- - Atomicidade total: tudo ou nada (uma transação). - Gates checados ANTES da transação, com falha rápida: `maxApps`, `maxProductsPerApp`, `maxContentsPerProduct`, email verificado. Se estourar quota, retorna `plan_limit_reached` / `plan_feature_required` sem criar nada. - Compose é determinístico (não usa IA, não debita créditos de IA). - Idempotência sobre o app inteiro: retry com a mesma `Idempotency-Key` devolve o app já criado, não cria um segundo. - `publish: true` publica o app ao final (exige `logoUrl` no `app`). Compose é o endpoint que torna a v1 agent-first: 1 chamada = app publicável. ================================================================================ 6. ERROS E COMO REAGIR (resumo operacional para o agente) ================================================================================ 401 unauthorized Chave ausente/inválida/revogada/expirada. Não faça retry com a mesma chave — peça ao creator uma nova chave. 403 plan_feature_required O plano do creator não tem `apiAccess` (precisa de BUSINESS) OU a feature específica (tradução, listagem pública) não está no plano. O corpo indica `upgradeTo: "BUSINESS"`. Não há retry programático — é decisão de upgrade do creator. 403 plan_limit_reached Quota estourada (ex.: `maxApps`, `maxProductsPerApp`). Não faça retry; o limite é do plano. Reduza o escopo ou peça upgrade. 402 insufficient_credits Operação que debita créditos de IA sem saldo. Não aplicável ao compose (que é determinístico). 404 not_found Recurso inexistente OU pertence a outro creator. Trate como "não existe para você". Verifique se está usando IDs retornados pela SUA chave. 409 conflict Slug/subdomínio já em uso (escolha outro `slug`) ou par `(platform, externalProductId)` já vinculado. Mensagem é genérica por segurança. 413 quota_exceeded Storage acima do limite do plano. 422 validation_error Body inválido. Veja `error.fields` para o campo e a razão. Corrija e reenvie (pode reusar a Idempotency-Key SE o body corrigido for a mesma operação lógica — mas como o body mudou, gere uma nova key para evitar `idempotency_key_reuse`). 422 idempotency_key_reuse Você reusou uma Idempotency-Key com um body diferente. Gere uma key nova para a operação nova. 429 rate_limited Faça backoff respeitando o header `Retry-After` (segundos) e tente de novo. 500 internal Erro do servidor. Faça retry com backoff exponencial usando a MESMA Idempotency-Key (idempotência garante que você não duplica se a 1ª tiver, na verdade, persistido). ================================================================================ 7. RECEITA: CONSTRUIR UM APP DO ZERO (passo a passo) ================================================================================ Caminho recomendado (1 chamada): 1. (Opcional) GET /api/v1/platforms para descobrir os ids de plataforma válidos. 2. (Opcional) GET /api/v1/apps/subdomain-available?value= para escolher o slug. 3. POST /api/v1/apps/compose com a árvore completa + Idempotency-Key (UUID). 4. Leia a resposta, capture o `app.id`, os ids de products/contents e as `webhookUrl` das integrations. Entregue as `webhookUrl` ao creator para ele colar nas plataformas de pagamento. 5. Se `publish` não foi true no compose, chame POST /api/v1/apps/{appId}/publish quando o app estiver pronto (lembre do `logoUrl`). Caminho granular (várias chamadas — quando você precisa de controle fino): 1. POST /api/v1/apps → captura appId 2. POST /api/v1/apps/{appId}/products → captura productId 3. POST .../products/{productId}/modules → captura moduleId 4. POST .../products/{productId}/contents (moduleId) → repita por aula 5. POST .../products/{productId}/integrations → captura webhookUrl 6. POST /api/v1/apps/{appId}/trails (productIds) → opcional 7. POST /api/v1/apps/{appId}/members → opcional 8. POST /api/v1/apps/{appId}/publish Em ambos os caminhos: SEMPRE envie Idempotency-Key em mutações e reuse-a em retries. ================================================================================ 8. EXEMPLO COMPLETO (curl) ================================================================================ Checar subdomínio: curl -s "https://seuapp.digital/api/v1/apps/subdomain-available?value=financas-pessoais" \ -H "Authorization: Bearer ak_live_9f3c...a3f9" Compose (app inteiro): curl -s -X POST "https://seuapp.digital/api/v1/apps/compose" \ -H "Authorization: Bearer ak_live_9f3c...a3f9" \ -H "Idempotency-Key: 3f1a9c2e-7b44-4d2a-9e10-2c5b8a1d4f00" \ -H "Content-Type: application/json" \ -d '{ "app": { "name": "Finanças Pessoais", "primaryColor": "#6366f1", "theme": "NETFLIX", "language": "pt-BR" }, "products": [ { "ref": "p1", "name": "Curso de Investimentos", "offerType": "MAIN", "modules": [ { "ref": "m1", "name": "Fundamentos" } ], "contents": [ { "name": "Aula 1", "type": "YOUTUBE", "url": "https://youtube.com/watch?v=abc", "moduleRef": "m1" } ], "integrations": [ { "platform": "hotmart", "externalProductId": "12345" } ] } ], "trails": [ { "name": "Trilha do Iniciante", "productRefs": ["p1"] } ], "publish": false }' Publicar: curl -s -X POST "https://seuapp.digital/api/v1/apps/clxApp.../publish" \ -H "Authorization: Bearer ak_live_9f3c...a3f9" \ -H "Idempotency-Key: 8a21...e0" \ -H "Content-Type: application/json" ================================================================================ 9. LIMITES E NOTAS FINAIS ================================================================================ - Você nunca recebe segredos (webhookSecret, credenciais de gateway, hash de chave). A v1 só devolve o que é necessário para construir o app. - Isolamento multi-tenant é automático e inquebrável: a chave fixa o creator; IDs de outro creator respondem 404. - A v1 não expõe billing, créditos de IA, upload bruto, domínio customizado, push, feed, comunidade, analytics, suporte, notificações, lifecycle, webhooks de entrada nem admin de plataforma. Esses fluxos vivem no dashboard humano. A v1 é a superfície mínima para "agente constrói app". - Documentação de erros: https://docs.seuapp.digital/api/errors Fim. Última atualização: 2026-05-30.