{"openapi":"3.0.3","info":{"title":"Memberfy API","version":"1.0.0","description":"API da plataforma Memberfy — comunidades, conteúdo, cursos, eventos,\nassinaturas e pagamentos.\n\n---\n\n## Começando em 3 passos\n\n**1. Obtenha um token.** Chame `POST /api/auth/login` com email e senha.\nO token vem em `data.token` e vale 7 dias.\n\n**2. Autorize esta página.** Clique no botão **Authorize** 🔓 no topo à direita\ne cole o token (só o token, sem o prefixo `Bearer`). A partir daí o *Try it out*\nenvia o header de autenticação sozinho em todas as chamadas.\n\n**3. Informe a comunidade.** Preencha o campo `X-CommunityId` nos endpoints que\no pedem. Sem ele a maioria das rotas responde `400` — veja abaixo.\n\n---\n\n## Headers\n\n| Header | Quando usar |\n| --- | --- |\n| `Authorization: Bearer <token>` | Em tudo que não seja login, registro ou rota pública. |\n| `X-CommunityId: <uuid>` | **Quase sempre.** A plataforma é community-centric: é este header que define em qual comunidade a operação acontece. |\n| `X-ProfileId: <uuid>` | Opcional. Age em nome de outro perfil (impersonação). Só SuperAdmin, Owner e Moderator. |\n| `Accept-Language` | Opcional. Idioma das mensagens: `en-US`, `pt-BR`, `es`, `fr`, `it`, `de`. Padrão `pt-BR`. |\n\n> ⚠️ **O `X-CommunityId` é a causa nº 1 de erro 400 nesta API.** O id que aparece\n> na URL não substitui o header — a autorização sempre usa o header.\n\n---\n\n## Formato das respostas\n\nToda resposta segue o mesmo envelope. **Sucesso:**\n\n```json\n{\n  \"success\": true,\n  \"message\": \"Login successful.\",\n  \"data\": { },\n  \"pagination\": { \"page\": 1, \"limit\": 20, \"total\": 137, \"totalPages\": 7 }\n}\n```\n\n`pagination` aparece só em listagens. **Erro:**\n\n```json\n{\n  \"success\": false,\n  \"message\": \"Valid email is required\",\n  \"errors\": [ { \"param\": \"email\", \"message\": \"Valid email is required\" } ]\n}\n```\n\nO array `errors` vem sempre, mesmo quando há um único erro — dá para tratar\nvalidação e erro de negócio pelo mesmo caminho.\n\n| Código | Significado |\n| --- | --- |\n| `400` | Validação falhou, ou falta o `X-CommunityId`. |\n| `401` | Token ausente, inválido ou expirado. |\n| `403` | Autenticado, mas sem permissão (papel insuficiente, ou recurso restrito). |\n| `404` | Recurso inexistente ou removido (a API usa soft delete). |\n\n---\n\n## Papéis e visibilidade\n\nHierarquia: **SuperAdmin > Owner > Admin > Moderator > Member**.\nCada vínculo de um membro com uma comunidade é um *Profile*, e é o papel nesse\nperfil que define o que a pessoa pode fazer naquela comunidade.\n\nRecursos (conteúdo, eventos, cursos) têm `visibility`:\n\n- `public` — qualquer um, mesmo sem token\n- `members` — apenas membros da comunidade\n- `plan` — apenas quem tem assinatura ativa\n\nEndpoints públicos aparecem aqui sem o cadeado 🔓. Em vários deles o token é\n*opcional*: mandar o token não é obrigatório, mas amplia o que é retornado.\n\n---\n\n## Paginação\n\nListagens aceitam `page` (começa em 1) e `limit` (padrão 20, máximo 100),\ne devolvem o bloco `pagination` com o total de itens e de páginas.\n\n---\n\n## SDK JavaScript — pronto para embedar\n\nNão escreva cliente à mão. O servidor já publica um SDK gerado a partir deste\nmesmo spec, cobrindo todas as operações:\n\n| Arquivo | Como usar |\n| --- | --- |\n| [`/sdk.js`](/sdk.js) | UMD — `<script src=\"/sdk.js\">` (expõe `Memberfy`), ou `require()` |\n| [`/sdk.mjs`](/sdk.mjs) | ESM — `import { createClient } from '/sdk.mjs'` |\n\n```html\n<script src=\"https://api.memberfy.dev/sdk.js\"></script>\n<script>\n  const api = Memberfy.createClient({ baseUrl: 'https://api.memberfy.dev' });\n\n  const session = await api.auth.login({ email, password });\n  api.setToken(session.token).setCommunity(communityId);\n\n  const events = await api.events.get();          // token e X-CommunityId automáticos\n  const me = await api.auth.getMe();\n</script>\n```\n\nO SDK cuida do `Authorization` e do `X-CommunityId` sozinho, desempacota o envelope\n(devolve `data` direto; listagens devolvem `{ data, pagination }`) e transforma falha\nem exceção `MemberfyError` com `.status`, `.body` e `.errors`. Para receber o corpo\ncru, use `createClient({ raw: true })`.\n\nComo é gerado em runtime a partir das rotas, ele nunca fica defasado em relação ao\nservidor que o serviu — atualizar é rebaixar o arquivo de novo.\n\n### Usando com IA (bolt.new, Claude, Cursor…)\n\nO `/sdk.js` diz **como chamar**; o `/docs.txt` diz **o que enviar**. Para um modelo\ngerar chamadas corretas, entregue o segundo:\n\n| Recurso | Tamanho | Quando usar |\n| --- | --- | --- |\n| [`/docs.txt`](/docs.txt) | ~11k tokens | Referência compacta de tudo |\n| [`/docs.txt?tags=Auth,Events`](/docs.txt?tags=Auth,Events) | ~1k tokens | Só as áreas de que precisa |\n| [`/docs.json`](/docs.json) | ~49k tokens | Spec completo, para codegen |\n\nO `/docs.txt` corta as seções de resposta repetidas (38% do JSON) e mantém o que\nimporta: path, se exige token, e cada parâmetro com tipo e obrigatoriedade.\nO filtro `?tags=` também funciona no `/docs.json`.\n\n> ⚠️ 61 dos 112 endpoints de escrita não declaram os campos do body, porque as rotas\n> não têm validadores `body()` — uploads via multipart, webhooks e alguns POSTs.\n> Para esses, nem o SDK nem o spec sabem os campos.\n\n### Ou gere seu próprio cliente\n\nO spec cru está em [`/docs.json`](/docs.json). Para um cliente tipado em TypeScript:\n\n```bash\nnpx openapi-typescript-codegen --input http://localhost:3000/docs.json --output ./sdk\n```\n\n> O spec completo tem ~180KB. Para ferramentas de IA com limite de contexto,\n> prefira consumir só as tags de que precisa."},"servers":[{"url":"https://api.memberfy.net","description":"Este servidor"},{"url":"http://localhost:3000","description":"Desenvolvimento local"},{"url":"https://api.memberfy.dev","description":"Desenvolvimento via túnel ngrok"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Token JWT obtido em `POST /api/auth/login`. Validade: 7 dias."}},"parameters":{"CommunityIdHeader":{"in":"header","name":"X-CommunityId","schema":{"type":"string","format":"uuid"},"required":false,"description":"ID da comunidade em que a operação acontece. Obrigatório na maioria dos endpoints com escopo de comunidade."},"ProfileIdHeader":{"in":"header","name":"X-ProfileId","schema":{"type":"string","format":"uuid"},"required":false,"description":"Perfil-alvo para impersonação. Apenas SuperAdmin, Owner e Moderator."},"AcceptLanguageHeader":{"in":"header","name":"Accept-Language","schema":{"type":"string","default":"pt-BR","enum":["en-US","pt-BR","es","fr","it","de"]},"required":false,"description":"Idioma preferido para as mensagens da resposta."},"PageQuery":{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Página da listagem (base 1)."},"LimitQuery":{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Quantidade de itens por página."},"ManagedSubscriptionId":{"in":"path","name":"subscriptionId","required":true,"schema":{"type":"string","format":"uuid"}},"ReportInterval":{"in":"query","name":"interval","schema":{"type":"string","enum":["day","week","month"],"default":"month"},"description":"Tamanho de cada período da série. `week` começa na segunda-feira. Rótulo do período:\n`YYYY-MM-DD` (dia ou segunda-feira da semana) ou `YYYY-MM` (mês).\nMáximo de períodos por consulta: 366 dias, 156 semanas ou 120 meses.\n"},"ReportFrom":{"in":"query","name":"from","schema":{"type":"string","format":"date","example":"2026-01-01"},"description":"Primeiro dia (inclusive), no fuso do relatório, alargado para o início do período\n(com `interval=month`, `2026-03-15` vira `2026-03-01`). Padrão: 30 dias, 12 semanas\nou 12 meses antes de `to`.\n"},"ReportTo":{"in":"query","name":"to","schema":{"type":"string","format":"date","example":"2026-10-31"},"description":"Último dia (inclusive), alargado até o fim do período. Padrão hoje."},"ReportTimezone":{"in":"query","name":"timezone","schema":{"type":"string","example":"America/Sao_Paulo"},"description":"Fuso IANA em que os períodos são contados. Padrão: o fuso do país da comunidade\n(o mesmo dos prazos do call4papers). A resposta devolve o fuso usado em `timezone`.\n"},"ReportPage":{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1},"description":"Página da lista detalhada (membros, eventos ou cursos)."},"ReportLimit":{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"description":"Itens por página da lista detalhada."}},"schemas":{"Pagination":{"type":"object","properties":{"page":{"type":"integer","example":1},"limit":{"type":"integer","example":20},"total":{"type":"integer","example":137},"totalPages":{"type":"integer","example":7}}},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string","example":"Operação realizada com sucesso."},"data":{"type":"object","nullable":true},"pagination":{"$ref":"#/components/schemas/Pagination"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"message":{"type":"string","example":"Erro ao processar a requisição."},"errors":{"type":"array","items":{"type":"object","properties":{"param":{"type":"string","nullable":true,"example":"email"},"message":{"type":"string","example":"Valid email is required"}}}}}},"ThemeColorScale":{"type":"object","description":"Escala de cor da comunidade. O tom 500 é a cor base e é obrigatório; os tons omitidos são derivados dele.","required":["500"],"properties":{"50":{"type":"string","example":"#fdf2f8"},"100":{"type":"string","example":"#fce7f3"},"200":{"type":"string","example":"#fbcfe8"},"300":{"type":"string","example":"#f9a8d4"},"400":{"type":"string","example":"#f472b6"},"500":{"type":"string","example":"#ec4899"},"600":{"type":"string","example":"#db2777"},"700":{"type":"string","example":"#be185d"},"800":{"type":"string","example":"#9d174d"},"900":{"type":"string","example":"#831843"},"950":{"type":"string","example":"#500724"}}},"Member":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"fullName":{"type":"string","example":"David"},"email":{"type":"string","format":"email","example":"david@memberfy.net"},"avatarUrl":{"type":"string","nullable":true},"isSuperAdmin":{"type":"boolean","example":false},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"type":"string","format":"date-time","nullable":true}}},"Profile":{"type":"object","description":"Vínculo entre um Member e uma Community, com o papel exercido.","properties":{"id":{"type":"string","format":"uuid"},"memberId":{"type":"string","format":"uuid"},"communityId":{"type":"string","format":"uuid"},"displayName":{"type":"string","nullable":true},"role":{"$ref":"#/components/schemas/Role"},"createdAt":{"type":"string","format":"date-time"}}},"Role":{"type":"string","enum":["OWNER","ADMIN","MODERATOR","MEMBER"],"description":"Hierarquia de papéis: SuperAdmin > Owner > Admin > Moderator > Member."},"Visibility":{"type":"string","enum":["PUBLIC","MEMBERS","SUBSCRIPTION"],"description":"Quem pode ver o recurso: todos, apenas membros, ou apenas assinantes."},"CfpCallInput":{"type":"object","description":"Edital de uma chamada de trabalhos. `speakerFeeCurrency` NÃO entra aqui: a moeda é da comunidade e quem a grava é o servidor — se o cliente enviar, é ignorado.","required":["title"],"properties":{"spaceId":{"type":"string","format":"uuid","description":"Obrigatório na criação."},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","description":"HTML. O resumo da listagem é derivado daqui."},"summary":{"type":"string","nullable":true},"bannerUrl":{"type":"string","nullable":true},"featuredUrl":{"type":"string","nullable":true},"type":{"type":"string","enum":["simple","advanced"],"description":"Preset e contrato de UI, não um segundo motor."},"modality":{"type":"string","enum":["in_person","online","hybrid"]},"submissionOpensAt":{"type":"string","description":"Datetime flutuante, sem fuso: horário de parede no fuso do país da comunidade (o `timeZone` que a chamada devolve). Vale para todas as datas da chamada."},"submissionClosesAt":{"type":"string"},"reviewOpensAt":{"type":"string"},"reviewClosesAt":{"type":"string"},"resultsAnnouncedAt":{"type":"string"},"votingOpensAt":{"type":"string"},"votingClosesAt":{"type":"string"},"allowedFormats":{"type":"array","items":{"type":"string","enum":["talk","lightning_talk","keynote","workshop","tutorial","masterclass","panel","roundtable","case_study","demo","poster","other"]}},"allowedDurations":{"type":"array","items":{"type":"integer"},"example":[20,45,90]},"maxSubmissionsPerSpeaker":{"type":"integer","nullable":true},"minReviewsPerSubmission":{"type":"integer"},"blindReview":{"type":"boolean"},"evaluationMode":{"type":"string","enum":["none","committee","community"]},"voteVisibility":{"type":"string","enum":["hidden","counts","full"]},"whoCanVote":{"type":"string","enum":["owners","staff","members"]},"allowCounterOffer":{"type":"boolean"},"counterOfferTimeoutDays":{"type":"integer","nullable":true},"airTravelCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"groundTransportCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"parkingCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"accommodationCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"mealCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"speakerBenefits":{"type":"array","items":{"type":"string"}},"speakerFeeMode":{"type":"string","enum":["none","fixed","speaker_defined"]},"speakerFeeAmount":{"type":"number","nullable":true},"tracks":{"type":"array","description":"Substitui a lista inteira quando enviada.","items":{"type":"object","required":["name","purpose"],"properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"purpose":{"type":"string"},"description":{"type":"string","nullable":true},"color":{"type":"string","nullable":true}}}},"eventDates":{"type":"array","description":"Substitui a lista inteira quando enviada. Uma linha por dia.","items":{"type":"object","required":["date","startTime","endTime"],"properties":{"date":{"type":"string","example":"2027-11-12"},"startTime":{"type":"string","example":"09:00"},"endTime":{"type":"string","example":"18:00"}}}}}},"CfpCostResponsibility":{"type":"string","enum":["none","organizer","speaker"],"description":"`none` = o custo não se aplica nesta chamada · `organizer` = a organização cobre · `speaker` = é por conta de quem propõe. A diferença entre `none` e `speaker` é lida de forma muito diferente por quem decide se vale a pena submeter."},"CfpSubmissionInput":{"type":"object","description":"Uma proposta. `requestedFeeCurrency` NÃO entra aqui — o servidor grava a moeda da comunidade junto do valor.","required":["title","description","format","durationMinutes"],"properties":{"title":{"type":"string"},"description":{"type":"string","description":"HTML. Campo único e rico — o resumo é derivado."},"trackId":{"type":"string","format":"uuid","nullable":true},"format":{"type":"string","enum":["talk","lightning_talk","keynote","workshop","tutorial","masterclass","panel","roundtable","case_study","demo","poster","other"]},"formatOther":{"type":"string","nullable":true},"durationMinutes":{"type":"integer"},"level":{"type":"string","enum":["beginner","intermediate","advanced"]},"deliveryMode":{"type":"string","enum":["in_person","online","either"],"nullable":true,"description":"Obrigatório quando a chamada é híbrida; ignorado nos outros casos."},"language":{"type":"string","nullable":true},"targetAudience":{"type":"string","nullable":true},"prerequisites":{"type":"string","nullable":true},"resourcesNeeded":{"type":"string","nullable":true},"pitchVideoUrl":{"type":"string","nullable":true},"speakerVideoUrl":{"type":"string","nullable":true},"requestedFeeAmount":{"type":"number","nullable":true,"description":"Só quando o edital está em `speaker_defined`."},"submit":{"type":"boolean","description":"`false` guarda como rascunho. Ausente ou `true`, envia."}}},"CfpNegotiationTerms":{"type":"object","description":"Os termos de uma rodada de negociação. Custos e cachê entram aqui de propósito: o edital declara a política padrão e a contraproposta abre a exceção caso a caso. `feeCurrency` é gravado pelo servidor.","properties":{"format":{"type":"string"},"durationMinutes":{"type":"integer"},"trackId":{"type":"string","format":"uuid"},"trackName":{"type":"string"},"scheduledAt":{"type":"string","description":"Datetime flutuante, sem fuso."},"deliveryMode":{"type":"string","enum":["in_person","online","either"]},"airTravelCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"groundTransportCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"parkingCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"accommodationCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"mealCost":{"$ref":"#/components/schemas/CfpCostResponsibility"},"feeAmount":{"type":"number","nullable":true},"notes":{"type":"string"}}},"ProductInput":{"type":"object","description":"Campos de um produto. Na criação, `title`, `type` e `price` são obrigatórios; na edição tudo é opcional e o que for omitido não muda.\n","properties":{"title":{"type":"string","example":"Plano Pro mensal"},"description":{"type":"string","description":"HTML.","example":"<p>Acesso a todos os cursos, encontros ao vivo e à comunidade.</p>"},"shortDescription":{"type":"string","example":"Cursos, encontros e comunidade"},"internalName":{"type":"string","description":"Nome visto só pela equipe.","example":"pro-mensal-2026"},"bannerUrl":{"type":"string","format":"uri","example":"https://memberfy.net/imagens/plano-pro-banner.png"},"featuredImageUrl":{"type":"string","format":"uri","example":"https://memberfy.net/imagens/plano-pro.png"},"slug":{"type":"string","example":"plano-pro-mensal"},"type":{"type":"string","enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"],"example":"SUBSCRIPTION"},"price":{"type":"number","minimum":0.01,"example":49.9},"billingInterval":{"type":"string","enum":["HOURLY","DAILY","WEEKLY","MONTHLY","YEARLY"],"description":"Só para `SUBSCRIPTION`.","example":"MONTHLY"},"trialDays":{"type":"integer","minimum":0,"maximum":365,"example":7},"requiresCardForTrial":{"type":"boolean","example":true},"allowCancellation":{"type":"boolean","example":true},"commitmentMonths":{"type":"integer","minimum":1,"maximum":36,"nullable":true,"description":"Fidelidade (F-35). Só `SUBSCRIPTION` `MONTHLY`.","example":12},"installments":{"type":"integer","minimum":2,"maximum":24,"description":"Para `INSTALLMENT`.","example":6},"installmentPrice":{"type":"number","minimum":0.01,"example":33},"allowedPaymentMethods":{"type":"array","items":{"type":"string"},"description":"Métodos aceitos no checkout, como `CREDIT_CARD`, `PIX` e `BOLETO`.","example":["CREDIT_CARD","PIX"]},"maxInstallments":{"type":"integer","minimum":1,"maximum":12,"example":3},"installmentInterestPayer":{"type":"string","enum":["BUYER","ORGANIZATION"],"example":"BUYER"},"feePayer":{"type":"string","enum":["ORGANIZATION","BUYER"],"example":"ORGANIZATION"},"accessDuration":{"type":"integer","minimum":1,"description":"Dias de acesso; ausente = vitalício.","example":365},"hasStock":{"type":"boolean","example":false},"stockQuantity":{"type":"integer","minimum":0,"example":100},"isHighlighted":{"type":"boolean","example":false},"directLinkEnabled":{"type":"boolean","example":false},"sortOrder":{"type":"integer","minimum":0,"example":0},"spaceIds":{"type":"array","items":{"type":"string","format":"uuid"},"example":["b1e2c3d4-5f6a-4b7c-8d9e-0f1a2b3c4d5e"]},"subscriptionGroupIds":{"type":"array","items":{"type":"string","format":"uuid"},"example":["f2b4d6e8-0a1c-4e3f-9b5d-7c9e1a3b5d70"]},"prerequisiteGroupIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Obsoleto na escrita (F-37); prefira `addOnProductIds` no plano.","example":[]},"thankYouMessage":{"type":"string","maxLength":5000,"example":"Obrigado! Seu acesso já está liberado."},"redirectUrl":{"type":"string","format":"uri","example":"https://memberfy.net/obrigado"},"metadata":{"type":"object","nullable":true,"example":{}}}},"ProductFeesInput":{"type":"object","required":["paymentMethod"],"properties":{"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER","WALLET_BALANCE"],"example":"CREDIT_CARD"},"installments":{"type":"integer","minimum":1,"maximum":12,"example":3},"countryCode":{"type":"string","minLength":2,"maxLength":2,"example":"BR"}}},"CheckoutInput":{"type":"object","required":["productId","paymentMethod"],"properties":{"productId":{"type":"string","format":"uuid","example":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60"},"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER"],"example":"PIX"},"installments":{"type":"integer","minimum":1,"maximum":12,"description":"Só no cartão de crédito.","example":1},"couponCode":{"type":"string","minLength":3,"maxLength":50,"example":"BEMVINDO10"},"cardToken":{"type":"string","description":"Token do cartão gerado no cliente (Pagar.me). Obrigatório no cartão sem cartão salvo.","example":"card_tok_exemplo123"},"customerData":{"type":"object","properties":{"name":{"type":"string","minLength":3,"maxLength":255,"example":"Maria Silva"},"email":{"type":"string","format":"email","example":"maria.silva@memberfy.net"},"document":{"type":"string","minLength":11,"maxLength":14,"description":"CPF ou CNPJ, só dígitos.","example":"12345678909"}}},"saveDocument":{"type":"boolean","example":true},"addOnProductIds":{"type":"array","maxItems":20,"items":{"type":"string","format":"uuid"},"example":[]}}},"CalculatePriceInput":{"type":"object","required":["productId","paymentMethod"],"properties":{"productId":{"type":"string","format":"uuid","example":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60"},"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER"],"example":"CREDIT_CARD"},"installments":{"type":"integer","minimum":1,"maximum":12,"example":3},"couponCode":{"type":"string","minLength":3,"maxLength":50,"example":"BEMVINDO10"},"addOnProductIds":{"type":"array","maxItems":20,"items":{"type":"string","format":"uuid"},"example":[]}}},"CertificateLayoutField":{"type":"object","description":"Um retângulo de um modelo IMAGE. Geometria em % da arte; `size` e `minSize` em % da altura da página A4, para a mesma caixa dar o mesmo resultado no PDF e nas imagens. `recipientName`, `issuedAt` e `qr` são obrigatórios.\n","required":["key","box"],"properties":{"key":{"type":"string","enum":["recipientName","issuedAt","qr","title","description","workload","subjectTitle","code","signer1","signer2"]},"box":{"type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":100},"y":{"type":"number","minimum":0,"maximum":100},"w":{"type":"number","minimum":0.1,"maximum":100},"h":{"type":"number","minimum":0.1,"maximum":100}}},"font":{"type":"string","enum":["inter","montserrat","lora","playfair-display","eb-garamond","great-vibes","noto-sans"],"description":"Obrigatório fora do `qr`."},"weight":{"type":"integer","enum":[400,700]},"size":{"type":"number","description":"% da altura da página (6 ≈ 36 pt)."},"minSize":{"type":"number","description":"O texto encolhe até aqui antes de quebrar em duas linhas."},"color":{"type":"string","example":"#1f2937"},"align":{"type":"string","enum":["left","center","right"]},"valign":{"type":"string","enum":["top","middle","bottom"]},"uppercase":{"type":"boolean"}}},"CertificateSigner":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"role":{"type":"string","nullable":true},"signatureImageUrl":{"type":"string","nullable":true,"description":"URL devolvida pelo upload de assinatura."}}},"CertificateTemplateInput":{"type":"object","properties":{"name":{"type":"string","description":"Nome interno do modelo."},"slug":{"type":"string","maxLength":60,"example":"conclusao-de-curso","description":"Endereço estável do modelo, para outros módulos (gatilhos de curso e evento) apontarem para ele sem o id. Gerado do nome na criação quando não vier; editável; único na comunidade; minúsculas, números e hífens. Renomear o modelo não muda o slug. Inválido ou já usado: 400 com `param: slug`.\n"},"title":{"type":"string","description":"Título impresso (\"Certificado de conclusão\")."},"description":{"type":"string","nullable":true,"description":"Aceita {nome}, {assunto} e {cargaHoraria} ({curso} e {evento} continuam valendo, como apelidos de {assunto}). Trecho entre colchetes é opcional: `concluiu[ {assunto}], com…` some quando a variável dentro dele está vazia. Fora de colchetes, a oração (entre vírgulas) com uma variável vazia é omitida, exceto a primeira, onde só a variável sai.\n"},"workloadHours":{"type":"number","nullable":true},"language":{"type":"string","example":"pt-BR","description":"Nasce com o idioma da comunidade."},"timezone":{"type":"string","example":"America/Sao_Paulo","description":"Fuso IANA da data impressa."},"signers":{"type":"array","maxItems":2,"items":{"$ref":"#/components/schemas/CertificateSigner"}},"layout":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/CertificateLayoutField"},"description":"Só no tipo IMAGE."}}}},"responses":{"BadRequest":{"description":"Requisição inválida — falha de validação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthorized":{"description":"Token ausente, inválido ou expirado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Autenticado, mas sem permissão para esta operação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Recurso não encontrado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"Conflito com o estado atual do recurso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalError":{"description":"Erro interno do servidor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}}},"security":[{"bearerAuth":[]}],"tags":[{"name":"Auth","description":"Registro, login e recuperação de senha"},{"name":"Members","description":"Dados do membro e métodos de pagamento"},{"name":"Communities","description":"Criação e gestão de comunidades"},{"name":"Profiles","description":"Vínculos membro↔comunidade e papéis (RBAC)"},{"name":"Content","description":"Posts e conteúdo da comunidade"},{"name":"Courses","description":"Cursos, módulos, aulas e matrículas"},{"name":"Events","description":"Eventos e participação"},{"name":"Status","description":"Status curtos estilo Twitter, com reações e comentários"},{"name":"Feed","description":"Feed agregado e recomendações"},{"name":"Sections & Spaces","description":"Organização da comunidade em seções e espaços"},{"name":"Subscriptions","description":"Assinaturas, grupos e planos"},{"name":"Products","description":"Produtos vendáveis"},{"name":"Coupons","description":"Cupons de desconto"},{"name":"Checkout","description":"Fluxo de compra e pagamento"},{"name":"Ledger","description":"Livro-razão financeiro da comunidade"},{"name":"Payouts","description":"Saques e configurações de repasse"},{"name":"Business","description":"Dados cadastrais e fiscais da comunidade"},{"name":"Gamification","description":"Pontos, níveis e conquistas"},{"name":"Activity Logs","description":"Registros de atividade da comunidade: ações da equipe, do assistente de IA (MCP) e dos membros, numa linha do tempo só"},{"name":"Moderation","description":"Denúncias e ações de moderação"},{"name":"Uploads","description":"Upload de mídia para o S3"},{"name":"Gallery","description":"Galeria de mídia da comunidade"},{"name":"Call for Papers","description":"Chamadas de trabalhos: editais, trilhas, propostas, avaliação, voto e negociação"},{"name":"Certificates","description":"Certificados: space, modelos (padrão e arte enviada), emissão em lote, PDF e imagens, revogação e verificação pública por código"},{"name":"Storefront","description":"Loja: space que vende produtos da comunidade, com modo all/selected e as regras de acesso do space"},{"name":"Dashboard","description":"Métricas e indicadores"},{"name":"Reports","description":"Relatórios da comunidade em séries prontas para gráfico: vendas, assinaturas, membros, engajamento e ranking, eventos, cursos, atividade de um membro e painel geral"},{"name":"Import","description":"Importação de dados em massa"},{"name":"Webhooks","description":"Recebimento de eventos de provedores externos"},{"name":"MCP","description":"Servidor MCP (Claude, ChatGPT, Cursor): OAuth 2.1 com escolha de comunidade, consentimento e conexões"},{"name":"Admin","description":"Endpoints administrativos — exigem SuperAdmin"},{"name":"System","description":"Health check e utilidades"}],"paths":{"/api/webhooks/pagarme":{"post":{"tags":["Webhooks"],"summary":"Executa pagarme","description":"Recebe os avisos da Pagar.me (v5). Autenticação por `Authorization: Basic` com o usuário e a senha do webhook configurados no painel, que precisam bater com `PAGARME_WEBHOOK_USER` e `PAGARME_WEBHOOK_PASSWORD`. Sem as variáveis, ou com credenciais ausentes ou erradas, o aviso é registrado em `webhook_logs` e recusado com 401. Aceito, responde 200 na hora e processa em segundo plano. Eventos da v5 tratados: `order.paid`, `order.payment_failed`, `order.canceled`, `charge.refunded`, `charge.partial_canceled`, `charge.chargedback`, `chargeback.received`, `charge.underpaid`, `charge.overpaid` (avisam a equipe, não liberam acesso) e `transfer.paid|failed|canceled` (só registrados). Qualquer outro é gravado como `IGNORED` e respondido com 200, sem nova tentativa.\n","security":[],"parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"description":"Credenciais do webhook ausentes ou erradas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postWebhooksPagarme"}},"/api/webhooks/retry-failed":{"get":{"tags":["Webhooks"],"summary":"Consulta retry failed","description":"Uso interno. Exige SuperAdmin ou o header X-Internal-Key.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getWebhooksRetryFailed"}},"/api/upload/avatar":{"post":{"tags":["Uploads"],"summary":"Cria ou executa avatar","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadAvatar"}},"/api/upload/avatar/member":{"post":{"tags":["Uploads"],"summary":"Cria ou executa member","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadAvatarMember"},"delete":{"tags":["Uploads"],"summary":"Remove member","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteUploadAvatarMember"}},"/api/upload/avatar/profile":{"post":{"tags":["Uploads"],"summary":"Cria ou executa profile","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadAvatarProfile"},"delete":{"tags":["Uploads"],"summary":"Remove profile","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteUploadAvatarProfile"}},"/api/upload/content/image":{"post":{"tags":["Uploads"],"summary":"Cria ou executa image","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadContentImage"}},"/api/upload/content/video":{"post":{"tags":["Uploads"],"summary":"Cria ou executa video","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadContentVideo"}},"/api/upload/community/logo":{"post":{"tags":["Uploads"],"summary":"Cria ou executa logo","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCommunityLogo"}},"/api/upload/community/banner":{"post":{"tags":["Uploads"],"summary":"Cria ou executa banner","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCommunityBanner"}},"/api/upload/community/favicon":{"post":{"tags":["Uploads"],"summary":"Cria ou executa favicon","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCommunityFavicon"}},"/api/upload/community/ogimage":{"post":{"tags":["Uploads"],"summary":"Cria ou executa ogimage","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCommunityOgimage"}},"/api/upload/business/document":{"post":{"tags":["Uploads"],"summary":"Cria ou executa document","description":"Envia o documento de identidade ou o comprovante de endereço do KYC da\ncomunidade do `X-CommunityId`. Só owner ou admin dessa comunidade (ou\nSuperAdmin). O `communityId` do corpo é opcional; se vier, precisa ser o\ndo header, senão 403. O arquivo é gravado privado no S3: a `url` da\nresposta é assinada e expira em 15 minutos.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["document","documentType"],"properties":{"document":{"type":"string","format":"binary"},"documentType":{"type":"string","enum":["identity","address-proof"]},"communityId":{"type":"string","format":"uuid","description":"Opcional; precisa ser igual ao X-CommunityId"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadBusinessDocument"}},"/api/upload/partner/document":{"post":{"tags":["Uploads"],"summary":"Cria ou executa document","description":"Envia o documento de identidade ou o comprovante de endereço de um sócio\nadministrador. Só owner ou admin da comunidade do `X-CommunityId` (ou\nSuperAdmin), e o sócio precisa pertencer ao cadastro dessa comunidade,\nsenão 404. O arquivo é gravado privado no S3: a `url` da resposta é\nassinada e expira em 15 minutos.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["document","partnerId","documentType"],"properties":{"document":{"type":"string","format":"binary"},"partnerId":{"type":"string","format":"uuid"},"documentType":{"type":"string","enum":["identity","address-proof"]}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadPartnerDocument"}},"/api/upload/event/{eventId}/banner":{"post":{"tags":["Uploads"],"summary":"Cria ou executa banner","parameters":[{"in":"path","name":"eventId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadEventByEventIdBanner"}},"/api/upload/event/{eventId}/featured":{"post":{"tags":["Uploads"],"summary":"Cria ou executa featured","parameters":[{"in":"path","name":"eventId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadEventByEventIdFeatured"}},"/api/upload/call4papers/{callId}/banner":{"post":{"tags":["Uploads"],"summary":"Envia o banner (16:9) de uma chamada de trabalhos","parameters":[{"in":"path","name":"callId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"banner":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCall4papersByCallIdBanner"}},"/api/upload/call4papers/{callId}/featured":{"post":{"tags":["Uploads"],"summary":"Envia a imagem de destaque (1:1) de uma chamada de trabalhos","parameters":[{"in":"path","name":"callId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"featured":{"type":"string","format":"binary"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCall4papersByCallIdFeatured"}},"/api/upload/product/{productId}/banner":{"post":{"tags":["Uploads"],"summary":"Cria ou executa banner","parameters":[{"in":"path","name":"productId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadProductByProductIdBanner"}},"/api/upload/product/{productId}/featured":{"post":{"tags":["Uploads"],"summary":"Cria ou executa featured","parameters":[{"in":"path","name":"productId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadProductByProductIdFeatured"}},"/api/upload/gallery/images":{"post":{"tags":["Uploads"],"summary":"Cria ou executa images","description":"Envia imagens para um space de galeria da comunidade do `X-CommunityId`\n(space de outra comunidade: 404). Respeita o `canCreate` do space:\n`staff` aceita owner, admin e moderator; `admins` aceita owner e admin;\nfora da regra, 403. SuperAdmin sempre passa.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID is required"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadGalleryImages"}},"/api/subscription-groups":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionGroups","tags":["Subscriptions"],"summary":"Lista subscriptions","description":"Lista os grupos de assinatura ativos da comunidade, com produtos e contagem de assinaturas ativas. Cada grupo traz slug, o endereço do plano nos links públicos (/pricing/<slug>/...), e addOnProductIds, a lista de adicionais do plano (F-37). Exige autenticação. A comunidade é a do X-CommunityId. Só devolve grupos dessa comunidade.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionGroups","tags":["Subscriptions"],"summary":"Cria ou executa subscriptions","description":"Cria um grupo de assinatura. Exige owner, admin ou SuperAdmin. A comunidade é a do X-CommunityId. productIds precisam ser produtos não excluídos dessa comunidade. slug é o endereço do plano nos links públicos (/pricing/<slug>/...): sem ele, é gerado do nome (sem acento, minúsculo, hífens; -2, -3 em caso de colisão). slug enviado e já usado por outro plano da comunidade, ativo ou não, responde 400 com param slug. Responde 201.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Plano Pro","slug":"plano-pro","description":"Cursos, encontros ao vivo e comunidade.","sortOrder":0,"productIds":["d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60"],"addOnProductIds":[]},"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name is required"},"slug":{"type":"string","maxLength":60,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Endereço do plano nos links públicos. Opcional; sem ele, é gerado do nome. Único na comunidade."},"description":{"type":"string"},"sortOrder":{"type":"integer"},"metadata":{"type":"object"},"productIds":{"type":"array","description":"productIds must be an array"},"productIds.*":{"type":"string","format":"uuid","description":"Each productId must be a valid UUID"},"addOnProductIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Adicionais do plano (F-37): produtos que podem ser somados a ele. Grava em product_prerequisites, a mesma relação do prerequisiteGroupIds do produto, vista do plano. Omitido mantém a lista; [] limpa. Cada produto precisa ser desta comunidade, não excluído e não ser opção de nenhum plano, senão 400 com param addOnProductIds. Só os SUBSCRIPTION MONTHLY são vendidos junto com o plano; os outros valem como pré-requisito de compra."}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscription-groups/{id}":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionGroupsById","tags":["Subscriptions"],"summary":"Detalha subscriptions por id","description":"Devolve o grupo com slug, produtos e addOnProductIds (a lista de adicionais do plano, F-37). Exige autenticação. A comunidade é a do X-CommunityId. Grupo de outra comunidade responde 404.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"put":{"operationId":"putCommunitiesByCommunityIdSubscriptionGroupsById","tags":["Subscriptions"],"summary":"Atualiza subscriptions","description":"Exige owner, admin ou SuperAdmin. A comunidade é a do X-CommunityId. Grupo de outra comunidade responde 404. productIds, quando enviado, substitui a lista inteira. slug só muda quando enviado: renomear o plano não altera o endereço. slug já usado por outro plano da comunidade, ativo ou não, responde 400 com param slug.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Plano Pro","description":"Cursos, encontros ao vivo e comunidade.","isActive":true},"schema":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string","maxLength":60,"pattern":"^[a-z0-9]+(?:-[a-z0-9]+)*$","description":"Endereço do plano nos links públicos. Só muda quando enviado; renomear o plano não o altera. Único na comunidade."},"description":{"type":"string"},"sortOrder":{"type":"integer"},"metadata":{"type":"object"},"isActive":{"type":"boolean"},"productIds":{"type":"array","description":"productIds must be an array"},"productIds.*":{"type":"string","format":"uuid","description":"Each productId must be a valid UUID"},"addOnProductIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Adicionais do plano (F-37). Substitui a lista inteira do plano; omitido mantém, [] limpa. Mesmas recusas do POST (400, param addOnProductIds). Tirar da lista um produto que tem assinatura viva de quem assina este plano responde 409 (param addOnProductIds): a cascata da F-33 a cancelaria na hora. Encerre essas assinaturas antes, ou desative a venda do produto."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCommunitiesByCommunityIdSubscriptionGroupsById","tags":["Subscriptions"],"summary":"Remove subscriptions","description":"Desativa o grupo (isActive false). Exige owner, admin ou SuperAdmin. A comunidade é a do X-CommunityId. Grupo de outra comunidade responde 404. Recusa com 400 se o grupo ainda tiver produtos não excluídos; vínculos com produtos já excluídos não contam.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscription-groups/{id}/products":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionGroupsByIdProducts","tags":["Subscriptions"],"summary":"Lista ou consulta products","description":"Produtos não excluídos do grupo. Exige autenticação. A comunidade é a do X-CommunityId. Grupo de outra comunidade responde 404.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscription-groups/reorder":{"patch":{"operationId":"patchCommunitiesByCommunityIdSubscriptionGroupsReorder","tags":["Subscriptions"],"summary":"Atualiza parcialmente reorder","description":"Exige owner, admin ou SuperAdmin. A comunidade é a do X-CommunityId. Todos os groupIds precisam ser dessa comunidade, senão 400.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"groupIds":["f2b4d6e8-0a1c-4e3f-9b5d-7c9e1a3b5d70","0c2e4a6b-8d1f-4b3c-a5e7-9f1b3d5c7e92"]},"schema":{"type":"object","required":["groupIds","groupIds.*"],"properties":{"groupIds":{"type":"array","description":"groupIds must be a non-empty array"},"groupIds.*":{"type":"string","format":"uuid","description":"Each groupId must be a valid UUID"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptions","tags":["Subscriptions"],"summary":"Lista as assinaturas da comunidade (gestão pela equipe)","description":"F-45. Exige owner, admin ou finance da comunidade do `X-CommunityId`.\nMais novas primeiro. Cada item: `member` (nome, e-mail), `plan` e `product` (opção),\n`status` e `statusLabel` (`CANCELING` quando vai encerrar no fim do período), `source`\n(`CHECKOUT` ou `MANUAL`), `isComplimentary` e `complimentaryUntil`, valor\n(`billingAmount`, `regularAmount`, `discountPercent`, `discountEndsAt`), `addOns`\ncobrados junto, `nextChargeTotal`, `paymentMethod`, `pendingRenewal` (PIX/boleto em\naberto), `commitmentEndsAt`, `nextBillingDate` e o período. Adicionais cobrados com o\nplano não aparecem como item próprio. Nunca traz custo de provedor.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"status","schema":{"type":"string","enum":["ACTIVE","TRIALING","PAST_DUE","PAUSED","CANCELING","CANCELED","EXPIRED","COMPLIMENTARY"]}},{"in":"query","name":"productId","schema":{"type":"string","format":"uuid"},"description":"Opção de cobrança"},{"in":"query","name":"subscriptionGroupId","schema":{"type":"string","format":"uuid"},"description":"Plano"},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"},"description":"Início da assinatura a partir de"},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"},"description":"Início da assinatura até"},{"in":"query","name":"search","schema":{"type":"string"},"description":"Nome ou e-mail do membro"},{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Lista paginada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdSubscriptions","tags":["Subscriptions"],"summary":"Cria uma assinatura manual (cortesia ou cobrança futura)","description":"F-45. Owner, admin ou finance; auditado.\n`mode = COMPLIMENTARY`: cortesia, sem cobrança e sem lançamento no extrato, até\n`complimentaryUntil` (encerra sozinha) ou sem fim.\n`mode = FUTURE_CHARGE`: grátis até `chargeStartsAt` e cobrada a partir dessa data como\nqualquer assinatura — por PIX/boleto (`paymentMethod`; a cobrança sai alguns dias antes\ne vai por e-mail) ou pelo cartão salvo do membro (`CREDIT_CARD`). O membro pode receber\num link para pagar ou cadastrar cartão (`POST .../payment-link`).\nMembro que já assina a mesma opção: 409. Membro ou opção de outra comunidade: 404.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"profileId":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","productId":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60","mode":"COMPLIMENTARY","complimentaryUntil":"2026-12-31T23:59:59.000Z","note":"Cortesia para quem palestrou no encontro de novembro."},"schema":{"type":"object","required":["profileId","productId","mode"],"properties":{"profileId":{"type":"string","format":"uuid"},"productId":{"type":"string","format":"uuid","description":"Opção de cobrança (produto SUBSCRIPTION)"},"mode":{"type":"string","enum":["COMPLIMENTARY","FUTURE_CHARGE"]},"complimentaryUntil":{"type":"string","format":"date-time","nullable":true},"chargeStartsAt":{"type":"string","format":"date-time","description":"Obrigatório em FUTURE_CHARGE"},"paymentMethod":{"type":"string","enum":["PIX","BOLETO","CREDIT_CARD"],"description":"FUTURE_CHARGE; padrão PIX"},"note":{"type":"string","maxLength":500}}}}}},"responses":{"201":{"description":"Assinatura criada (formato do detalhe).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"O membro já assina esta opção."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/export.csv":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionsExportCsv","tags":["Subscriptions"],"summary":"Exporta as assinaturas da comunidade em CSV","description":"F-45. Owner, admin ou finance. Mesmos filtros da listagem, sem paginação (até 5.000\nlinhas). Colunas: id, member, email, plan, option, status, billingAmount, currency,\ndiscountPercent, addOns, paymentMethod, nextBillingDate, currentPeriodEnd,\ncommitmentEndsAt, source, complimentaryUntil, startDate, canceledAt. UTF-8 com BOM;\ncélula que começaria uma fórmula vem com `'` na frente.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"status","schema":{"type":"string"}},{"in":"query","name":"productId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"subscriptionGroupId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"}},{"in":"query","name":"search","schema":{"type":"string"}}],"responses":{"200":{"description":"CSV, uma linha por assinatura.","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionsBySubscriptionId","tags":["Subscriptions"],"summary":"Detalhe de uma assinatura (gestão pela equipe)","description":"F-45. Owner, admin ou finance. Os campos da listagem, mais `charges` (histórico de\ncobranças: data, período, valor, status, pago/falhou, motivo, forma de pagamento,\nparcelas), `events` (linha do tempo, mais nova primeiro: `CREATED`, `CHARGE_PAID`,\n`CHARGE_FAILED`, `CANCELED`, `ENDED` e `TEAM_ACTION` com `action`, `actor`, `before` e\n`after`) e `addOnSubscriptions`. Assinatura de outra comunidade: 404.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Detalhe.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/cancel":{"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionsBySubscriptionIdCancel","tags":["Subscriptions"],"summary":"Cancela agora ou no fim do período (equipe)","description":"F-45. Owner, admin ou finance; auditado. `immediate: true` encerra agora; sem ele, a\nassinatura fica ativa até o fim do período pago e não renova. A equipe passa por cima\ndo contrato (F-35). Já encerrada, ou já marcada para encerrar: 409. A resposta é o\ndetalhe depois da ação.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"example":{"immediate":false,"reason":"Pedido do membro por e-mail."},"schema":{"type":"object","properties":{"immediate":{"type":"boolean"},"reason":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A assinatura não aceita a ação no estado atual."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/reactivate":{"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionsBySubscriptionIdReactivate","tags":["Subscriptions"],"summary":"Reativa uma assinatura marcada para encerrar (equipe)","description":"F-45. Owner, admin ou finance; auditado. Só antes do fim do período; a cobrança volta a\npartir dele. Uma cortesia reativada vira assinatura comum a partir do fim dela. Não\nmarcada para encerrar, ou período já acabou: 409.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Não está marcada para encerrar","ou o período acabou.":null},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/discount":{"put":{"operationId":"putCommunitiesByCommunityIdSubscriptionsBySubscriptionIdDiscount","tags":["Subscriptions"],"summary":"Aplica um desconto percentual (equipe)","description":"F-45. Owner, admin ou finance; auditado. `percent` (mais de 0 e menos de 100, até 2\ncasas) vale a partir da próxima cobrança, até `endsAt` (ou enquanto durar). Usa os\ncampos que toda renovação já aplica; o valor cheio fica em `regularAmount`. Cupom por\ncódigo não é aplicado por aqui.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"percent":20,"endsAt":"2027-03-31T23:59:59.000Z"},"schema":{"type":"object","required":["percent"],"properties":{"percent":{"type":"number"},"endsAt":{"type":"string","format":"date-time","nullable":true}}}}}},"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Assinatura encerrada."},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCommunitiesByCommunityIdSubscriptionsBySubscriptionIdDiscount","tags":["Subscriptions"],"summary":"Remove o desconto (equipe)","description":"F-45. Owner, admin ou finance; auditado. A próxima cobrança volta ao valor cheio. Sem desconto, 409.","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Sem desconto."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/add-ons":{"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionsBySubscriptionIdAddOns","tags":["Subscriptions"],"summary":"Adiciona um adicional ao plano, sem cobrar agora (equipe)","description":"F-45. Owner, admin ou finance; auditado. `productId` precisa ser um adicional da lista\ndo plano, vendido junto (F-33/F-37), que o membro ainda não tenha. O resto do período\natual sai sem custo; a partir da próxima renovação o adicional é cobrado junto com o\nplano. Nada é cobrado agora. A resposta traz `addOnSubscriptionId`.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"productId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e"},"schema":{"type":"object","required":["productId"],"properties":{"productId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A assinatura não está ativa."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/add-ons/{addOnSubscriptionId}":{"delete":{"operationId":"deleteCommunitiesByCommunityIdSubscriptionsBySubscriptionIdAddOnsByAddOnSubscriptionId","tags":["Subscriptions"],"summary":"Remove um adicional do plano (equipe)","description":"F-45. Owner, admin ou finance; auditado. O adicional encerra no fim do período (padrão)\nou agora (`immediate: true` no corpo). Adicional que não é cobrado com esta\nassinatura: 404.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"in":"path","name":"addOnSubscriptionId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"O adicional já encerrou."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/extend":{"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionsBySubscriptionIdExtend","tags":["Subscriptions"],"summary":"Estende o período sem cobrar (equipe)","description":"F-45. Owner, admin ou finance; auditado. Concede tempo: o fim do período (e a próxima\ncobrança, quando há) avança `days` dias ou vai até `until` (um dos dois). Os adicionais\ncobrados com o plano acompanham. Data que não seja depois do fim atual: 400.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"days":30},"schema":{"type":"object","properties":{"days":{"type":"integer","minimum":1,"maximum":3650},"until":{"type":"string","format":"date-time"}}}}}},"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Assinatura encerrada."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/manage/subscriptions/{subscriptionId}/payment-link":{"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionsBySubscriptionIdPaymentLink","tags":["Subscriptions"],"summary":"Envia ao membro o link para pagar ou cadastrar cartão (equipe)","description":"F-45. Owner, admin ou finance; auditado. E-mail ao membro com o link\n`https://<app da comunidade>/billing?subscription=<id>`, onde ele paga (\"Pagar agora\",\nPIX/boleto) ou cadastra um cartão. Não cobra nada. Cada envio é um e-mail.\n","parameters":[{"$ref":"#/components/parameters/ManagedSubscriptionId"},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Detalhe depois da ação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Assinatura encerrada."},"422":{"description":"O e-mail não pôde ser enfileirado (membro sem e-mail)."},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscriptions":{"get":{"tags":["Subscriptions"],"summary":"Lista subscriptions","description":"Cada assinatura traz `commitmentEndsAt` (fim do contrato vigente, ou `null` sem contrato) e `cancelEffectiveAt` (quando um cancelamento agendado de fato encerra a assinatura, ou `null`), e `product.commitmentMonths` (F-35). F-37: `billedWithId` é a assinatura do plano com que um adicional é cobrado (o adicional não traz os campos abaixo); nas outras, `billedWithId = null`, `addOns` (os adicionais cobrados junto: `id`, `productId`, `title`, `status`, `billingAmount`, `canceledAt`, `renewsWithPlan`) e `nextChargeTotal` (o plano mais os adicionais que renovam com ele, sem a taxa paga pelo comprador; `null` sem próxima cobrança). `pendingRenewal`: a cobrança de renovação em aberto que a assinatura espera — o PIX ou boleto gerado antes do vencimento (F-38), o de \"Pagar agora\", ou um cartão em análise — ou `null`. Forma: `{ purchaseId, paymentMethod, amount, dueDate, pixCode, qrCode, boletoUrl, boletoBarcode }`. `amount` é o total do pedido (plano e adicionais), o que o membro paga. `pixCode` (copia e cola), `qrCode` (URL da imagem), `boletoUrl`, `boletoBarcode` (linha digitável) e `dueDate` (validade do PIX ou vencimento do boleto) vêm do pedido na Pagar.me e são `null` no cartão ou quando o provedor não responde. Sempre `null` num adicional ligado: a cobrança aparece no plano.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSubscriptions"}},"/api/subscriptions/{id}":{"get":{"tags":["Subscriptions"],"summary":"Detalha subscriptions por id","description":"Traz `commitmentEndsAt`, `cancelEffectiveAt` e `product.commitmentMonths` (F-35), e os campos da F-37: `billedWithId`; e, quando não é adicional de outra, `addOns` e `nextChargeTotal` (ver `GET /api/subscriptions`). Traz também `pendingRenewal` (ver `GET /api/subscriptions`).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSubscriptionsById"}},"/api/subscriptions/{id}/billings":{"get":{"tags":["Subscriptions"],"summary":"Lista ou consulta billings","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSubscriptionsByIdBillings"}},"/api/subscriptions/{id}/cancel":{"post":{"tags":["Subscriptions"],"summary":"Cria ou executa cancel","description":"Corpo: `immediate` (boolean, opcional) e `cancelReason` (texto, opcional). O assinante cancela a própria assinatura; owner e admin da comunidade do `X-CommunityId` (e SuperAdmin) cancelam qualquer assinatura dela. **Contrato (F-35):** quando o assinante cancela uma assinatura `ACTIVE` antes de `commitmentEndsAt`, o cancelamento fica agendado para o fim do contrato, mesmo com `immediate: true`: `status` continua `ACTIVE`, `nextBillingDate` continua preenchido e as cobranças seguem até lá. Owner e admin não ficam presos ao contrato: com `immediate: true` encerram na hora, inclusive um cancelamento já agendado (é o único caso em que uma assinatura com `canceledAt` aceita novo cancelamento). **Anual (F-36):** o assinante que cancela uma assinatura `YEARLY` fica com o acesso até o fim do ano pago, mesmo com `immediate: true`, e ela não renova; não há reembolso. Owner e admin continuam podendo encerrar na hora. **`allowCancellation: false`** no produto: o assinante recebe 400 (`cancellationNotAllowed`); owner e admin podem cancelar. A resposta traz, além dos campos de antes, `commitmentEndsAt` (fim do contrato vigente, ou `null`) e `cancelEffectiveAt` (quando a assinatura de fato termina: agora, no fim do período, ou no fim do período em que o contrato acaba). Um cancelamento no fim do período é encerrado pelo job horário quando o período acaba (FIN-43): `status` vira `CANCELED` e o acesso termina.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cancelReason":{"type":"string","minLength":3,"maxLength":500,"example":"Não estou conseguindo acompanhar os encontros."},"immediate":{"type":"boolean","description":"`true` encerra agora; ausente ou `false`, ao fim do período pago.","example":false}}},"example":{"cancelReason":"Não estou conseguindo acompanhar os encontros.","immediate":false}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdCancel"}},"/api/subscriptions/{id}/pause":{"post":{"tags":["Subscriptions"],"summary":"Cria ou executa pause","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdPause"}},"/api/subscriptions/{id}/resume":{"post":{"tags":["Subscriptions"],"summary":"Cria ou executa resume","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdResume"}},"/api/subscriptions/{id}/reactivate":{"post":{"tags":["Subscriptions"],"summary":"Cria ou executa reactivate","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdReactivate"}},"/api/subscriptions/{id}/change-tier/quote":{"post":{"tags":["Subscriptions"],"summary":"Prévia da troca de plano","description":"FIN-68. Sem efeito: diz o que `POST /change-tier` faria com o mesmo corpo. `:id` é a assinatura do plano, do próprio membro, na comunidade do X-CommunityId; de outra pessoa ou de outra comunidade responde 404. As recusas são as mesmas de `change-tier`.\n`changeType`: `UPGRADE` (opção mais cara na mesma periodicidade), `DOWNGRADE`, `SAME_PRICE` ou `INTERVAL_CHANGE` (mensal ↔ anual). `mode`: `IMMEDIATE` só para `UPGRADE` com `immediate` ausente ou `true` e sem adicional que a opção nova deixe de oferecer; o resto é `SCHEDULED`, para `effectiveDate` (o fim do período pago), e `scheduledReason` diz por quê (`DOWNGRADE`, `SAME_PRICE`, `INTERVAL_CHANGE`, `ADD_ONS_END` ou `REQUESTED`).\nNo `IMMEDIATE`: `prorataAmount` é a diferença de preço proporcional aos `remainingDays` de `periodDays`; com menos de 3 dias ou menos de R$ 10, `floorApplied = true` e `amountDueNow = 0` (troca na hora, sem cobrança). `amountToCharge` soma a taxa da plataforma quando o comprador a paga (`feePayer = BUYER`). A cobrança é no cartão salvo (`cardRequired`, `hasSavedCard`), em até `maxInstallments` parcelas (meses restantes no anual; 1 no mensal).\nSempre: `newPrice` (preço por período da opção nova), `nextChargeDate` e `nextChargeTotal` (a primeira cobrança no preço novo, com os adicionais que continuam); `addOns` (cada adicional cobrado com o plano: `outcome = KEPT` continua, no valor da periodicidade nova, `newAmount`; `ENDS` termina com a troca); `contract` (`commitmentEndsAt` depois da troca; `carriedOver = true` quando o contrato atual continua valendo); `couponEnds` (o cupom da assinatura deixa de valer na troca); `replacesScheduledChange` (a troca agendada que esta substituiria, ou `null`).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"newProductId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","immediate":true},"schema":{"type":"object","required":["newProductId"],"properties":{"newProductId":{"type":"string","format":"uuid","description":"A opção de plano de destino"},"immediate":{"type":"boolean","description":"Ausente vale `true` aqui: a prévia do upgrade na hora"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Operação realizada com sucesso","data":{"subscriptionId":"4f1c9a2e-8b3d-4e6f-9a1b-2c3d4e5f6a7b","changeType":"UPGRADE","mode":"IMMEDIATE","scheduledReason":null,"effectiveDate":"2026-10-07T15:00:00.000Z","currency":"BRL","currentProduct":{"id":"0b7e9c1a-2d3f-4a5b-8c6d-7e8f9a0b1c2d","title":"Starter · Mensal","price":"49.90","billingInterval":"MONTHLY"},"newProduct":{"id":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","title":"Growth · Mensal","price":"99.90","billingInterval":"MONTHLY","commitmentMonths":null},"currentAmount":"49.90","newPrice":"99.90","feePayer":"ORGANIZATION","periodDays":30,"remainingDays":18,"prorataAmount":"30.00","floorApplied":false,"amountDueNow":"30.00","amountToCharge":"30.00","maxInstallments":1,"cardRequired":true,"hasSavedCard":true,"nextChargeDate":"2026-10-25T15:00:00.000Z","nextChargeTotal":"99.90","addOns":[],"contract":{"currentCommitmentEndsAt":null,"commitmentEndsAt":null,"carriedOver":false},"couponEnds":false,"replacesScheduledChange":null}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdChangeTierQuote"}},"/api/subscriptions/{id}/change-tier":{"post":{"tags":["Subscriptions"],"summary":"Troca a opção de plano da assinatura","description":"FIN-68. Move a assinatura do plano para outra opção de plano à venda na mesma comunidade (de outro plano também, ex.: Starter → Growth). Só o próprio assinante; assinatura de outra pessoa ou de outra comunidade responde 404. A assinatura continua a mesma (mesmo `id`, histórico, período e adicionais); muda `productId`, `billingAmount` e `billingInterval`. Veja a prévia em `POST /change-tier/quote`.\n**Upgrade** (opção mais cara na mesma periodicidade, com `immediate: true`): vale na hora e cobra agora, no cartão salvo do membro (o padrão, ou `paymentMethodId`), a diferença proporcional aos dias que faltam no período; a próxima renovação já vem no preço novo. Abaixo do piso (menos de 3 dias ou de R$ 10) troca sem cobrar. A cobrança é uma venda como as outras: taxa da plataforma e `feePayer` da opção nova, parcelas até o `maxInstallments` da prévia (`installments`). Se o cartão for recusado ou a cobrança não for confirmada na hora, **nada muda**: 402 (recusa) ou 502 (provedor fora do ar). Sem cartão salvo: 400 `param = paymentMethodId`.\n**Agendada** (opção mais barata ou de mesmo preço, outra periodicidade — mensal ↔ anual, sem proporcional entre períodos —, upgrade com `immediate: false`, ou upgrade que tiraria um adicional): nada é cobrado agora. Na renovação de `effectiveDate` a assinatura passa para a opção nova e a cobrança já é no preço e na periodicidade dela. Uma nova troca agendada substitui a anterior; dá para desfazer com `DELETE /scheduled-change`.\n**Adicionais** (F-37): os que a opção nova oferece continuam (no valor da periodicidade nova); os que ela não oferece terminam na troca. **Contrato** (F-35): o contrato em vigor continua até o fim; sem contrato, uma opção nova com contrato começa o dela na troca. **Cupom**: deixa de valer na troca.\nRecusas, todas antes de qualquer cobrança: 400 `param = id` quando a assinatura não está `ACTIVE`, tem cancelamento agendado, é cortesia ou é um adicional ligado a um plano; 400 `param = newProductId` para a mesma opção, opção que não é de plano, fora de venda, em outra moeda, ou já assinada; 404 `newProductId` de outra comunidade ou inexistente; 403 `newProductId` para um adicional sem o plano que ele exige; 403 `param = id` quando a comunidade não tem informações comerciais aprovadas (só no upgrade cobrado); 409 `param = id` enquanto há uma cobrança de renovação do próximo período em aberto (PIX ou boleto já gerado, ou cartão em análise). O texto da recusa vem em `errors[0].message`.\nResponde 200. `data`: `mode` (`IMMEDIATE` ou `SCHEDULED`), `changeType`, `scheduledReason`, `effectiveDate`, `currentProduct`, `newProduct`, `subscription` (como ficou), `scheduledChange` (o mesmo objeto de `GET /scheduled-change`, ou `null`), `charge` (`purchaseId`, `orderId`, `amount`, `currency`, `installments`, `feeBreakdown` só com a taxa da plataforma; `null` sem cobrança), `addOns`, `contract`, `couponEnds`.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["newProductId"],"properties":{"newProductId":{"type":"string","format":"uuid","example":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e"},"immediate":{"type":"boolean","description":"`true` aplica um upgrade agora, com a cobrança proporcional; ausente ou `false`, agenda para o fim do período. Downgrade e troca de periodicidade são sempre agendados.","example":true},"paymentMethodId":{"type":"string","format":"uuid","description":"Cartão salvo do membro (/payment-methods) para o upgrade cobrado agora. Ausente: o cartão padrão."},"installments":{"type":"integer","minimum":1,"maximum":12,"description":"Parcelas do proporcional, até o `maxInstallments` da prévia."}}},"example":{"newProductId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","immediate":true}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Plano alterado para Growth · Mensal.","data":{"mode":"IMMEDIATE","changeType":"UPGRADE","scheduledReason":null,"effectiveDate":"2026-10-07T15:00:00.000Z","currentProduct":{"id":"0b7e9c1a-2d3f-4a5b-8c6d-7e8f9a0b1c2d","title":"Starter · Mensal","price":"49.90","billingInterval":"MONTHLY"},"newProduct":{"id":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","title":"Growth · Mensal","price":"99.90","billingInterval":"MONTHLY","commitmentMonths":null},"subscription":{"id":"4f1c9a2e-8b3d-4e6f-9a1b-2c3d4e5f6a7b","status":"ACTIVE","productId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","billingAmount":"99.90","billingInterval":"MONTHLY","currency":"BRL","nextBillingDate":"2026-10-25T15:00:00.000Z","commitmentEndsAt":null},"scheduledChange":null,"charge":{"purchaseId":"7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d","orderId":"or_AbCdEf123","amount":"30.00","currency":"BRL","installments":1},"addOns":[],"contract":{"currentCommitmentEndsAt":null,"commitmentEndsAt":null,"carriedOver":false},"couponEnds":false}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"},"502":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdChangeTier"}},"/api/subscriptions/{id}/scheduled-change":{"get":{"tags":["Subscriptions"],"summary":"Consulta a troca de plano agendada","description":"FIN-68. A troca de plano que espera o fim do período. O assinante, ou owner/admin da comunidade do X-CommunityId (e SuperAdmin); assinatura de outra pessoa ou de outra comunidade responde 404. Sem troca agendada, 404 (`noScheduledChange`). `data`: `changeType` (`UPGRADE`, `DOWNGRADE`, `SAME_PRICE` ou `INTERVAL_CHANGE`), `currentProduct` e `newProduct` (`id`, `title`, `price`, `billingInterval`), `effectiveDate` (quando a troca vale: a renovação em que a cobrança já vem no preço novo), `scheduledAt` e `scheduledById` (o perfil que agendou). O mesmo objeto vem em `scheduledChange` de `GET /api/subscriptions`, `GET /api/subscriptions/{id}` e `GET /api/subscriptions/me` (ou `null`).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Mudança agendada recuperada com sucesso","data":{"changeType":"INTERVAL_CHANGE","currentProduct":{"id":"0b7e9c1a-2d3f-4a5b-8c6d-7e8f9a0b1c2d","title":"Growth · Mensal","price":"99.90","billingInterval":"MONTHLY"},"newProduct":{"id":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","title":"Growth · Anual","price":"999.00","billingInterval":"YEARLY"},"effectiveDate":"2026-10-25T15:00:00.000Z","scheduledAt":"2026-10-07T15:00:00.000Z","scheduledById":"3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSubscriptionsByIdScheduledChange"},"delete":{"tags":["Subscriptions"],"summary":"Desfaz a troca de plano agendada","description":"FIN-68. Desfaz a troca agendada; a assinatura renova na opção atual. O assinante, ou owner/admin da comunidade do X-CommunityId (e SuperAdmin); de outra pessoa ou de outra comunidade responde 404. Sem troca agendada, 404 (`noScheduledChange`). Depois que a cobrança de renovação do período da troca foi gerada (PIX ou boleto enviado antes do vencimento, já no preço novo), responde 409 `param = id`: a troca vale quando ela for paga.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteSubscriptionsByIdScheduledChange"}},"/api/subscriptions/{id}/add-ons/quote":{"post":{"tags":["Subscriptions"],"summary":"Cota um adicional para o plano em andamento","description":"F-37. Sem efeito: diz quanto custa somar um adicional ao plano que o membro já assina. `:id` é a assinatura do plano (a âncora), do próprio membro, na comunidade do X-CommunityId; de outra pessoa ou de outra comunidade responde 404. O adicional precisa estar na lista de adicionais do plano e ser `SUBSCRIPTION` `MONTHLY` à venda; já assinado (ACTIVE, TRIALING, PAST_DUE ou PAUSED) responde 400. A âncora precisa estar ACTIVE, sem cancelamento agendado e com próxima cobrança; assinatura que já é adicional de outra responde 400 (`param = id`). `periodAmount` é o valor do adicional por período do plano (o mensal, ou 12 × o mensal no anual). `prorataAmount` é o proporcional até `nextChargeDate`; com menos de 3 dias ou menos de R$ 10, `floorApplied = true` e `amountDueNow = 0`: o adicional começa já e entra cheio na próxima cobrança. `amountToCharge` soma a taxa da plataforma quando o comprador a paga (`feePayer = BUYER`); é uma cobrança separada, com taxa percentual e fixa. `maxInstallments` é o teto de parcelas no cartão (meses restantes no anual, limitado ao da opção do plano; 1 no mensal). `nextChargeTotal` é o total da próxima cobrança conjunta já com o adicional.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"productId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e"},"schema":{"type":"object","required":["productId"],"properties":{"productId":{"type":"string","format":"uuid","description":"O adicional"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdAddOnsQuote"}},"/api/subscriptions/{id}/add-ons":{"post":{"tags":["Subscriptions"],"summary":"Soma um adicional ao plano em andamento","description":"F-37. Cobra agora o proporcional da cotação (`/add-ons/quote`, mesmas regras e recusas) num pedido separado, e cria a assinatura do adicional ligada à do plano (`billedWithId`), com as datas do plano: a partir da próxima cobrança ele vem no mesmo pedido que o plano. Com o piso (`floorApplied`), nada é cobrado e o adicional já nasce ligado (`charged = false`). Pagamento: `paymentMethod` (obrigatório quando há valor a cobrar, senão 400 com `param = paymentMethod`) entre os aceitos pela opção do plano; `installments` até o `maxInstallments` da cotação, só no cartão; cartão salvo por `paymentMethodId` (do próprio membro, senão 404) ou cartão novo por `cardToken`; PIX e boleto devolvem `pixCode`/`qrCode` ou `boletoUrl`/`boletoBarcode`, e o adicional nasce quando o pagamento é confirmado. Cartão salvo aprovado na hora já devolve `subscriptionId` e `status = COMPLETED`; senão `status = PROCESSING`. Recusa do provedor responde 402, provedor fora do ar 502, como no checkout. Responde 201. Como no checkout, 403 (`param = id`) quando a comunidade não tem informações comerciais `APPROVED`, antes de cotar ou cobrar. Vale também para aceitar uma oferta de downsell, que compra o adicional por este mesmo caminho.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"productId":"e8a1c3f5-7b9d-4f2a-8c6e-0d2f4a6b8c1e","paymentMethod":"CREDIT_CARD","installments":1,"paymentMethodId":"9e1a3c5b-7d9f-4b1c-8e3a-5c7e9b1d3f64"},"schema":{"type":"object","required":["productId"],"properties":{"productId":{"type":"string","format":"uuid","description":"O adicional"},"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO"]},"installments":{"type":"integer","minimum":1,"maximum":12},"cardToken":{"type":"string","description":"Cartão novo, tokenizado no app"},"paymentMethodId":{"type":"string","format":"uuid","description":"Cartão salvo do membro (/payment-methods)"},"customerData":{"type":"object","description":"Nome, e-mail, documento e telefone do pagador, como no checkout"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdAddOns"}},"/api/subscriptions/{id}/pay-now":{"post":{"tags":["Subscriptions"],"summary":"Paga agora uma assinatura em atraso","description":"\"Pagar agora\" (decisão do David, 2026-10-05). Gera, para a **mesma assinatura** em `PAST_DUE`, uma cobrança nova: PIX, boleto, cartão novo (`cardToken`) ou cartão salvo (`paymentMethodId`, do assinante). Os adicionais cobrados junto com o plano (F-37) entram no mesmo pedido, com a taxa fixa uma vez. Paga (na hora, para cartão aprovado; ou pelo webhook), a assinatura volta a `ACTIVE`, o período avança e os adicionais suspensos voltam. O período pago é o que está em aberto, a partir de `nextBillingDate`; se ele já teria terminado, começa agora. Cobranças PIX/boleto de renovação ainda abertas da assinatura são canceladas antes, para não pagar duas vezes. Cartão novo usado aqui vira o cartão da próxima renovação. Quem pode: o assinante, ou owner/admin da comunidade do X-CommunityId (e SuperAdmin); assinatura de outra pessoa ou de outra comunidade responde 404. Recusas, todas antes de qualquer cobrança: 400 `param = id` quando a assinatura não está `PAST_DUE` ou é um adicional ligado a um plano; 400 `paymentMethod`/`installments` fora do que o produto aceita (parcelas só no cartão); 400 `cardToken` com cartão e sem token nem `paymentMethodId`; 404 `paymentMethodId` de cartão que não é do assinante; 409 `param = id` quando uma cobrança de cartão da assinatura ainda está em análise. Recusa do provedor responde 402; provedor fora do ar, 502. Responde 201. `data`: `subscriptionId`, `status`, `paid`, `pendingRenewal` (o mesmo objeto de `GET /api/subscriptions`, ou `null` quando já foi pago), `purchaseId`, `orderId`, `amount` (total do pedido), `currency`, `installments`, `periodStart`, `periodEnd` e `items` (`subscriptionId`, `productId`, `title`, `amount`).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"paymentMethod":"PIX"},"schema":{"type":"object","required":["paymentMethod"],"properties":{"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO"]},"installments":{"type":"integer","minimum":1,"maximum":12,"description":"Só no cartão, até o maxInstallments do produto"},"paymentMethodId":{"type":"string","format":"uuid","description":"Cartão salvo do assinante (/payment-methods)"},"cardToken":{"type":"string","description":"Cartão novo, tokenizado no app"},"customerData":{"type":"object","description":"Nome, e-mail, documento e telefone do pagador, como no checkout. Sem ele, usa o cliente do pedido original"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSubscriptionsByIdPayNow"}},"/api/storefront/spaces/{spaceId}/products":{"get":{"tags":["Storefront"],"summary":"Lista os produtos de um space Loja","description":"Devolve os produtos que o space `storefront` mostra a quem pergunta. Segue as mesmas regras de acesso do space (public / members / plan / private com concessões, seção e space em AND) — quem não pode abrir o space recebe 403. Só produtos `ACTIVE` e não excluídos da comunidade do header. Em modo `all`, todo produto ativo da comunidade; em `selected`, só os escolhidos, na ordem escolhida. Nunca traz custo de provedor. `allowedPaymentMethods` vem como array. `soldOut` indica estoque esgotado sem revelar a quantidade. Um produto avulso listado aqui pode ser comprado em `POST /api/checkout` por quem enxerga este space, mesmo com `directLinkEnabled` desligado. Adicionais (produtos com `prerequisiteGroupIds`) só aparecem para quem tem assinatura ACTIVE ou TRIALING num dos grupos exigidos; quem administra a Loja (`canManageSpace`) vê todos. Cada produto traz `prerequisiteGroupIds`.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"type":"object","properties":{"space":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string","nullable":true},"module":{"type":"string","enum":["storefront"]},"visibility":{"type":"string","enum":["public","members","plan","private"]}}},"mode":{"type":"string","enum":["all","selected"]},"canManageSpace":{"type":"boolean"},"products":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"title":{"type":"string"},"slug":{"type":"string"},"shortDescription":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"bannerUrl":{"type":"string","nullable":true},"featuredImageUrl":{"type":"string","nullable":true},"type":{"type":"string","enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"]},"price":{"type":"string","example":"197.00"},"currency":{"type":"string"},"billingInterval":{"type":"string","nullable":true},"trialDays":{"type":"integer","nullable":true},"installments":{"type":"integer","nullable":true},"installmentPrice":{"type":"string","nullable":true},"maxInstallments":{"type":"integer","nullable":true},"allowedPaymentMethods":{"type":"array","nullable":true,"items":{"type":"string"}},"feePayer":{"type":"string","enum":["ORGANIZATION","BUYER"]},"soldOut":{"type":"boolean"},"isHighlighted":{"type":"boolean"},"sortOrder":{"type":"integer"},"prerequisiteGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getStorefrontSpacesBySpaceIdProducts"}},"/api/storefront/spaces/{spaceId}":{"get":{"tags":["Storefront"],"summary":"Configuração de um space Loja","description":"Owner ou admin da comunidade do header. Devolve o modo (`all`/`selected`) e os produtos escolhidos (`productIds`, na ordem de exibição). A seleção é mantida mesmo em `all`. Um space sem configuração salva responde o padrão (`all`, sem seleção) sem gravar nada.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"type":"object","properties":{"space":{"type":"object"},"mode":{"type":"string","enum":["all","selected"]},"productIds":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getStorefrontSpacesBySpaceId"},"put":{"tags":["Storefront"],"summary":"Define o modo e os produtos de um space Loja","description":"Owner ou admin da comunidade do header. `mode: all` mostra todo produto ativo da comunidade; `mode: selected` mostra só `productIds`. `productIds` substitui a seleção inteira, na ordem enviada; omitido, mantém a atual. Produtos em rascunho são aceitos e só aparecem quando ativos. Produto de outra comunidade ou excluído é recusado com 400.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["all","selected"]},"productIds":{"type":"array","maxItems":500,"items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putStorefrontSpacesBySpaceId"}},"/api/status":{"get":{"tags":["Status"],"summary":"Lista status","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getStatus"},"post":{"tags":["Status"],"summary":"Cria ou executa status","description":"Sujeito a verificação de papel (RBAC). Além disso, respeita o\n`canCreate` do space: `staff` aceita owner, admin e moderator;\n`admins` aceita owner e admin; `anyone` não restringe. Fora da\nregra, 403 com `errors[0].param = \"spaceId\"`. SuperAdmin sempre passa.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postStatus"}},"/api/status/{id}":{"put":{"tags":["Status"],"summary":"Atualiza status","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putStatusById"},"delete":{"tags":["Status"],"summary":"Remove status","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteStatusById"}},"/api/status/{id}/react":{"post":{"tags":["Status"],"summary":"Cria ou executa react","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postStatusByIdReact"}},"/api/status/{id}/comment":{"post":{"tags":["Status"],"summary":"Cria ou executa comment","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postStatusByIdComment"}},"/api/status/{id}/comments":{"get":{"tags":["Status"],"summary":"Lista ou consulta comments","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getStatusByIdComments"}},"/api/status/{id}/comment/{commentId}/react":{"post":{"tags":["Status"],"summary":"Adiciona, troca ou remove a reação a um comentário de status","description":"Mandar a mesma reação de novo remove; outra reação troca. O status precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"type":"👏"},"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["🎉","❤️","👍","🔥","🙌","😊","👏"],"description":"Reaction type is required"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postStatusByIdCommentByCommentIdReact"}},"/api/status/{statusId}/comment/{commentId}":{"put":{"tags":["Status"],"summary":"Atualiza comment","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"statusId","required":true,"schema":{"type":"string"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","minLength":1,"maxLength":280,"description":"Comment must be between 1 and 280 characters"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putStatusByStatusIdCommentByCommentId"},"delete":{"tags":["Status"],"summary":"Remove comment","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"statusId","required":true,"schema":{"type":"string"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteStatusByStatusIdCommentByCommentId"}},"/api/spaces":{"get":{"tags":["Sections & Spaces"],"summary":"Lista sections & spaces","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.\n\nA lista é filtrada por quem pergunta. Um item `private` que o leitor não\nalcança **some** quando o que o fecha é um grupo de membros, e **volta\ncom `locked: true` e `lockReason`** (`product` ou `subscription`) quando\no que o fecha pode ser comprado — esconder a oferta seria esconder a\nvenda. Owner, admin e moderator recebem tudo.\n\nA resposta traz, **para quem administra**, os campos opcionais novos\n`access` (o que o próprio space exige), `requiredBySection` (o que a\nseção exige — combina com **E**, não é mais item da mesma lista, e vem\ncom `sectionId`, `sectionTitle` e `visibility`) e `accessFromProducts`\n(os produtos ligados pela tela de produtos, que a tela de space não\nedita).\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"sectionId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid section ID is required"},{"in":"query","name":"module","required":false,"schema":{"type":"string"},"description":"Invalid module type"},{"in":"query","name":"visibility","required":false,"schema":{"type":"string","enum":["public","members","plan","private"]},"description":"Invalid visibility value"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSpaces"},"post":{"tags":["Sections & Spaces"],"summary":"Cria ou executa sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"sectionId":"a7d3e9f1-2b4c-4d6e-8f0a-1b2c3d4e5f60","title":"Mural da comunidade","description":"Novidades, perguntas e apresentações.","module":"feed","visibility":"members","canCreate":"anyone"},"schema":{"type":"object","required":["sectionId","title","module"],"properties":{"sectionId":{"type":"string","format":"uuid","description":"Valid section ID is required"},"title":{"type":"string","maxLength":255,"description":"Title is required"},"description":{"type":"string","description":"Description must be a string"},"slug":{"type":"string","maxLength":255,"description":"Letras minúsculas, números e hífen. Não pode começar com _ (rotas internas do app ficam em /_/): 400 com param = slug. Gerado do título quando ausente, nunca com _."},"icon":{"type":"string","maxLength":100,"description":"Icon must be 100 characters or less"},"order":{"type":"integer","description":"Order must be a non-negative integer"},"module":{"type":"string","description":"Invalid module type"},"externalUrl":{"type":"string","format":"uri","description":"Invalid URL format"},"visibility":{"type":"string","enum":["public","members","plan","private"],"description":"Nunca mais aberta que a da seção que contém o space, na ordem `public` < `members` < `plan` < `private`. Mais aberta devolve 400.\n"},"access":{"type":"object","description":"Quem entra quando `visibility` é `private`. Opcional e **aditivo**: ausente não mexe em nada; presente **substitui** o conjunto inteiro, porque o modal sempre manda tudo. As três listas são **união** — satisfazer qualquer uma basta. Um id de outra comunidade devolve 400 com `errors`.\n","properties":{"groupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"productIds":{"type":"array","items":{"type":"string","format":"uuid"}},"subscriptionGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"moduleConfig":{"type":"object","nullable":true,"description":"Configuração específica do módulo, preenchida no wizard. A forma depende do módulo — `call4papers` guarda o modo do space e a primeira chamada. Enviar `null` limpa.\n"},"canCreate":{"type":"string","enum":["anyone","staff","admins"],"description":"Quem cria conteúdo no space (post, status, evento, curso, imagem de galeria). `anyone`: quem a rota já aceita; `staff`: owner, admin e moderator; `admins`: owner e admin. Opcional: na criação o padrão é `anyone`; na edição, ausente não mexe. Comentar e reagir não dependem disso.\n"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSpaces"}},"/api/spaces/modules":{"get":{"tags":["Sections & Spaces"],"summary":"Lista o catálogo de módulos de space por categoria","description":"Catálogo estático dos módulos de space, agrupados nas categorias\n`community`, `people` e `coworking`, nessa ordem — que é a ordem das\nabas do seletor de módulo na criação de space. Dentro de cada\ncategoria, os módulos vêm na ordem de exibição.\n\nCada módulo traz só a `key` estável e `available`. O rótulo é\ntraduzido pelo app; a API não devolve texto para o usuário.\n\n`available: false` marca um módulo **planejado**: ele aparece no\ncatálogo para o app mostrar como \"em breve\", mas **não** é aceito em\n`POST /api/spaces` nem em `PUT /api/spaces/{id}`. Os módulos com\n`available: true` são exatamente os aceitos no campo `module`.\n\nRestrito a owner e admin da comunidade do `X-CommunityId` — o mesmo\npapel que pode criar space.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Catálogo de módulos agrupado por categoria.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"categories":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["community","people","coworking"]},"modules":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"content"},"available":{"type":"boolean","example":true}}}}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSpacesModules"}},"/api/spaces/{id}":{"get":{"tags":["Sections & Spaces"],"summary":"Detalha sections & spaces por id","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.\n\nResponde 403 quando o leitor não alcança o item. A regra é a mesma da\nlistagem e vale também para o deep link por slug.\n\nA resposta traz, **para quem administra**, os campos opcionais novos\n`access` (o que o próprio space exige), `requiredBySection` (o que a\nseção exige — combina com **E**, não é mais item da mesma lista, e vem\ncom `sectionId`, `sectionTitle` e `visibility`) e `accessFromProducts`\n(os produtos ligados pela tela de produtos, que a tela de space não\nedita).\n","security":[],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSpacesById"},"put":{"tags":["Sections & Spaces"],"summary":"Atualiza sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"title":"Mural da comunidade","description":"Novidades, perguntas e apresentações da turma."},"schema":{"type":"object","properties":{"sectionId":{"type":"string","format":"uuid","description":"Valid section ID is required"},"title":{"type":"string","maxLength":255,"description":"Title cannot be empty"},"description":{"type":"string","description":"Description must be a string"},"slug":{"type":"string","maxLength":255,"description":"Letras minúsculas, números e hífen. Não pode começar com _ (rotas internas do app ficam em /_/): 400 com param = slug. Gerado do título quando ausente, nunca com _."},"icon":{"type":"string","maxLength":100,"description":"Icon must be 100 characters or less"},"order":{"type":"integer","description":"Order must be a non-negative integer"},"module":{"type":"string","description":"Invalid module type"},"externalUrl":{"type":"string"},"visibility":{"type":"string","enum":["public","members","plan","private"],"description":"Nunca mais aberta que a da seção que contém o space, na ordem `public` < `members` < `plan` < `private`. Mais aberta devolve 400.\n"},"access":{"type":"object","description":"Quem entra quando `visibility` é `private`. Opcional e **aditivo**: ausente não mexe em nada; presente **substitui** o conjunto inteiro, porque o modal sempre manda tudo. As três listas são **união** — satisfazer qualquer uma basta. Um id de outra comunidade devolve 400 com `errors`.\n","properties":{"groupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"productIds":{"type":"array","items":{"type":"string","format":"uuid"}},"subscriptionGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"moduleConfig":{"type":"object","nullable":true,"description":"Configuração específica do módulo, preenchida no wizard. A forma depende do módulo — `call4papers` guarda o modo do space e a primeira chamada. Enviar `null` limpa.\n"},"canCreate":{"type":"string","enum":["anyone","staff","admins"],"description":"Quem cria conteúdo no space (post, status, evento, curso, imagem de galeria). `anyone`: quem a rota já aceita; `staff`: owner, admin e moderator; `admins`: owner e admin. Opcional: na criação o padrão é `anyone`; na edição, ausente não mexe. Comentar e reagir não dependem disso.\n"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putSpacesById"},"delete":{"tags":["Sections & Spaces"],"summary":"Remove sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteSpacesById"}},"/api/spaces/reorder":{"post":{"tags":["Sections & Spaces"],"summary":"Cria ou executa reorder","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"sectionId":"a7d3e9f1-2b4c-4d6e-8f0a-1b2c3d4e5f60","spaces":[{"id":"b1e2c3d4-5f6a-4b7c-8d9e-0f1a2b3c4d5e","order":0},{"id":"c3f5a7b9-1d2e-4f6a-8b0c-2d4e6f8a0b1c","order":1}]},"schema":{"type":"object","required":["sectionId","spaces","spaces.*.id","spaces.*.order"],"properties":{"sectionId":{"type":"string","format":"uuid","description":"Valid section ID is required"},"spaces":{"type":"array","description":"Spaces array is required with at least one item"},"spaces.*.id":{"type":"string","format":"uuid","description":"Each space must have a valid ID"},"spaces.*.order":{"type":"integer","description":"Each space must have a non-negative order value"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSpacesReorder"}},"/api/sections":{"get":{"tags":["Sections & Spaces"],"summary":"Lista sections & spaces","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.\n\nA lista é filtrada por quem pergunta. Um item `private` que o leitor não\nalcança **some** quando o que o fecha é um grupo de membros, e **volta\ncom `locked: true` e `lockReason`** (`product` ou `subscription`) quando\no que o fecha pode ser comprado — esconder a oferta seria esconder a\nvenda. Owner, admin e moderator recebem tudo.\n\nA resposta traz, **para quem administra**, um campo opcional novo\n`access` com as três listas da concessão (`groups`, `products`,\n`subscriptionGroups`). Membro comum não recebe: o nome de um grupo já é\ninformação.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"visibility","required":false,"schema":{"type":"string","enum":["public","members","plan","private"]},"description":"Invalid visibility value"},{"in":"query","name":"isHome","required":false,"schema":{"type":"boolean"},"description":"isHome must be boolean"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSections"},"post":{"tags":["Sections & Spaces"],"summary":"Cria ou executa sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"title":"Comece por aqui","description":"O essencial para quem acabou de chegar.","visibility":"members"},"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":255,"description":"Title is required"},"description":{"type":"string","description":"Description must be a string"},"slug":{"type":"string","maxLength":255,"description":"Letras minúsculas, números e hífen. Não pode começar com _ nem ser um nome reservado pelo app (admin, pricing, billing, checkout-success, products, settings, account, members, monetization, set-password, api, docs, oauth, verify, offer, payment e outros; lista em src/config/reservedSlugs.js): 400 com param = slug. Gerado do título quando ausente, nunca com _ nem reservado."},"icon":{"type":"string","description":"Invalid icon value"},"order":{"type":"integer","description":"Order must be a non-negative integer"},"visibility":{"type":"string","enum":["public","members","plan","private"],"description":"Invalid visibility value"},"access":{"type":"object","description":"Quem entra quando `visibility` é `private`. Opcional e **aditivo**: ausente não mexe em nada; presente **substitui** o conjunto inteiro, porque o modal sempre manda tudo. As três listas são **união** — satisfazer qualquer uma basta. Um id de outra comunidade devolve 400 com `errors`.\n","properties":{"groupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"productIds":{"type":"array","items":{"type":"string","format":"uuid"}},"subscriptionGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"isHome":{"type":"boolean","description":"isHome must be boolean"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSections"}},"/api/sections/{id}":{"get":{"tags":["Sections & Spaces"],"summary":"Detalha sections & spaces por id","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.\n\nResponde 403 quando o leitor não alcança o item. A regra é a mesma da\nlistagem e vale também para o deep link por slug.\n\nA resposta traz, **para quem administra**, um campo opcional novo\n`access` com as três listas da concessão (`groups`, `products`,\n`subscriptionGroups`). Membro comum não recebe: o nome de um grupo já é\ninformação.\n","security":[],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSectionsById"},"put":{"tags":["Sections & Spaces"],"summary":"Atualiza sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"title":"Comece por aqui","visibility":"public"},"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":255,"description":"Title cannot be empty"},"description":{"type":"string","description":"Description must be a string"},"slug":{"type":"string","maxLength":255,"description":"Letras minúsculas, números e hífen. Não pode começar com _ nem ser um nome reservado pelo app (admin, pricing, billing, checkout-success, products, settings, account, members, monetization, set-password, api, docs, oauth, verify, offer, payment e outros; lista em src/config/reservedSlugs.js): 400 com param = slug. Gerado do título quando ausente, nunca com _ nem reservado."},"icon":{"type":"string","description":"Invalid icon value"},"order":{"type":"integer","description":"Order must be a non-negative integer"},"visibility":{"type":"string","enum":["public","members","plan","private"],"description":"Invalid visibility value"},"access":{"type":"object","description":"Quem entra quando `visibility` é `private`. Opcional e **aditivo**: ausente não mexe em nada; presente **substitui** o conjunto inteiro, porque o modal sempre manda tudo. As três listas são **união** — satisfazer qualquer uma basta. Um id de outra comunidade devolve 400 com `errors`.\n","properties":{"groupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"productIds":{"type":"array","items":{"type":"string","format":"uuid"}},"subscriptionGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}}}},"isHome":{"type":"boolean","description":"isHome must be boolean"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putSectionsById"},"delete":{"tags":["Sections & Spaces"],"summary":"Remove sections & spaces","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteSectionsById"}},"/api/sections/reorder":{"post":{"tags":["Sections & Spaces"],"summary":"Cria ou executa reorder","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"sections":[{"id":"a7d3e9f1-2b4c-4d6e-8f0a-1b2c3d4e5f60","order":0},{"id":"e4a6c8d0-2f1b-4c3d-9e5f-7a9b1c3d5e70","order":1}]},"schema":{"type":"object","required":["sections","sections.*.id","sections.*.order"],"properties":{"sections":{"type":"array","description":"Sections array is required with at least one item"},"sections.*.id":{"type":"string","format":"uuid","description":"Each section must have a valid ID"},"sections.*.order":{"type":"integer","description":"Each section must have a non-negative order value"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postSectionsReorder"}},"/api/search":{"get":{"tags":["Feed"],"summary":"Busca por título na comunidade","description":"Procura `q` no título de posts (e no texto de posts curtos), eventos, cursos, seções, spaces e chamadas de trabalhos da comunidade do `X-CommunityId`, sem diferenciar maiúsculas nem acentos (\"comunidade\" acha \"Comunidáde\"). Qualquer papel da comunidade; cada um só recebe o que pode abrir: spaces e seções fechados para a pessoa ficam de fora, e quem não é da equipe só vê itens aprovados e publicados, cursos publicados e chamadas que não são rascunho. Cada item traz `type` (`post`, `event`, `course`, `section`, `space`, `call_for_papers`), `id`, `title` e o space onde está.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"q","required":true,"schema":{"type":"string","minLength":2,"maxLength":200},"example":"como a comunidade funciona"},{"in":"query","name":"types","required":false,"description":"Lista separada por vírgula; padrão: todos.","schema":{"type":"string","example":"posts,events"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"`data.items` com os resultados, `data.total` com quantos acharam no total.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Sucesso","data":{"query":"como a comunidade funciona","total":1,"items":[{"type":"post","feedType":"content","id":"8a6e0f4e-1b2c-4d3e-9f8a-7b6c5d4e3f2a","title":"Como a comunidade funciona","slug":"como-a-comunidade-funciona","space":{"id":"0b7c1d2e-3f4a-4b5c-8d9e-0f1a2b3c4d5e","title":"Boas-vindas"}}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getSearch"}},"/api/reports/sales":{"get":{"operationId":"getCommunitiesByCommunityIdReportsSales","tags":["Reports"],"summary":"Relatório de vendas por período","description":"F-46. Owner, admin ou finance. Vem do **extrato** (ledger), então o líquido aqui é o\nlíquido do extrato no mesmo período.\n\nCada linha de `series` é um período (`period`) com: `gross` (bruto pago pelo comprador),\n`platformFee` (taxa da plataforma), `installmentInterest` (juros de parcelamento da\nMemberfy), `net` (líquido creditado), `sales` (número de vendas), `averageTicket`,\n`refunds`/`refundsCount`, `chargebacks`/`chargebacksCount` (com a tarifa de contestação)\ne `netAfterRefunds` (`net` − reembolsos − contestações). Períodos sem venda vêm com zero.\n`totals` soma a janela; `allTime` soma desde a primeira venda.\n\nCom `groupBy`, `groups[]` repete o mesmo formato por produto (opção de cobrança), plano,\nforma de pagamento ou tipo de produto. Uma venda sem plano entra no grupo `key: null`.\n`payouts` traz os saques por período na mesma moeda: `requested` (pedidos, pela data do\npedido, sem os cancelados e os que falharam) e `completed` (concluídos, pela data de\nconclusão), com as quantidades.\nUma moeda por consulta (`currency`; padrão: a moeda com mais vendas). Nunca traz custo\nde provedor: a taxa da plataforma é a única taxa.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"},{"in":"query","name":"groupBy","schema":{"type":"string","enum":["none","product","plan","paymentMethod","productType"],"default":"none"}},{"in":"query","name":"currency","schema":{"type":"string","enum":["BRL","USD","EUR","GBP","MXN","ARS"]}}],"responses":{"200":{"description":"Série pronta para gráfico.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-08-01","to":"2026-09-30","timezone":"America/Sao_Paulo","currency":"BRL","currencies":["BRL"],"groupBy":"plan","series":[{"period":"2026-08","gross":0,"platformFee":0,"installmentInterest":0,"net":0,"sales":0,"averageTicket":0,"refunds":0,"refundsCount":0,"chargebacks":0,"chargebacksCount":0,"netAfterRefunds":0},{"period":"2026-09","gross":899.4,"platformFee":89.94,"installmentInterest":0,"net":776.52,"sales":6,"averageTicket":149.9,"refunds":99.9,"refundsCount":2,"chargebacks":0,"chargebacksCount":0,"netAfterRefunds":676.62}],"totals":{"gross":899.4,"platformFee":89.94,"installmentInterest":0,"net":776.52,"sales":6,"averageTicket":149.9,"refunds":99.9,"refundsCount":2,"chargebacks":0,"chargebacksCount":0,"netAfterRefunds":676.62},"allTime":{"gross":3205.3,"platformFee":320.53,"installmentInterest":12.4,"net":2872.37,"sales":21,"averageTicket":152.63,"refunds":99.9,"refundsCount":2,"chargebacks":0,"chargebacksCount":0,"netAfterRefunds":2772.47},"payouts":{"series":[{"period":"2026-08","requested":0,"requestedCount":0,"completed":0,"completedCount":0},{"period":"2026-09","requested":500,"requestedCount":1,"completed":500,"completedCount":1}],"totals":{"requested":500,"requestedCount":1,"completed":500,"completedCount":1}},"groups":[{"key":"9b2f4c1e-7a3d-4e8b-a1c6-5d0f2e7b9c34","label":"Plano Pro","totals":{"gross":899.4,"net":776.52,"sales":6},"series":[{"period":"2026-08","gross":0,"net":0,"sales":0},{"period":"2026-09","gross":899.4,"net":776.52,"sales":6}]}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/subscriptions":{"get":{"operationId":"getCommunitiesByCommunityIdReportsSubscriptions","tags":["Reports"],"summary":"Relatório de assinaturas (MRR, novas, canceladas, churn)","description":"F-46. Owner, admin ou finance.\n\n`series[]` por período: `mrr` (receita recorrente mensal no fim do período: cada\nassinatura pagante convertida para o mês — anual ÷ 12, semanal × 52 ÷ 12),\n`active` (pagantes no fim do período), `new`, `canceled`, `churnRate` (% de canceladas\nsobre as ativas no início do período; `null` quando não havia nenhuma), `trialing` e\n`courtesy` (cortesias vigentes, fora do MRR).\n\nO histórico é reconstruído pelas datas de início e de fim de cada assinatura. Mudanças\nde status que não deixam data (um atraso que se resolveu, uma pausa) só aparecem no\nretrato atual `current` (`mrr`, `arr`, `paying`, `byStatus`, `canceling` — vão encerrar\nno fim do período —, `pastDue`, `courtesy`). `byPlan[]` traz, por plano, as pagantes e o\nMRR de hoje e as novas/canceladas da janela. `downsell` conta ofertas de última chance\nexibidas e aceitas na janela.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"},{"in":"query","name":"currency","schema":{"type":"string","enum":["BRL","USD","EUR","GBP","MXN","ARS"]}}],"responses":{"200":{"description":"Série pronta para gráfico.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-09-01","to":"2026-10-31","timezone":"America/Sao_Paulo","currency":"BRL","currencies":["BRL"],"series":[{"period":"2026-09","mrr":174.63,"active":4,"new":1,"canceled":0,"churnRate":0,"trialing":0,"courtesy":0},{"period":"2026-10","mrr":224.53,"active":5,"new":2,"canceled":1,"churnRate":25,"trialing":0,"courtesy":1}],"totals":{"new":3,"canceled":1,"churnRate":14.29,"mrrStart":174.63,"mrrEnd":224.53},"current":{"mrr":224.53,"arr":2694.36,"paying":5,"byStatus":{"ACTIVE":6,"CANCELED":1},"canceling":1,"pastDue":0,"courtesy":1},"byPlan":[{"key":"9b2f4c1e-7a3d-4e8b-a1c6-5d0f2e7b9c34","label":"Plano Pro","active":5,"mrr":224.53,"new":3,"canceled":1,"courtesy":1}],"downsell":{"shown":4,"accepted":1,"acceptanceRate":25}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/members":{"get":{"operationId":"getCommunitiesByCommunityIdReportsMembers","tags":["Reports"],"summary":"Relatório de membros (novos, ativos, inativos, por grupo e tag)","description":"F-46. Owner, admin ou moderador.\n\n**Ativo** é quem fez pelo menos uma destas coisas no período: publicou (post ou\nconteúdo), comentou, reagiu, se inscreveu em evento (vou/talvez), se matriculou em curso,\nabriu ou concluiu aula, ou ganhou pontos no ranking (inclui o login diário, quando a\ngamificação está ligada). Só ler, sem interagir, não conta: visualizações não são\nregistradas. No retrato atual (`current`), ativo é quem fez isso nos últimos 30 dias ou\nentrou no app nesse intervalo (`lastSeenAt`).\n\n`series[]`: `new` (entraram no período), `active`, `total` (membros no fim do período) e\n`inactive` (`total` − `active`). `byGroup[]` e `byTag[]` (até 100 tags) trazem `total`,\n`new`, `active` e `inactive` na janela. Membros removidos não contam.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"}],"responses":{"200":{"description":"Série pronta para gráfico.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"week","from":"2026-09-28","to":"2026-10-11","timezone":"America/Sao_Paulo","activeDefinition":{"activeDays":30,"counts":["post","article","comment","reaction","event","enrollment","lesson","points"]},"series":[{"period":"2026-09-28","new":3,"active":9,"total":25,"inactive":16},{"period":"2026-10-05","new":2,"active":11,"total":27,"inactive":16}],"totals":{"new":5,"active":13},"current":{"total":27,"active":14,"inactive":13,"byRole":{"owner":2,"admin":1,"moderator":1,"member":22,"finance":1}},"byGroup":[{"id":"5c1d7e3a-2b4f-4a6c-9e8d-1f0a3b5c7d92","name":"Produto","total":8,"new":1,"active":5,"inactive":3}],"byTag":[{"tag":"mentor","total":4,"new":0,"active":3,"inactive":1}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/members/{profileId}/activity":{"get":{"operationId":"getCommunitiesByCommunityIdReportsMembersByProfileIdActivity","tags":["Reports"],"summary":"Atividade de um membro (contagens, links e pontos do ranking)","description":"F-46. Owner ou admin. Um membro da comunidade do `X-CommunityId`; de outra comunidade\nou removido, 404.\n\n`counts.period` (na janela) e `counts.allTime`: `posts` (feed), `articles` (conteúdo),\n`comments`, `reactions`, `eventRegistrations`, `courseEnrollments`, `lessonActivity`,\n`points`; e, em `allTime`, `purchases` (pagas), `activeSubscriptions`,\n`coursesCompleted`, `certificates` (emitidos).\n`ranking`: pontos totais, nível, quanto falta para o próximo, posição no ranking geral e\n`byAction[]` (cada ação que dá pontos, com quantidade e pontos no total e na janela).\n`recent`: os últimos posts, comentários, eventos, cursos, compras (valor pago, forma de\npagamento — nunca taxa), assinaturas vigentes e certificados, com `link.path` relativo\nao endereço da comunidade (e `link.url` completo quando ela tem domínio próprio). Post\ndo feed não tem página própria: o link abre o space.\nNão há registro de navegação nem de login além do login diário da gamificação.\n","parameters":[{"in":"path","name":"profileId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"}],"responses":{"200":{"description":"Atividade do membro.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-01-01","to":"2026-10-31","timezone":"America/Sao_Paulo","profile":{"id":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","name":"Maria Silva","role":"member","email":"maria.silva@memberfy.net","joinedAt":"2026-02-10T13:00:00.000Z","lastSeenAt":"2026-10-05T21:14:00.000Z"},"counts":{"period":{"posts":4,"articles":1,"comments":14,"reactions":21,"eventRegistrations":3,"courseEnrollments":2,"lessonActivity":9,"points":356},"allTime":{"posts":4,"articles":1,"comments":24,"reactions":21,"eventRegistrations":3,"courseEnrollments":2,"lessonActivity":9,"points":356,"purchases":2,"activeSubscriptions":1,"coursesCompleted":1,"certificates":1}},"ranking":{"totalPoints":356,"level":3,"pointsToNextLevel":244,"position":2,"byAction":[{"action":"COMPLETE_LESSON","count":9,"points":225,"countInPeriod":9,"pointsInPeriod":225}]},"recent":{"posts":[{"type":"article","id":"aa05ecd3-3940-4675-860b-7b9657c57c1e","title":"Como organizei meu primeiro meetup","createdAt":"2026-09-16T14:45:31.124Z","link":{"path":"/home/artigos/aa05ecd3-3940-4675-860b-7b9657c57c1e","url":null}}],"certificates":[{"id":"0b7e5d2a-3c4f-4e6a-8b1d-9f2c4a6e8b10","title":"Curso de Facilitação","issuedAt":"2026-09-20T12:00:00.000Z","link":{"path":"/_/certificates/verify/7KQ3M9T2XW4P","url":null}}]}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/engagement":{"get":{"operationId":"getCommunitiesByCommunityIdReportsEngagement","tags":["Reports"],"summary":"Relatório de engajamento (posts, comentários, reações e ranking)","description":"F-46. Owner, admin ou moderador.\n\n`series[]` por período: `posts` (feed), `articles` (conteúdo), `comments`, `reactions`,\n`activeMembers` e `points` (pontos do ranking ganhos no período). `bySpace[]` reparte\nposts, comentários e reações pelo space onde aconteceram (`space: null` = fora de space).\n`members[]` é a lista paginada de quem mais engajou na janela, com `posts` (feed +\nconteúdo), `comments`, `reactions`, `interactions` (essas três + inscrições em evento e\nmatrículas), `pointsInPeriod` e o `ranking` de hoje (pontos totais e nível). Ordem por\n`orderBy` (padrão `points` quando a gamificação está ligada, senão `interactions`).\n`unansweredPosts` lista os posts e conteúdos da janela que ninguém além do autor comentou.\n\n`ranking` é o dado que gera o ranking: `enabled`, `rules[]` (pontos por ação),\n`series[]` com os pontos por período e por ação (uma coluna por tipo de ação),\n`byAction[]` (quantidade e pontos de cada ação na janela) e `levels[]` (quantos membros\nem cada nível hoje).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"},{"in":"query","name":"orderBy","schema":{"type":"string","enum":["points","interactions","posts","comments","reactions"]}},{"$ref":"#/components/parameters/ReportPage"},{"$ref":"#/components/parameters/ReportLimit"}],"responses":{"200":{"description":"Série pronta para gráfico; `pagination` vale para `members`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-09-01","to":"2026-10-31","timezone":"America/Sao_Paulo","orderBy":"points","series":[{"period":"2026-09","posts":5,"articles":1,"comments":30,"reactions":42,"activeMembers":9,"points":401},{"period":"2026-10","posts":1,"articles":1,"comments":14,"reactions":21,"activeMembers":6,"points":128}],"totals":{"posts":6,"articles":2,"comments":44,"reactions":63,"activeMembers":11,"points":529},"bySpace":[{"space":{"id":"032c2011-6062-4dcb-a28c-1add5699e122","title":"Avisos","module":"content"},"link":{"path":"/home/avisos","url":null},"posts":0,"articles":2,"comments":10,"reactions":12}],"members":[{"position":1,"profile":{"id":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","name":"Maria Silva","role":"member"},"posts":5,"comments":14,"reactions":21,"interactions":46,"pointsInPeriod":356,"ranking":{"totalPoints":356,"level":3,"pointsToNextLevel":244}}],"unansweredPosts":{"total":1,"items":[{"type":"post","id":"edd54af6-dab7-4e05-8b86-2c10eb919df6","title":"Alguém vai ao meetup de sábado?","createdAt":"2026-10-02T20:35:44.243Z","author":{"id":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","name":"Maria Silva"},"link":{"path":"/home/geral","url":null}}]},"ranking":{"enabled":true,"rules":[{"action":"CREATE_POST","points":10,"active":true}],"series":[{"period":"2026-09","points":401,"actions":60,"CREATE_POST":50,"DAILY_LOGIN":31},{"period":"2026-10","points":128,"actions":20,"CREATE_POST":10,"DAILY_LOGIN":22}],"byAction":[{"action":"CREATE_POST","count":6,"points":60}],"levels":[{"level":1,"members":20},{"level":3,"members":1}]}},"pagination":{"page":1,"limit":20,"total":11,"totalPages":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/events":{"get":{"operationId":"getCommunitiesByCommunityIdReportsEvents","tags":["Reports"],"summary":"Relatório de eventos (inscritos e interessados)","description":"F-46. Owner, admin ou moderador.\n\n**Presença não é registrada** (não existe check-in): `attendanceTracked` é `false` e\n`attended` vem `null`. O que existe é a resposta de cada pessoa: `going` (vou),\n`maybe` (talvez) e `notGoing`.\n\n`series[]` por período: `events` (eventos que começam no período) e as respostas\nregistradas no período. `events[]` (paginada) traz os eventos da janela, pela data de\ninício (ou de criação, sem data), com as respostas e o link.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"},{"$ref":"#/components/parameters/ReportPage"},{"$ref":"#/components/parameters/ReportLimit"}],"responses":{"200":{"description":"Série e lista de eventos; `pagination` vale para `events`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-09-01","to":"2026-10-31","timezone":"America/Sao_Paulo","attendanceTracked":false,"series":[{"period":"2026-09","events":2,"going":18,"maybe":5,"notGoing":1},{"period":"2026-10","events":1,"going":7,"maybe":2,"notGoing":0}],"totals":{"events":3,"going":25,"maybe":7,"notGoing":1},"events":[{"id":"3e9a1c5b-7d2f-4b8e-a6c0-1f4d7b9e2a35","title":"Meetup de outubro","startTime":"2026-10-18T22:00:00.000Z","type":"in_person","category":"meetup","link":{"path":"/eventos/agenda/meetup-de-outubro","url":null},"going":7,"maybe":2,"notGoing":0,"attended":null}]},"pagination":{"page":1,"limit":20,"total":3,"totalPages":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/courses":{"get":{"operationId":"getCommunitiesByCommunityIdReportsCourses","tags":["Reports"],"summary":"Relatório de cursos (matrículas, progresso e conclusão)","description":"F-46. Owner, admin ou moderador.\n\n`series[]` por período: `enrollments`, `completions` (cursos concluídos) e\n`lessonsCompleted`. `courses[]` (paginada, mais matrículas primeiro) traz, por curso:\n`lessons`, `enrollments` (todas, sem as canceladas), `newEnrollments` e\n`completedInPeriod` (na janela), `completed`, `completionRate` (%) e `averageProgress`\n(% médio de aulas concluídas por matriculado; `null` sem matrícula).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportInterval"},{"$ref":"#/components/parameters/ReportFrom"},{"$ref":"#/components/parameters/ReportTo"},{"$ref":"#/components/parameters/ReportTimezone"},{"$ref":"#/components/parameters/ReportPage"},{"$ref":"#/components/parameters/ReportLimit"}],"responses":{"200":{"description":"Série e lista de cursos; `pagination` vale para `courses`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"interval":"month","from":"2026-09-01","to":"2026-10-31","timezone":"America/Sao_Paulo","series":[{"period":"2026-09","enrollments":12,"completions":3,"lessonsCompleted":41},{"period":"2026-10","enrollments":4,"completions":1,"lessonsCompleted":15}],"totals":{"enrollments":16,"completions":4,"lessonsCompleted":56},"courses":[{"id":"7f3b9d1e-5a2c-4e8f-b6d0-2c4e6a8b0d13","title":"Facilitação de comunidades","status":"published","link":{"path":"/aprender/cursos/facilitacao","url":null},"lessons":8,"enrollments":16,"newEnrollments":16,"completed":4,"completedInPeriod":4,"completionRate":25,"averageProgress":47.5}]},"pagination":{"page":1,"limit":20,"total":1,"totalPages":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/reports/overview":{"get":{"operationId":"getCommunitiesByCommunityIdReportsOverview","tags":["Reports"],"summary":"Painel geral da comunidade, num pedido só","description":"F-46. Owner, admin, moderador ou finance; cada bloco segue a regra da sua área:\n`money` só para owner, admin e finance; `community` só para owner, admin e moderador.\nO bloco que o papel não vê não vem na resposta.\n\nCompara **este mês até agora** (`current`) com o mês passado inteiro (`previous`) e com o\nmês passado até o mesmo ponto (`previousToDate`, que é a base dos `...ChangePercent`).\n`money`: vendas (mesmo formato do relatório de vendas), `mrr`, `arr`,\n`payingSubscriptions` e a série de assinaturas dos dois meses. `community`: membros\n(total e novos), engajamento (posts, comentários, reações, pontos, membros ativos) e\neventos nos próximos 30 dias. Meses no fuso da comunidade (ou `timezone`).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"$ref":"#/components/parameters/ReportTimezone"}],"responses":{"200":{"description":"Resumo do mês.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Relatório gerado.","data":{"timezone":"America/Sao_Paulo","month":"2026-10","previousMonth":"2026-09","asOf":"2026-10-06T17:27:12.020Z","money":{"currency":"BRL","revenue":{"current":{"gross":299.8,"platformFee":29.98,"net":262.33,"sales":2},"previous":{"gross":899.4,"platformFee":89.94,"net":776.52,"sales":6},"previousToDate":{"gross":149.9,"platformFee":14.99,"net":131.16,"sales":1},"netChangePercent":100.01},"mrr":224.53,"arr":2694.36,"payingSubscriptions":5,"subscriptions":[{"period":"2026-09","mrr":174.63,"new":1,"canceled":0,"churnRate":0},{"period":"2026-10","mrr":224.53,"new":2,"canceled":1,"churnRate":25}]},"community":{"members":{"total":27,"new":{"current":2,"previous":5,"previousToDate":1,"changePercent":100}},"engagement":{"current":{"posts":2,"comments":14,"reactions":21,"points":128,"activeMembers":6},"previous":{"posts":6,"comments":30,"reactions":42,"points":401,"activeMembers":9},"previousToDate":{"posts":1,"comments":5,"reactions":9,"points":60,"activeMembers":4},"interactionsChangePercent":146.67},"upcomingEvents30Days":1}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/checkout/purchases/{purchaseId}/refresh":{"post":{"tags":["Checkout"],"summary":"Atualiza o status de uma compra consultando o provedor","description":"Para a tela de confirmação, quando o webhook do provedor atrasa ou se perde. Se a compra está `PENDING` ou `PROCESSING` (ou `FAILED` há menos de 7 dias: um PIX cancelado pode ser pago mesmo assim), consulta o pedido na Pagar.me (só leitura) e aplica o que ele diz, exatamente como o webhook faria: pago conclui a compra (e abre a assinatura, lança no ledger, manda o e-mail); falhou ou cancelado fecha a compra como `FAILED`; ainda aberto não muda nada. Idempotente: se o webhook chegar depois, nada é feito duas vezes. Só o comprador, na comunidade do `X-CommunityId`; compra de outra pessoa ou de outra comunidade responde 404. O provedor é consultado no máximo uma vez a cada 10 segundos por compra (`outcome = throttled` dentro dessa janela); compra já concluída responde o status sem consultar (`outcome = unchanged`). Limite de 30 requisições por minuto por IP (429). `outcome`: `paid` (o provedor diz pago; a compra foi ou já estava concluída), `failed` (o provedor diz falhou/cancelado), `pending` (pedido ainda aberto), `unchanged` (compra já fechada, provedor não consultado), `throttled` (consultado há pouco), `skipped` (compra sem pedido no provedor). `subscription` é a assinatura aberta pela compra (ou a renovada, numa cobrança de renovação), ou null.\n","parameters":[{"in":"path","name":"purchaseId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Status atual da compra, depois da consulta ao provedor.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"message":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","ACTIVE","FAILED","REFUNDED","DISPUTED"]},"isActive":{"type":"boolean"},"paymentMethod":{"type":"string"},"accessStartDate":{"type":"string","format":"date-time","nullable":true},"accessEndDate":{"type":"string","format":"date-time","nullable":true},"outcome":{"type":"string","enum":["paid","failed","pending","unchanged","throttled","skipped"]},"subscription":{"type":"object","nullable":true,"properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string"},"productId":{"type":"string","format":"uuid"},"startDate":{"type":"string","format":"date-time"},"currentPeriodStart":{"type":"string","format":"date-time"},"currentPeriodEnd":{"type":"string","format":"date-time"},"nextBillingDate":{"type":"string","format":"date-time","nullable":true}}},"thankYouMessage":{"type":"string","nullable":true,"description":"Mensagem de agradecimento do produto"},"redirectUrl":{"type":"string","nullable":true,"description":"Para onde levar o comprador depois da compra"},"unlocksSpaces":{"type":"array","description":"Só quando a compra está paga. Spaces que o produto ou o plano libera.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"}}}}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Requisições demais em pouco tempo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"},"502":{"description":"Provedor de pagamento indisponível; nada foi alterado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"operationId":"postCheckoutPurchasesByPurchaseIdRefresh"}},"/api/profiles/invite":{"post":{"tags":["Profiles"],"description":"Owner e admin podem dar qualquer papel atribuível, admin inclusive (a mesma regra da promoção). Owner nunca é dado na entrada; moderator e abaixo recebem 403.\nCada convidado recebe e-mail, também em lote, pela fila (a resposta não espera o envio): conta nova recebe o link de uso único `https://<app da comunidade>/_/auth/set-password?id=&token=`, válido por 7 dias (ver `POST /api/auth/set-password`); quem já tem conta recebe \"você foi adicionado(a) à comunidade\" com o link de entrada. Nenhuma senha é gerada nem devolvida.\n","summary":"Cria ou executa invite","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["communityId","emails","role"],"properties":{"communityId":{"type":"string","format":"uuid","description":"Valid community ID is required"},"emails":{"type":"string"},"role":{"type":"string","enum":["admin","moderator","member","finance"],"description":"Valid role is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postProfilesInvite"}},"/api/profiles/create":{"post":{"tags":["Profiles"],"description":"Owner e admin podem dar qualquer papel atribuível, admin inclusive (a mesma regra da promoção). Owner nunca é dado na entrada; moderator e abaixo recebem 403.\nA pessoa recebe pela fila (a resposta não espera o envio) o link de uso único `https://<app da comunidade>/_/auth/set-password?id=&token=`, válido por 7 dias (ver `POST /api/auth/set-password`). A resposta não traz mais `tempPassword`.\n","summary":"Cria ou executa create","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["communityId","fullName","email","role"],"properties":{"communityId":{"type":"string","format":"uuid","description":"Valid community ID is required"},"fullName":{"type":"string","minLength":2,"maxLength":100,"description":"Full name must be between 2 and 100 characters"},"email":{"type":"string","format":"email","description":"Valid email is required"},"role":{"type":"string","enum":["admin","moderator","member","finance"],"description":"Valid role is required"},"avatarUrl":{"type":"string","format":"uri","description":"Avatar URL must be a valid URL"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postProfilesCreate"}},"/api/profiles/autocomplete":{"get":{"tags":["Profiles"],"summary":"Lista ou consulta autocomplete","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"search","required":false,"schema":{"type":"string"},"description":"Search must be a string"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getProfilesAutocomplete"}},"/api/profiles/list":{"get":{"tags":["Profiles"],"summary":"Lista ou consulta list","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"page","required":false,"schema":{"type":"integer"},"description":"Page must be a positive integer"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"Limit must be between 1 and 100"},{"in":"query","name":"search","required":false,"schema":{"type":"string"},"description":"Search must be a string"},{"in":"query","name":"role","required":false,"schema":{"type":"string","enum":["owner","admin","moderator","member","finance"]},"description":"Invalid role"},{"in":"query","name":"sortBy","required":false,"schema":{"type":"string","enum":["joinedAt","lastSeenAt","displayName","role","fullName"]},"description":"Invalid sortBy field"},{"in":"query","name":"order","required":false,"schema":{"type":"string","enum":["asc","desc"]},"description":"Order must be asc or desc"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getProfilesList"}},"/api/profiles/my":{"get":{"tags":["Profiles"],"summary":"Lista ou consulta my","description":"Cada perfil traz `certificateCount` (F-42): quantos certificados a pessoa tem na comunidade. Sair da comunidade apaga todos eles, e a tela de saída avisa com esse número.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getProfilesMy"}},"/api/profiles/tags":{"get":{"tags":["Profiles"],"summary":"Tags já usadas na comunidade","description":"O `distinct` das tags manuais dos perfis desta comunidade, com a contagem de uso. Serve de sugestão ao campo de tags. Não inclui tags de sistema — essas são derivadas e ninguém as escreve. Sujeito a verificação de papel (RBAC).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getProfilesTags"}},"/api/profiles/tags/{tag}":{"put":{"tags":["Profiles"],"summary":"Renomeia uma tag em toda a comunidade","description":"Reescreve a tag em todos os perfis que a carregam, sem distinguir caixa. Renomear para uma tag que já existe é uma **fusão**: quem tiver as duas fica com uma só. Tudo ou nada — se falhar no meio, nada é gravado.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"tag","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":40}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesTagsByTag"},"delete":{"tags":["Profiles"],"summary":"Remove uma tag de todos os perfis da comunidade","description":"Os perfis continuam; a tag sai de todos eles. Tudo ou nada.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"tag","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteProfilesTagsByTag"}},"/api/profiles/tags/{tag}/color":{"put":{"tags":["Profiles"],"summary":"Define a cor com que uma tag é desenhada","description":"A tag continua sendo texto no perfil; isto guarda só a aparência, por comunidade. Tag sem cor escolhida é desenhada em cinza, e renomear ou excluir leva a cor junto.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"tag","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["color"],"properties":{"color":{"type":"string","example":"#2563EB","description":"Hex de 6 dígitos com #"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesTagsByTagColor"}},"/api/profiles/{id}/email":{"put":{"tags":["Profiles"],"summary":"Troca o e-mail de login de um membro","description":"O e-mail vive em `Member`, que é **global**: a troca vale para todas as comunidades daquela pessoa, não só para esta. Era read-only por causa disso, e o custo de continuar read-only era maior — quem foi convidado com o endereço errado não tinha caminho nenhum a não ser recadastrar.\n**Só SuperAdmin.** Owner e admin de uma comunidade não podem: como o e-mail é o login da pessoa em todas as comunidades, quem é owner de uma comunidade onde a vítima é só membro poderia trocar o login dela e tomar a comunidade que ela tem em outro lugar. A senha não muda junto.\nEndereço já usado por outra pessoa devolve 400 com mensagem, não 500.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesByIdEmail"}},"/api/profiles/{id}/phone":{"put":{"tags":["Profiles"],"summary":"Grava o telefone de contato de um membro","description":"Como o e-mail, o número vive em `Member` e vale para todas as comunidades daquela pessoa. Guardado em **E.164** (`+5541999998888`): o que chega pode vir com parênteses, espaço ou hífen, e é normalizado no servidor.\n`phoneCountry` é o país escolhido, em ISO 3166-1 alfa-2. Serve de prefixo quando o número vem sem `+`, e é guardado porque `+1` é dois países.\nString vazia ou null **limpa** o telefone. **Só SuperAdmin**, pelo mesmo motivo do e-mail: o número vive em `Member` e vale para todas as comunidades.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","nullable":true,"maxLength":32},"phoneCountry":{"type":"string","nullable":true,"minLength":2,"maxLength":2}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesByIdPhone"}},"/api/profiles/{id}/tags":{"put":{"tags":["Profiles"],"summary":"Grava as tags manuais de um perfil","description":"Substitui o array inteiro. Só quem administra membros (owner, admin, moderator). O perfil é procurado DENTRO da comunidade do header — um id de outra comunidade simplesmente não é encontrado.\nTags de sistema (como `speaker`) **não** se escrevem por aqui: são derivadas do histórico, e concedê-las à mão faria \"palestrante\" virar um cargo.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tags"],"properties":{"tags":{"type":"array","maxItems":20,"items":{"type":"string","maxLength":40},"description":"Sem strings vazias e sem duplicata ignorando caixa."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesByIdTags"}},"/api/profiles/{id}":{"put":{"tags":["Profiles"],"summary":"Atualiza profiles","description":"Proteção do owner: só outro owner ou um SuperAdmin edita o perfil de um owner. Admin recebe 403 `profile.ownerProtected`.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string","minLength":1,"maxLength":100,"description":"Display name must be between 1 and 100 characters"},"tagline":{"type":"string","maxLength":200,"description":"Tagline must be less than 200 characters"},"profileType":{"type":"string","enum":["user","company"],"description":"Valid profile type is required"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesById"},"delete":{"tags":["Profiles"],"summary":"Remove profiles","description":"Proteção do owner: só outro owner ou um SuperAdmin remove o perfil de um owner. Admin recebe 403 `profile.ownerProtected`.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteProfilesById"}},"/api/profiles/{id}/role":{"put":{"tags":["Profiles"],"summary":"Atualiza role","description":"Proteção do owner: só owner ou SuperAdmin muda o papel de um owner (403 `profile.ownerProtected`) ou torna alguém owner (403 `profile.ownerPromotionForbidden`).\n`finance` (F-32) é um papel lateral, só de leitura do financeiro: lê ledger, saldo, saques, dados bancários/KYC e o painel de vendas, e não altera nada disso. Fora do financeiro, vale como `member`. Só owner, admin ou SuperAdmin atribuem `finance` (403 `profile.financeRoleForbidden`).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["role"],"properties":{"role":{"type":"string","enum":["owner","admin","moderator","member","finance"],"description":"Valid role is required"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putProfilesByIdRole"}},"/api/products":{"get":{"operationId":"getCommunitiesByCommunityIdProducts","tags":["Products"],"summary":"Lista products","description":"Cada produto traz `prerequisiteGroupIds`: os grupos de assinatura (planos) que ele exige quando é um adicional; vazio quando não exige nenhum. Traz também `commitmentMonths`: a duração do contrato em meses, ou `null` quando a assinatura não tem contrato (F-35).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdProducts","tags":["Products"],"summary":"Cria ou executa products","description":"Owner ou admin. Aceita, entre os demais campos, `directLinkEnabled` (boolean opcional, padrão `false`): com ele ligado, um produto avulso (`ONE_TIME` ou `INSTALLMENT`) pode ser comprado por link direto e aparece em `GET /checkout/products`. Desligado, só é comprável por quem enxerga um space Loja (`storefront`) que o mostra. Assinaturas ignoram a flag. `prerequisiteGroupIds` (array de UUID opcional) torna o produto um adicional: ele só aparece nas listagens públicas e só é vendido a quem tem assinatura ACTIVE ou TRIALING num desses grupos, e a assinatura do adicional acompanha a do plano. Os grupos precisam ser da comunidade (senão 400, `param = prerequisiteGroupIds`) e não podem incluir um grupo em `subscriptionGroupIds` (400). A resposta traz `prerequisiteGroupIds`. **Obsoleto na escrita (F-37):** a lista agora é escrita pelo plano (`addOnProductIds` em `POST`/`PUT /subscription-groups`), sobre a mesma relação. Este campo continua aceito e gravando, e continua nas respostas. `commitmentMonths` (inteiro de 1 a 36, ou `null`) é a duração do contrato (fidelidade, F-35): só vale para `SUBSCRIPTION` com `billingInterval` `MONTHLY` (senão 400, `param = commitmentMonths`); `null` ou ausente = sem contrato. A resposta traz `commitmentMonths`. `installmentInterestPayer` (`BUYER`, o padrão, ou `ORGANIZATION`; F-43) diz quem paga os juros de parcelamento da Memberfy no cartão: `BUYER` soma ao preço, `ORGANIZATION` cobra o preço e desconta da comunidade. A resposta traz o campo.\n**Rascunho sem aprovação (2026-10-06):** criar não exige mais informações comerciais aprovadas. O produto nasce sempre `DRAFT`, e a moeda (`currency` na resposta) sai do país das informações comerciais em qualquer status (`PENDING`, `IN_REVIEW`, `REJECTED` ou `APPROVED`); sem informações comerciais, `BRL`. O que exige aprovação é publicar (`POST .../publish` ou `PUT` com `status: ACTIVE`).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ProductInput"},{"type":"object","required":["title","type","price"]}]},"example":{"title":"Plano Pro mensal","description":"<p>Acesso a todos os cursos, encontros ao vivo e à comunidade.</p>","type":"SUBSCRIPTION","price":49.9,"billingInterval":"MONTHLY","allowedPaymentMethods":["CREDIT_CARD","PIX"],"maxInstallments":1}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/products/{idOrSlug}":{"get":{"operationId":"getCommunitiesByCommunityIdProductsByIdOrSlug","tags":["Products"],"summary":"Detalha products por id","description":"Traz `prerequisiteGroupIds`: os grupos de assinatura (planos) que o produto exige quando é um adicional; vazio quando não exige nenhum. Traz também `commitmentMonths` (duração do contrato em meses, ou `null`; F-35).\n","parameters":[{"in":"path","name":"idOrSlug","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/products/{id}/calculate-fees":{"post":{"operationId":"postCommunitiesByCommunityIdProductsByIdCalculateFees","tags":["Products"],"summary":"Cria ou executa calculate fees","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductFeesInput"},"example":{"paymentMethod":"CREDIT_CARD","installments":3,"countryCode":"BR"}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/products/{id}":{"put":{"operationId":"putCommunitiesByCommunityIdProductsById","tags":["Products"],"summary":"Atualiza products","description":"Owner ou admin. Aceita `directLinkEnabled` (boolean opcional) para ligar ou desligar a compra por link direto de um produto avulso; omitido, mantém o valor atual. `prerequisiteGroupIds` (array de UUID opcional) substitui os planos que o adicional exige; `[]` limpa, omitido mantém. Mesmas validações da criação: grupo de outra comunidade ou grupo em que o produto está dá 400. A resposta traz `prerequisiteGroupIds`. **Obsoleto na escrita (F-37):** prefira `addOnProductIds` no plano; este campo continua aceito e gravando. `commitmentMonths` (1 a 36, ou `null` para tirar o contrato) muda a duração do contrato (F-35); omitido, mantém. É conferido contra o produto depois da atualização: só `SUBSCRIPTION` `MONTHLY` (senão 400, `param = commitmentMonths`). Vale para assinaturas novas e para a renovação do contrato das existentes; uma assinatura feita sem contrato continua sem. `installmentInterestPayer` (`BUYER` ou `ORGANIZATION`; F-43): quem paga os juros de parcelamento no cartão. Ausente não muda.\n**`status: ACTIVE` é publicar** e segue as regras de `POST .../publish`: sem informações comerciais `APPROVED`, 403 com a mensagem traduzida que aponta onde preenchê-las; com a moeda do produto diferente da do país aprovado, 400 (`param = currency`). As mesmas regras valem ao trocar `currency` de um produto já `ACTIVE`. Editar qualquer outro campo, de rascunho ou de produto no ar, não exige aprovação.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProductInput"},"example":{"price":59.9,"shortDescription":"Cursos, encontros e comunidade"}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCommunitiesByCommunityIdProductsById","tags":["Products"],"summary":"Remove products","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/products/{id}/publish":{"post":{"operationId":"postCommunitiesByCommunityIdProductsByIdPublish","tags":["Products"],"summary":"Cria ou executa publish","description":"Owner ou admin. Põe o produto no ar (`DRAFT` ou `INACTIVE` → `ACTIVE`): a partir daí ele aparece na loja, no link direto e nas opções do plano, e pode ser comprado. Exige informações comerciais `APPROVED` para **todo** produto (antes valia só quando `requiresApproval` era verdadeiro). Recusas: 403 sem aprovação, com a mensagem traduzida dizendo que o rascunho continua editável e onde preencher as informações comerciais (Configurações › Informação Comercial); 400 quando a moeda do produto difere da moeda do país aprovado (`param = currency`) — o preço não é convertido nem reinterpretado: ajuste `currency` e `price` com `PUT` e publique de novo; 400 quando o país aprovado não tem moeda suportada; 400 se já está `ACTIVE`. Publicar um plano é publicar as suas opções, uma a uma, por esta rota.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Sem papel de owner/admin, ou a comunidade ainda não tem informações comerciais aprovadas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Para publicar e começar a vender, a comunidade precisa ter as informações comerciais aprovadas. Enquanto isso, você pode criar e configurar tudo como rascunho: preencha em Configurações › Informação Comercial e envie para análise.","errors":[{"message":"Para publicar e começar a vender, a comunidade precisa ter as informações comerciais aprovadas. Enquanto isso, você pode criar e configurar tudo como rascunho: preencha em Configurações › Informação Comercial e envie para análise."}]}}}},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/products/{id}/unpublish":{"post":{"operationId":"postCommunitiesByCommunityIdProductsByIdUnpublish","tags":["Products"],"summary":"Cria ou executa unpublish","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payout-settings":{"get":{"operationId":"getCommunitiesByCommunityIdPayoutSettings","tags":["Payouts"],"summary":"Lista ou consulta payout settings","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdPayoutSettings","tags":["Payouts"],"summary":"Cria ou executa payout settings","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["bankCode","accountNumber","accountDigit","branchNumber","accountType","holderName","holderDocumentNumber"],"properties":{"bankCode":{"type":"string","description":"Código do banco é obrigatório."},"accountNumber":{"type":"string","description":"Número da conta é obrigatório."},"accountDigit":{"type":"string","description":"Dígito da conta é obrigatório."},"branchNumber":{"type":"string","description":"Número da agência é obrigatório."},"accountType":{"type":"string","enum":["checking","savings","checking_joint","savings_joint"],"description":"Tipo da conta é obrigatório."},"holderName":{"type":"string","description":"Nome do titular é obrigatório."},"holderDocumentNumber":{"type":"string","description":"Documento do titular é obrigatório."},"transferEnabled":{"type":"boolean","description":"transferEnabled deve ser boolean."},"transferInterval":{"type":"string","enum":["daily","weekly","monthly"],"description":"Intervalo de transferência inválido."},"transferDay":{"type":"integer","description":"Dia de transferência deve estar entre 0 e 31."},"automaticAnticipationEnabled":{"type":"boolean","description":"automaticAnticipationEnabled deve ser boolean."},"anticipatableVolumePercentage":{"type":"integer","description":"Porcentagem deve estar entre 0 e 100."}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payout-settings/submit":{"post":{"operationId":"postCommunitiesByCommunityIdPayoutSettingsSubmit","tags":["Payouts"],"summary":"Cria ou executa submit","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payout-settings/status":{"get":{"operationId":"getCommunitiesByCommunityIdPayoutSettingsStatus","tags":["Payouts"],"summary":"Lista ou consulta status","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payout-settings/prerequisites":{"get":{"operationId":"getCommunitiesByCommunityIdPayoutSettingsPrerequisites","tags":["Payouts"],"summary":"Lista ou consulta prerequisites","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payouts/balance":{"get":{"operationId":"getCommunitiesByCommunityIdPayoutsBalance","tags":["Payouts"],"summary":"Consulta balance","description":"Exige autenticação e papel financeiro (owner, admin ou finance) na comunidade do X-CommunityId. Além de total, available, retained, pending e currency, devolve a taxa de saque vigente (`transferFee`) e o maior valor que pode ser pedido agora (`maxPayoutAmount` = available − transferFee, nunca negativo). A taxa de saque é cobrada por cima do valor pedido (FIN-45).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Saldo e taxa de saque.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"total":{"type":"number"},"available":{"type":"number"},"retained":{"type":"number"},"pending":{"type":"number"},"currency":{"type":"string"},"transferFee":{"type":"number","description":"Taxa de saque da plataforma, somada ao valor pedido. Ex.: 3.67"},"maxPayoutAmount":{"type":"number","description":"Maior valor que pode ser pedido: available − transferFee, mínimo 0"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payouts":{"get":{"operationId":"getCommunitiesByCommunityIdPayouts","tags":["Payouts"],"summary":"Consulta payouts","description":"Exige autenticação — aplicada a todas as rotas deste router.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","CANCELED"]}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdPayouts","tags":["Payouts"],"summary":"Executa payouts","description":"Exige autenticação e papel owner ou admin na comunidade do X-CommunityId. `amount` é o valor que a comunidade recebe; a taxa de saque da plataforma é somada a ele, e `amount + transferFee` sai do saldo disponível (FIN-45). Saldo que não cobre os dois responde 400 com a mensagem traduzida mostrando a taxa. A resposta traz, além do saque, `transferFee` e `totalDebited` (strings com duas casas, como `amount`). O extrato registra a taxa numa entrada própria (`PAYOUT_REQUESTED` com `metadata.isTransferFee = true`), devolvida se o saque for cancelado ou falhar. A taxa vigente pode ser consultada antes em `GET .../payouts/balance` ou `GET .../ledger/balance` (`transferFee`, `maxPayoutAmount`).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount"],"properties":{"amount":{"type":"number","description":"Valor que a comunidade recebe (maior que 0). A taxa de saque é somada a ele."}}}}}},"responses":{"201":{"description":"Saque criado.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","description":"O saque (PayoutRequest), com `providerData` sempre nulo.","properties":{"id":{"type":"string","format":"uuid"},"amount":{"type":"string","description":"Valor que a comunidade recebe"},"status":{"type":"string"},"transferFee":{"type":"string","description":"Taxa de saque cobrada por cima do valor. \"0.00\" em saques anteriores à FIN-45"},"totalDebited":{"type":"string","description":"amount + transferFee: o que saiu do saldo"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payouts/{id}":{"get":{"operationId":"getCommunitiesByCommunityIdPayoutsById","tags":["Payouts"],"summary":"Consulta :id","description":"Exige autenticação e papel financeiro (owner, admin ou finance) na comunidade do X-CommunityId. O saque é buscado só dentro dessa comunidade: o id de um saque de outra comunidade responde 404, igual a um id inexistente (SEC-13).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/payouts/{id}/cancel":{"post":{"operationId":"postCommunitiesByCommunityIdPayoutsByIdCancel","tags":["Payouts"],"summary":"Executa :id cancel","description":"Cancela um saque PENDING. Exige autenticação e papel owner ou admin na comunidade do X-CommunityId. O saque é buscado só dentro dessa comunidade: o id de um saque de outra comunidade responde 404 e nada é alterado (SEC-13). Saque fora de PENDING responde 400.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Saque cancelado; o valor volta ao saldo disponível.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/members/me/payment-methods":{"get":{"tags":["Members"],"summary":"Lista members","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getMembersMePaymentMethods"},"post":{"tags":["Members"],"summary":"Cria ou executa members","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postMembersMePaymentMethods"}},"/api/members/me/payment-methods/{id}/set-default":{"post":{"tags":["Members"],"summary":"Cria ou executa set default","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postMembersMePaymentMethodsByIdSetDefault"}},"/api/members/me/payment-methods/{id}":{"delete":{"tags":["Members"],"summary":"Remove members","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteMembersMePaymentMethodsById"}},"/api/oauth/authorize/info":{"get":{"tags":["MCP"],"summary":"Dados da tela de consentimento do MCP","description":"A tela `/_/mcp/authorize` do app chama esta rota com **exatamente** os parâmetros que recebeu na URL. Valida o pedido (cliente, `redirect_uri`, PKCE) e devolve o nome do cliente, os escopos explicados e as comunidades da pessoa com o papel dela em cada uma. Pedido inválido: 400; quando a `redirect_uri` é confiável, `data.redirectTo` traz o endereço de volta ao cliente com o erro. Requer o token do app; não usa `X-CommunityId`.\n","parameters":[{"in":"query","name":"response_type","required":true,"schema":{"type":"string","enum":["code"]}},{"in":"query","name":"client_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"redirect_uri","required":true,"schema":{"type":"string"}},{"in":"query","name":"code_challenge","required":true,"schema":{"type":"string"}},{"in":"query","name":"code_challenge_method","required":true,"schema":{"type":"string","enum":["S256"]}},{"in":"query","name":"state","schema":{"type":"string"}},{"in":"query","name":"scope","schema":{"type":"string"}},{"in":"query","name":"resource","schema":{"type":"string"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"`data`: `client { name, uri, logoUri }`, `redirectHost`, `scopes [{ key, label }]`, `moneyRequiresConfirmation`, `communities [{ id, name, slug, logoUrl, domain, role }]`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getOauthAuthorizeInfo"}},"/api/oauth/authorize/consent":{"post":{"tags":["MCP"],"summary":"Permitir — liga o assistente à comunidade escolhida","description":"Corpo: os mesmos parâmetros da URL da tela mais `communityId`, que tem de ser uma comunidade em que a pessoa tem perfil (403 se não). Cria a conexão (membro + comunidade + cliente) e devolve `data.redirectTo`, a `redirect_uri` do cliente com `code` e `state`: o app faz `window.location.assign(redirectTo)`. O assistente age com o papel que a pessoa tiver na comunidade **a cada chamada**. Requer o token do app.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","redirect_uri","response_type","code_challenge","code_challenge_method","communityId"],"properties":{"response_type":{"type":"string","enum":["code"]},"client_id":{"type":"string"},"redirect_uri":{"type":"string"},"code_challenge":{"type":"string"},"code_challenge_method":{"type":"string","enum":["S256"]},"state":{"type":"string"},"scope":{"type":"string"},"resource":{"type":"string"},"communityId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"`data`: `{ redirectTo, connectionId }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postOauthAuthorizeConsent"}},"/api/oauth/authorize/deny":{"post":{"tags":["MCP"],"summary":"Cancelar — recusa o pedido de acesso do assistente","description":"Corpo: os mesmos parâmetros da URL da tela. Devolve `data.redirectTo` com `error=access_denied` e o `state`, para o app devolver o navegador ao cliente. Nada é gravado. Requer o token do app.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["client_id","redirect_uri"],"properties":{"client_id":{"type":"string"},"redirect_uri":{"type":"string"},"state":{"type":"string"}}}}}},"responses":{"200":{"description":"`data`: `{ redirectTo }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"operationId":"postOauthAuthorizeDeny"}},"/api/oauth/connections":{"get":{"tags":["MCP"],"summary":"Assistentes conectados (MCP)","description":"Sem parâmetro: as conexões ativas da própria pessoa, em todas as comunidades. `?scope=community`: todas as conexões ativas da comunidade do `X-CommunityId`, só para owner e admin (403 para os demais). Cada item: `id`, `clientName`, `clientUri`, `scope`, `community { id, name, slug }`, `member { id, fullName }`, `createdAt`, `lastUsedAt`.\n","parameters":[{"in":"query","name":"scope","schema":{"type":"string","enum":["community"]}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Lista de conexões.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"operationId":"getOauthConnections"}},"/api/oauth/connections/{id}":{"delete":{"tags":["MCP"],"summary":"Desconectar um assistente (revoga a conexão MCP)","description":"A pessoa revoga a própria conexão; owner e admin do `X-CommunityId` revogam qualquer conexão daquela comunidade. Todos os tokens morrem na hora. Conexão de outra pessoa fora desse caso: 404.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"`data`: `{ id, revoked: true }`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"operationId":"deleteOauthConnectionsById"}},"/api/oauth/connections/{id}/diagnostics":{"get":{"tags":["MCP"],"summary":"Diagnóstico de uma conexão MCP (versão e lista de ferramentas)","description":"Mostra qual versão do servidor e qual lista de ferramentas uma conexão recebeu por último, comparadas com o que o servidor mandaria agora. Serve para descobrir quando o assistente está com a lista de ferramentas desatualizada (guardada de uma conversa antiga). Só owner e admin do `X-CommunityId` (e SuperAdmin); conexão de outra comunidade: 404. Inclui conexões revogadas. `data.server`: `version` (`<versão do pacote>+<commit curto>`, muda a cada deploy), `commit`, `release` (quando o Heroku informa) e, para conexão ativa, `toolsFingerprint`, `toolCount`, `role` e `scopes` atuais. `lastInitialize`, `lastToolsList`, `lastToolCall` e `lastUnknownTool`: a última linha de auditoria de cada tipo (`at`, `status` e, quando houver, `tool`, `client_name`, `client_version`, `server_version`, `tools_fingerprint`, `tool_count`, `renamed_to`), ou `null`. `listUpToDate`: se o `tools_fingerprint` da última lista entregue bate com o atual (`null` quando não há o que comparar).\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Diagnóstico da conexão.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Diagnóstico da conexão","data":{"connection":{"id":"6f1c2a9e-3b7d-4c51-9a0e-2d8f4b6c1e73","clientName":"Claude","scope":"read write","member":{"id":"0b6e9d2c-7a14-4f3b-8c25-91d0e6a4b3f8","fullName":"Maria Souza"},"createdAt":"2026-10-01T12:00:00.000Z","lastUsedAt":"2026-10-06T20:31:00.000Z","revokedAt":null},"server":{"version":"1.0.0+4a9b547","commit":"4a9b547e0c1d2f3a4b5c6d7e8f9a0b1c2d3e4f5a","release":null,"toolsFingerprint":"3f9a1c0b7e2d","toolCount":102,"role":"owner","scopes":["read","write"]},"lastInitialize":{"at":"2026-10-06T17:10:00.000Z","status":"ok","client_name":"claude-ai","client_version":"0.1.0","protocol_version":"2025-06-18","server_version":"1.0.0+72fe149","tools_fingerprint":"8d41e07a9c35","tool_count":96},"lastToolsList":{"at":"2026-10-06T17:10:01.000Z","status":"ok","server_version":"1.0.0+72fe149","tools_fingerprint":"8d41e07a9c35","tool_count":96},"lastToolCall":{"at":"2026-10-06T17:15:00.000Z","status":"ok","tool":"list_members"},"lastUnknownTool":null,"listUpToDate":false}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"operationId":"getOauthConnectionsByIdDiagnostics"}},"/api/oauth/audit":{"get":{"tags":["MCP"],"summary":"Auditoria do MCP na comunidade","description":"Cada chamada de ferramenta e cada evento de conexão (autorizou, revogou, refresh reapresentado) da comunidade do `X-CommunityId`, do mais novo para o mais antigo. Só owner e admin. Filtro opcional por `connectionId`. Também registra `session.initialize` e `tools.list` (em `args`: `client_name`, `client_version`, `server_version`, `tools_fingerprint`, `tool_count`) e `tool.unknown`, quando o assistente chama uma ferramenta que não está na lista da conexão (`status` `stale_list` ou `not_available`; `args.renamed_to` quando é um nome antigo em português).\n","parameters":[{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"connectionId","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Linhas de auditoria, paginadas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"operationId":"getOauthAudit"}},"/.well-known/oauth-protected-resource":{"get":{"tags":["MCP"],"summary":"Metadados do recurso protegido (o servidor MCP)","description":"RFC 9728. Diz ao cliente MCP qual é o recurso (`{origem}/mcp`), quem o autoriza (esta própria API) e quais escopos existem (`read`, `write`). Também responde em `/.well-known/oauth-protected-resource/mcp`. Público.\n","responses":{"200":{"description":"Metadados no formato da RFC 9728 (fora do envelope da API)."}},"operationId":"getWellKnownOauthProtectedResource"}},"/.well-known/oauth-authorization-server":{"get":{"tags":["MCP"],"summary":"Metadados do servidor de autorização OAuth 2.1","description":"RFC 8414. Endpoints de autorização, token, registro dinâmico e revogação. PKCE só `S256`. Também responde em `/.well-known/openid-configuration` para clientes que só procuram lá. Público.\n","responses":{"200":{"description":"Metadados no formato da RFC 8414 (fora do envelope da API)."}},"operationId":"getWellKnownOauthAuthorizationServer"}},"/oauth/register":{"post":{"tags":["MCP"],"summary":"Registro dinâmico de cliente OAuth (RFC 7591)","description":"É assim que o Claude, o ChatGPT e o Cursor se registram sozinhos, sem chave para copiar. `redirect_uris` obrigatório: `https://` qualquer, `http://` só em `localhost`. `token_endpoint_auth_method` `none` (padrão, cliente público com PKCE), `client_secret_post` ou `client_secret_basic` (o segredo volta uma única vez). Limite de 20 registros por hora por IP. Público.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["redirect_uris"],"properties":{"redirect_uris":{"type":"array","items":{"type":"string"}},"client_name":{"type":"string"},"client_uri":{"type":"string"},"logo_uri":{"type":"string"},"token_endpoint_auth_method":{"type":"string","enum":["none","client_secret_post","client_secret_basic"]},"grant_types":{"type":"array","items":{"type":"string","enum":["authorization_code","refresh_token"]}}}}}}},"responses":{"201":{"description":"Cliente registrado (formato da RFC 7591, fora do envelope da API)."},"400":{"description":"`{ error, error_description }` — `invalid_redirect_uri` ou `invalid_client_metadata`."},"429":{"description":"Limite de registros atingido."}},"operationId":"postOauthRegister"}},"/oauth/authorize":{"get":{"tags":["MCP"],"summary":"Início da autorização OAuth (abre a tela de consentimento do app)","description":"Valida o cliente, a `redirect_uri` (tem de ser uma das registradas), `response_type=code` e o PKCE (`code_challenge` com `code_challenge_method=S256`, obrigatório). Válido, redireciona (302) para a tela de consentimento do app (`{app}/_/mcp/authorize`) com os mesmos parâmetros. Cliente ou `redirect_uri` inválidos: 400, sem redirecionar. Os demais erros voltam para a `redirect_uri` com `error` e `state`. Público.\n","parameters":[{"in":"query","name":"response_type","required":true,"schema":{"type":"string","enum":["code"]}},{"in":"query","name":"client_id","required":true,"schema":{"type":"string"}},{"in":"query","name":"redirect_uri","required":true,"schema":{"type":"string"}},{"in":"query","name":"code_challenge","required":true,"schema":{"type":"string"}},{"in":"query","name":"code_challenge_method","required":true,"schema":{"type":"string","enum":["S256"]}},{"in":"query","name":"state","schema":{"type":"string"}},{"in":"query","name":"scope","schema":{"type":"string","example":"read write"}},{"in":"query","name":"resource","schema":{"type":"string"}}],"responses":{"302":{"description":"Para a tela de consentimento do app, ou de volta ao cliente com `error`."},"400":{"description":"Cliente desconhecido ou `redirect_uri` não registrada."}},"operationId":"getOauthAuthorize"}},"/oauth/token":{"post":{"tags":["MCP"],"summary":"Emite e renova tokens OAuth do MCP","description":"`grant_type=authorization_code` troca o código pelo par de tokens, conferindo o PKCE (`code_verifier`) e a `redirect_uri`. `grant_type=refresh_token` renova e **gira** o refresh token: reapresentar um já usado revoga a conexão inteira. Access token de 1 hora, refresh de 30 dias, ambos opacos e presos à conexão (membro + comunidade). Aceita `application/x-www-form-urlencoded` ou JSON. Limite de 60 por minuto por IP. Público.\n","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["grant_type","client_id"],"properties":{"grant_type":{"type":"string","enum":["authorization_code","refresh_token"]},"client_id":{"type":"string"},"client_secret":{"type":"string"},"code":{"type":"string"},"redirect_uri":{"type":"string"},"code_verifier":{"type":"string"},"refresh_token":{"type":"string"},"resource":{"type":"string"}}}}}},"responses":{"200":{"description":"`{ access_token, token_type: Bearer, expires_in, refresh_token, scope }`."},"400":{"description":"`{ error, error_description }` — `invalid_grant`, `invalid_request`, `unsupported_grant_type`."},"401":{"description":"`invalid_client`."}},"operationId":"postOauthToken"}},"/oauth/revoke":{"post":{"tags":["MCP"],"summary":"Revoga um token do MCP (RFC 7009)","description":"Revogar o access token ou o refresh token revoga a conexão inteira: o assistente para de enxergar a comunidade na hora. Token desconhecido também responde 200, como manda a RFC.\n","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","required":["token","client_id"],"properties":{"token":{"type":"string"},"token_type_hint":{"type":"string","enum":["access_token","refresh_token"]},"client_id":{"type":"string"},"client_secret":{"type":"string"}}}}}},"responses":{"200":{"description":"Revogado (ou já não valia)."},"401":{"description":"`invalid_client`."}},"operationId":"postOauthRevoke"}},"/api/notification-settings":{"get":{"tags":["Communities"],"operationId":"getNotificationSettings","summary":"Para onde vão os avisos da comunidade","description":"O e-mail que recebe os avisos de venda, estorno e chargeback da comunidade do header `X-CommunityId`. `null` quer dizer que os avisos vão para o e-mail da empresa (BusinessInformation) e, sem ele, para o e-mail do owner. Só owner e admin.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Configuração lida","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"data":{"type":"object","properties":{"salesNotificationEmail":{"type":"string","format":"email","nullable":true}}}}}}}},"401":{"description":"Sem autenticação"},"403":{"description":"Não é owner nem admin da comunidade"}}},"put":{"tags":["Communities"],"operationId":"updateNotificationSettings","summary":"Define o e-mail dos avisos de venda da comunidade","description":"Grava o e-mail que recebe os avisos de venda, estorno e chargeback. `null` ou string vazia limpa o campo, e os avisos voltam para o e-mail da empresa e, sem ele, para o do owner. Só owner e admin.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"salesNotificationEmail":"vendas@memberfy.net"},"schema":{"type":"object","properties":{"salesNotificationEmail":{"type":"string","format":"email","nullable":true}}}}}},"responses":{"200":{"description":"Configuração gravada"},"400":{"description":"E-mail inválido"},"401":{"description":"Sem autenticação"},"403":{"description":"Não é owner nem admin da comunidade"}}}},"/api/moderation/stats":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta stats","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationStats"}},"/api/moderation/contents/pending":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta pending","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationContentsPending"}},"/api/moderation/contents/{id}":{"put":{"tags":["Moderation"],"summary":"Atualiza contents","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putModerationContentsById"}},"/api/moderation/courses/pending":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta pending","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationCoursesPending"}},"/api/moderation/courses/{id}":{"put":{"tags":["Moderation"],"summary":"Atualiza courses","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putModerationCoursesById"}},"/api/moderation/events/pending":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta pending","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationEventsPending"}},"/api/moderation/events/{id}":{"put":{"tags":["Moderation"],"summary":"Atualiza events","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putModerationEventsById"}},"/api/moderation/gallery/pending":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta pending","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationGalleryPending"}},"/api/moderation/gallery/{id}":{"put":{"tags":["Moderation"],"summary":"Atualiza gallery","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putModerationGalleryById"}},"/api/moderation/status/pending":{"get":{"tags":["Moderation"],"summary":"Lista ou consulta pending","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getModerationStatusPending"}},"/api/moderation/status/{id}":{"put":{"tags":["Moderation"],"summary":"Atualiza status","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putModerationStatusById"}},"/api/member-groups":{"get":{"tags":["Hierarquia"],"summary":"Lista os grupos de membros da comunidade","description":"Departamentos, áreas, squads e comitês, com a contagem de pessoas em cada um. Um grupo é um dos dois eixos do organograma; o outro é quem responde a quem.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getMemberGroups"},"post":{"tags":["Hierarquia"],"summary":"Cria um grupo de membros","description":"O nome é único dentro da comunidade. `parentGroupId` permite diretoria → área → squad; um pai que fechasse o ciclo é recusado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500},"parentGroupId":{"type":"string","format":"uuid","nullable":true},"leaderProfileId":{"type":"string","format":"uuid","nullable":true},"color":{"type":"string","example":"#FF6500","description":"Hex de 6 dígitos com #"},"order":{"type":"integer","minimum":0},"isDefault":{"type":"boolean","description":"Todo mundo entra neste grupo: ao marcar, os perfis existentes entram na hora e todo perfil novo passa a entrar junto. Desmarcar nao remove ninguem."}}}}}},"responses":{"201":{"description":"Grupo criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postMemberGroups"}},"/api/member-groups/{id}":{"put":{"tags":["Hierarquia"],"summary":"Atualiza um grupo de membros","description":"Renomeia, troca o líder, muda a cor ou move o grupo para outro pai. Mover para dentro de um descendente é recusado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500,"nullable":true},"parentGroupId":{"type":"string","format":"uuid","nullable":true},"leaderProfileId":{"type":"string","format":"uuid","nullable":true},"color":{"type":"string","nullable":true},"order":{"type":"integer","minimum":0},"isDefault":{"type":"boolean","description":"Todo mundo entra neste grupo: ao marcar, os perfis existentes entram na hora e todo perfil novo passa a entrar junto. Desmarcar nao remove ninguem."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putMemberGroupsById"},"delete":{"tags":["Hierarquia"],"summary":"Remove um grupo de membros","description":"Soft delete. Os vínculos das pessoas com este grupo são desfeitos, e os grupos filhos sobem para o pai deste — a mesma política usada quando um líder sai, para não deixar buraco no organograma.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteMemberGroupsById"}},"/api/members/profile":{"put":{"tags":["Members"],"summary":"Atualiza profile","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fullName":{"type":"string","description":"Full name cannot be empty"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putMembersProfile"}},"/api/members/{id}":{"get":{"tags":["Members"],"summary":"Detalha members por id","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getMembersById"}},"/mcp":{"post":{"tags":["MCP"],"summary":"Servidor MCP do Memberfy (Streamable HTTP)","description":"Endpoint do Model Context Protocol para o Claude, o ChatGPT, o Cursor e qualquer cliente MCP. Corpo e resposta são JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`…), sem sessão. Exige `Authorization: Bearer` com o access token do OAuth (`/oauth/token`); sem ele, 401 com `WWW-Authenticate` apontando para `/.well-known/oauth-protected-resource/mcp`. O token está preso a uma comunidade e o assistente age com o papel atual de quem conectou: as ferramentas chamam as mesmas rotas da API, com as mesmas regras. Dinheiro (cupom, preço, saque, cancelamento) pede confirmação em duas chamadas. Limite de 120 chamadas de ferramenta por minuto por conexão. Nomes de ferramentas e argumentos são identificadores em inglês (`snake_case`, ex.: `create_course`, `sales_report`); títulos, resumos e mensagens saem no idioma do membro conectado (senão o da comunidade, senão en-US). Respostas podem trazer `next_steps` (até três próximas ações que o papel pode executar), e o servidor expõe prompts prontos (`prompts/list`) conforme o papel. `serverInfo.version` é `<versão do pacote>+<commit curto>` e muda a cada deploy. O resultado de `initialize` e o de `tools/list` trazem `_meta.memberfy` com `server_version`, `tools_fingerprint` (hash curto dos nomes e dos esquemas de entrada da lista que esta conexão recebe) e `tool_count`; as instruções do servidor terminam com uma linha que repete a versão da lista. Chamar uma ferramenta fora da lista da conexão devolve um erro de ferramenta (`isError`) pedindo para a pessoa abrir uma nova conversa ou reconectar o conector; se o nome é um dos antigos em português, a resposta traz `renamed_to` com o nome novo.\n","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Mensagem JSON-RPC 2.0 do MCP"}}}},"responses":{"200":{"description":"Resposta JSON-RPC (fora do envelope da API)."},"401":{"description":"Sem token, ou token inválido, vencido ou revogado."},"429":{"description":"Limite de requisições da conexão."}},"operationId":"postMcp"}},"/api/ledger":{"get":{"operationId":"getCommunitiesByCommunityIdLedger","tags":["Ledger"],"summary":"Consulta ledger","description":"Exige autenticação — aplicada a todas as rotas deste router.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}},{"in":"query","name":"entryType","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/ledger/balance":{"get":{"operationId":"getCommunitiesByCommunityIdLedgerBalance","tags":["Ledger"],"summary":"Consulta balance","description":"Exige autenticação e papel financeiro (owner, admin ou finance) na comunidade do X-CommunityId. Além do saldo, devolve a taxa de saque vigente (`transferFee`, cobrada por cima do valor pedido) e o maior valor que pode ser sacado agora (`maxPayoutAmount` = available − transferFee, mínimo 0), para a tela mostrar a taxa antes de confirmar (FIN-45).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Saldo e taxa de saque.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"total":{"type":"number"},"available":{"type":"number"},"retained":{"type":"number"},"pending":{"type":"number"},"currency":{"type":"string"},"transferFee":{"type":"number","description":"Taxa de saque da plataforma. Ex.: 3.67"},"maxPayoutAmount":{"type":"number","description":"available − transferFee, mínimo 0"},"fetchedAt":{"type":"string"},"timestamp":{"type":"integer"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/import/substack":{"post":{"tags":["Import"],"summary":"Cria ou executa substack","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Valid Space ID is required"},"visibility":{"type":"string","enum":["public","members","plan"],"description":"Invalid visibility"},"autoPublish":{"type":"boolean","description":"autoPublish must be boolean"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postImportSubstack"}},"/api/import/{importId}":{"get":{"tags":["Import"],"summary":"Detalha import por id","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"importId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getImportByImportId"},"delete":{"tags":["Import"],"summary":"Remove import","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"importId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteImportByImportId"}},"/api/import":{"get":{"tags":["Import"],"summary":"Lista import","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"},"description":"Page must be a positive integer"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"Limit must be between 1 and 100"},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["PENDING","EXTRACTING","IMPORTING","COMPLETED","FAILED","CANCELLED"]},"description":"Invalid status"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getImport"}},"/api/hierarchy/org-chart":{"get":{"tags":["Hierarquia"],"summary":"Devolve o organograma da comunidade","description":"Lista **plana** de nós, cada um com o seu `reportsToId` — a árvore e o canvas montam a sua forma a partir dela em uma passada. Nunca carrega a comunidade inteira por padrão: começa de uma pessoa (`rootProfileId`) ou de um grupo (`groupId`), desce `depth` níveis e para no teto de `limit`, devolvendo `truncated: true` em vez de cortar em silêncio. Cada nó traz `hasUnloadedReports`, que é o que diz à tela se a caixa ainda abre.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"rootProfileId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Começa o desenho nesta pessoa. Sem ele, começa por quem não responde a ninguém."},{"in":"query","name":"groupId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Desenha só um grupo: quem está nele, tendo como raiz quem responde a alguém de fora."},{"in":"query","name":"depth","required":false,"schema":{"type":"integer","minimum":1,"maximum":10,"default":2}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":2000,"default":500}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getHierarchyOrgChart"}},"/api/hierarchy/profiles/{id}":{"put":{"tags":["Hierarquia"],"summary":"Define o líder e os grupos de um perfil","description":"Campo omitido fica como está; `reportsToId: null` transforma a pessoa em raiz. `groupIds` é o conjunto inteiro, não um acréscimo — é o que permite a tela tirar alguém de um grupo. `primaryGroupId` decide qual grupo nomeia e colore a caixa no organograma; omitido, vale o primeiro da lista. Recusa ciclo (A responde a B, B responde a A), perfil de outra comunidade e responder a si mesmo.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reportsToId":{"type":"string","format":"uuid","nullable":true},"groupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"primaryGroupId":{"type":"string","format":"uuid","nullable":true}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putHierarchyProfilesById"}},"/api/hierarchy/profiles/{id}/direct-reports-count":{"get":{"tags":["Hierarquia"],"summary":"Quantas pessoas respondem diretamente a este perfil","description":"Serve ao aviso antes de remover alguém: quem responde ao removido sobe um nível, e a tela precisa dizer quantos antes de confirmar.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getHierarchyProfilesByIdDirectReportsCount"}},"/api/gamification":{"get":{"tags":["Gamification"],"summary":"Lista gamification","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGamification"}},"/api/gamification/config":{"get":{"tags":["Gamification"],"summary":"Consulta a configuração de gamificação","description":"Se a gamificação está ligada (`isEnabled`) e quantos pontos vale cada ação\n(`actionRules`: `{ CREATE_POST: { points, isActive } }`) na comunidade do `X-CommunityId`.\nHoje responde a qualquer usuário autenticado; o app só a chama na aba de gamificação de\nMembros (owner e admin). Para a tela de ranking, use `GET /api/gamification`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGamificationConfig"},"put":{"tags":["Gamification"],"summary":"Atualiza a configuração de gamificação","description":"Exige owner ou admin da comunidade do `X-CommunityId`. `isEnabled` liga ou desliga o\nranking; `actionRules` mapeia o tipo de ação para os pontos que ela vale\n(`{ \"CREATE_POST\": 10 }`) — os tipos que ficam de fora mantêm a pontuação atual.\nAs mensagens de resposta e de validação vêm no idioma do `Accept-Language`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"isEnabled":true,"actionRules":{"CREATE_POST":10,"COMMENT_POST":5,"LIKE_POST":1,"DAILY_LOGIN":2}},"schema":{"type":"object","properties":{"isEnabled":{"type":"boolean","description":"Liga ou desliga a gamificação na comunidade."},"actionRules":{"type":"object","description":"Pontos por tipo de ação (CREATE_POST, LIKE_POST, COMMENT_POST, REPLY_COMMENT, RECEIVE_LIKE, CREATE_EVENT, PARTICIPATE_EVENT, CREATE_COURSE, ENROLL_COURSE, COMPLETE_LESSON, DAILY_LOGIN).","additionalProperties":{"type":"integer","minimum":0}}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putGamificationConfig"}},"/api/gamification/leaderboard":{"get":{"tags":["Gamification"],"summary":"Lista ou consulta leaderboard","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGamificationLeaderboard"}},"/api/gamification/score":{"get":{"tags":["Gamification"],"summary":"Lista ou consulta score","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGamificationScore"}},"/api/gamification/actions":{"get":{"tags":["Gamification"],"summary":"Lista ou consulta actions","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGamificationActions"}},"/api/gamification/recalculate/{profileId}":{"post":{"tags":["Gamification"],"summary":"Cria ou executa recalculate","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"profileId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postGamificationRecalculateByProfileId"}},"/api/gamification/track":{"post":{"tags":["Gamification"],"summary":"Cria ou executa track","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["profileId","communityId","actionType"],"properties":{"profileId":{"type":"string","description":"profileId é obrigatório"},"communityId":{"type":"string","description":"communityId é obrigatório"},"actionType":{"type":"string","description":"actionType é obrigatório"},"targetId":{"type":"string"},"targetType":{"type":"string"},"sectionId":{"type":"string","format":"uuid","description":"sectionId deve ser um UUID válido"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postGamificationTrack"}},"/api/gallery/images":{"get":{"tags":["Gallery"],"summary":"Lista ou consulta images","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado. O space precisa ser da comunidade do `X-CommunityId`; space de outra comunidade (ou requisição sem o header) responde 404, como se não existisse.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID is required"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"},"description":"Page must be a positive integer"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"Limit must be between 1 and 50"},{"in":"query","name":"sortBy","required":false,"schema":{"type":"string","enum":["createdAt","views","likes","title"]},"description":"Invalid sort field"},{"in":"query","name":"order","required":false,"schema":{"type":"string","enum":["asc","desc"]},"description":"Order must be asc or desc"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"Space não encontrado: não existe, foi removido ou é de outra comunidade que não a do `X-CommunityId`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Space not found","errors":[{"message":"Space not found"}]}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGalleryImages"}},"/api/gallery/images/{imageId}":{"get":{"tags":["Gallery"],"summary":"Lista ou consulta images","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado. A imagem precisa estar num space da comunidade do `X-CommunityId`; senão a resposta é 404.","security":[],"parameters":[{"in":"path","name":"imageId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"Imagem não encontrada: não existe, foi removida ou está num space de outra comunidade que não a do `X-CommunityId` (nesse caso a resposta é a mesma, para não revelar que a imagem existe).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Gallery image not found","errors":[{"message":"Gallery image not found"}]}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getGalleryImagesByImageId"},"put":{"tags":["Gallery"],"summary":"Atualiza images","description":"Edita título, descrição e tags. Pode o autor da imagem ou quem é owner, admin ou moderator da comunidade. A imagem precisa estar num space da comunidade do `X-CommunityId`; senão a resposta é 404.","parameters":[{"in":"path","name":"imageId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":255,"description":"Title must be between 1 and 255 characters"},"description":{"type":"string","maxLength":2000,"description":"Description must be at most 2000 characters"},"tags":{"type":"array","description":"Tags must be an array"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Imagem não encontrada: não existe, foi removida ou está num space de outra comunidade que não a do `X-CommunityId` (nesse caso a resposta é a mesma, para não revelar que a imagem existe).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Gallery image not found","errors":[{"message":"Gallery image not found"}]}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putGalleryImagesByImageId"},"delete":{"tags":["Gallery"],"summary":"Remove images","description":"Remove a imagem (soft delete). Pode o autor da imagem ou quem é owner, admin ou moderator da comunidade. A imagem precisa estar num space da comunidade do `X-CommunityId`; senão a resposta é 404.","parameters":[{"in":"path","name":"imageId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Imagem não encontrada: não existe, foi removida ou está num space de outra comunidade que não a do `X-CommunityId` (nesse caso a resposta é a mesma, para não revelar que a imagem existe).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Gallery image not found","errors":[{"message":"Gallery image not found"}]}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteGalleryImagesByImageId"}},"/api/gallery/images/{imageId}/react":{"post":{"tags":["Gallery"],"summary":"Cria ou executa react","description":"Alterna a reação do membro na imagem. A imagem precisa estar num space da comunidade do `X-CommunityId`; senão a resposta é 404.","parameters":[{"in":"path","name":"imageId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reaction"],"properties":{"reaction":{"type":"string","enum":["celebrate","love","like","fire","clap","smile","raise_hands"],"description":"Valid reaction is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Imagem não encontrada: não existe, foi removida ou está num space de outra comunidade que não a do `X-CommunityId` (nesse caso a resposta é a mesma, para não revelar que a imagem existe).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Gallery image not found","errors":[{"message":"Gallery image not found"}]}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postGalleryImagesByImageIdReact"}},"/api/feed":{"get":{"tags":["Feed"],"summary":"Lista feed","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}},{"in":"query","name":"type","required":false,"schema":{"type":"string","enum":["all","status","content","event","events","course","courses","call4papers"]}},{"in":"query","name":"visibility","required":false,"schema":{"type":"string","enum":["public","members","all"]}},{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"communityId","required":false,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getFeed"}},"/api/feed/stats":{"get":{"tags":["Feed"],"summary":"Lista ou consulta stats","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"communityId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid community ID is required"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getFeedStats"}},"/api/feed/recommendations":{"get":{"tags":["Feed"],"summary":"Lista ou consulta recommendations","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"communityId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid community ID is required"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getFeedRecommendations"}},"/api/feed/{type}/{id}/react":{"post":{"tags":["Feed"],"summary":"Cria ou executa react","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["👍","❤️","🔥","🙌","😊","👏","🎉"],"description":"Invalid reaction type"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postFeedByTypeByIdReact"}},"/api/feed/{type}/{id}/comment":{"post":{"tags":["Feed"],"summary":"Cria ou executa comment","description":"O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["content"],"properties":{"content":{"type":"string","minLength":1,"maxLength":2000,"description":"Comment content is required and must be between 1 and 2000 characters"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postFeedByTypeByIdComment"}},"/api/feed/{type}/{id}/pin":{"put":{"tags":["Feed"],"summary":"Atualiza pin","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"type","required":true,"schema":{"type":"string"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["pinned"],"properties":{"pinned":{"type":"boolean","description":"pinned must be a boolean value"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putFeedByTypeByIdPin"}},"/api/fees":{"get":{"operationId":"getCommunitiesByCommunityIdFees","tags":["Payouts"],"summary":"Taxas da comunidade","description":"A taxa da plataforma que vale para a comunidade (o override dela, campo a campo\nsobre a regra da plataforma), limites de saque, métodos de pagamento e exemplos.\nF-43: `installmentRates` traz os juros de parcelamento da Memberfy no cartão, % total\nsobre o valor por número de parcelas (`{ \"2\": \"4.29\", ..., \"12\": \"6.00\" }`; 1× é 0).\n`examples` traz \"PIX R$ 100\", \"Cartão 1x R$ 300\" e, com juros pagos pelo comprador,\n\"Cartão 6x R$ 300\" e \"Cartão 12x R$ 300\" (estes com `installments`,\n`installmentInterestPercent`, `installmentInterest`, `totalWithInterest` e\n`installmentAmount`).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/fees/simulate":{"post":{"operationId":"postCommunitiesByCommunityIdFeesSimulate","tags":["Payouts"],"summary":"Simula a taxa e os juros de parcelamento de uma venda da comunidade","description":"Mesmo cálculo do checkout (`calculateFees`). Com `installments` > 1 no cartão, a resposta\ntraz os juros de parcelamento da Memberfy (F-43): `installmentInterestPayer`,\n`installmentInterestPercent`, `installmentInterest` (o que o comprador paga de juros;\n`0.00` quando a comunidade absorve), `totalWithInterest` e `installmentAmount`, além do\nobjeto `installmentInterest` dentro do cálculo. `feePayer` e `installmentInterestPayer`\naceitam `ORGANIZATION`/`BUYER` (e os nomes antigos `COMMUNITY`/`CUSTOMER`); o padrão dos\ndois é `BUYER`, como num produto. Nunca traz custo do provedor.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","paymentMethod"],"properties":{"amount":{"type":"number","description":"Amount must be greater than 0"},"paymentMethod":{"type":"string","enum":["PIX","CREDIT_CARD","DEBIT_CARD","BOLETO"],"description":"Invalid payment method"},"installments":{"type":"integer","description":"Installments must be between 1 and 12"},"feePayer":{"type":"string","enum":["ORGANIZATION","BUYER","COMMUNITY","CUSTOMER"],"description":"Quem paga a taxa da plataforma; padrão BUYER"},"installmentInterestPayer":{"type":"string","enum":["ORGANIZATION","BUYER","COMMUNITY","CUSTOMER"],"description":"Quem paga os juros de parcelamento; padrão BUYER"},"currency":{"type":"string","enum":["BRL","USD","EUR"],"description":"Invalid currency"},"countryCode":{"type":"string","minLength":2,"maxLength":2,"description":"Country code must be 2 characters"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/events/categories":{"get":{"tags":["Events"],"summary":"Lista ou consulta categories","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID required if provided"},{"in":"query","name":"filter","required":false,"schema":{"type":"string","enum":["next","my","past","all"]},"description":"Filter must be one of: next, my, past, all"},{"in":"query","name":"search","required":false,"schema":{"type":"string"},"description":"Search must be a string"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getEventsCategories"}},"/api/events":{"post":{"tags":["Events"],"summary":"Cria ou executa events","description":"Sujeito a verificação de papel (RBAC). Além disso, respeita o\n`canCreate` do space: `staff` aceita owner, admin e moderator;\n`admins` aceita owner e admin; `anyone` não restringe. Fora da\nregra, 403 com `errors[0].param = \"spaceId\"`. SuperAdmin sempre passa.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","title"],"properties":{"spaceId":{"type":"string","format":"uuid","description":"Valid space ID required if provided"},"slug":{"type":"string","description":"Slug is required"},"title":{"type":"string","description":"Title is required"},"type":{"type":"string","enum":["online","hybrid","in_person"],"description":"Type must be online, hybrid, or in_person"},"location":{"type":"string","description":"Location must be a string"},"placeId":{"type":"string","description":"Place ID must be a string"},"street":{"type":"string","description":"Street must be a string"},"number":{"type":"string","description":"Number must be a string"},"neighborhood":{"type":"string","description":"Neighborhood must be a string"},"city":{"type":"string","description":"City must be a string"},"state":{"type":"string","description":"State must be a string"},"country":{"type":"string","description":"Country must be a string"},"postalCode":{"type":"string","description":"Postal code must be a string"},"latitude":{"type":"number","description":"Latitude must be a number"},"longitude":{"type":"number","description":"Longitude must be a number"},"streamingUrl":{"type":"string","format":"uri","description":"Streaming URL must be valid"},"streamingService":{"type":"string","enum":["youtube","vimeo","mux"],"description":"Streaming service must be youtube, vimeo, or mux"},"bannerUrl":{"type":"string","format":"uri","description":"Banner URL must be valid"},"featuredImageUrl":{"type":"string","format":"uri","description":"Featured image URL must be valid"},"videoTeaserUrl":{"type":"string","format":"uri","description":"Video teaser URL must be valid"},"hostIds":{"type":"array","description":"hostIds must be an array"},"hostIds.*":{"type":"string","format":"uuid","description":"Each hostId must be a valid UUID"},"organizerIds":{"type":"array","description":"organizerIds must be an array"},"organizerIds.*":{"type":"string","format":"uuid","description":"Each organizerId must be a valid UUID"},"timezone":{"type":"string","description":"Timezone must be a string"},"audience":{"type":"string","description":"Audience must be a string"},"visibility":{"type":"string","enum":["public","members","plan"],"description":"Visibility must be public, members, or plan"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postEvents"}},"/api/events/{identifier}":{"get":{"tags":["Events"],"summary":"Detalha events por id","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"in":"path","name":"identifier","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID required if provided"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getEventsByIdentifier"}},"/api/events/{id}":{"put":{"tags":["Events"],"summary":"Atualiza events","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Valid space ID required if provided"},"hostIds":{"type":"array","description":"hostIds must be an array"},"hostIds.*":{"type":"string","format":"uuid","description":"Each hostId must be a valid UUID"},"organizerIds":{"type":"array","description":"organizerIds must be an array"},"organizerIds.*":{"type":"string","format":"uuid","description":"Each organizerId must be a valid UUID"},"visibility":{"type":"string","enum":["public","members","plan"],"description":"Visibility must be public, members, or plan"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putEventsById"},"delete":{"tags":["Events"],"summary":"Remove events","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteEventsById"}},"/api/events/{id}/participate":{"post":{"tags":["Events"],"summary":"Cria ou executa participate","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["going","maybe","not_going"],"description":"Valid status is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postEventsByIdParticipate"}},"/api/events/{id}/participants":{"get":{"tags":["Events"],"summary":"Lista ou consulta participants","description":"Endpoint público — não exige autenticação.","security":[],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["going","maybe"]},"description":"Valid status is required"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getEventsByIdParticipants"}},"/api/events/{id}/start-stream":{"post":{"tags":["Events"],"summary":"Cria ou executa start stream","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"streamingUrl":{"type":"string","format":"uri","description":"Streaming URL must be valid"},"streamingService":{"type":"string","enum":["youtube","vimeo","mux"],"description":"Streaming service must be youtube, vimeo, or mux"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postEventsByIdStartStream"}},"/api/events/{id}/stop-stream":{"post":{"tags":["Events"],"summary":"Cria ou executa stop stream","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postEventsByIdStopStream"}},"/api/emails/stats":{"get":{"operationId":"getWebhooksEmailStatsByCommunityId","tags":["System"],"summary":"Estatísticas de e-mail da comunidade","description":"Contagem dos e-mails da comunidade do `X-CommunityId`: total, enviados, com falha, pendentes, entregues, abertos, clicados, devolvidos e marcados como spam. Exige owner ou admin dessa comunidade.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscription-groups/{groupId}/downsell-offers":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionGroupsByGroupIdDownsellOffers","tags":["Downsell"],"summary":"Lista as ofertas de downsell do plano, com métricas","description":"F-39. Owner ou admin da comunidade do `X-CommunityId` (e SuperAdmin); plano de outra comunidade responde 404. Cada oferta traz `stats`: `shown` (exibições vistas na tela), `delivered` (disponibilizadas), `accepted` (aceites pagos), `declined`, `expired`, `conversionRate` (aceites / disponibilizadas), `revenueFirstCharge` e `netFirstCharge` (o 1º pagamento, bruto e líquido da comunidade), `revenueTotal` e `netTotal` (com as renovações da assinatura nascida da oferta). Nunca custo do provedor.\n","parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Ofertas do plano.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdSubscriptionGroupsByGroupIdDownsellOffers","tags":["Downsell"],"summary":"Cria uma oferta de downsell para um adicional do plano","description":"F-39. Owner ou admin. Recusas 400 com `errors[].param`: `productId` (fora da lista do plano ou não vendido junto), `discountPercent` (fora de (0, 100)), `timing` (já existe uma IMMEDIATE ativa para o mesmo adicional), `delayMinutes` (ausente em DELAYED, ou fora de 60 min a 90 dias), `priceCycles` (ausente em CYCLES, ou fora de 2 a 36), `ttlMinutes` (fora de 1 h a 30 dias).\n","parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["productId","timing"],"properties":{"productId":{"type":"string","format":"uuid","description":"Adicional da lista do plano, vendido junto (SUBSCRIPTION MONTHLY)"},"discountPercent":{"type":"number","description":"Maior que 0 e menor que 100, até 2 casas. Padrão 10"},"timing":{"type":"string","enum":["IMMEDIATE","DELAYED"]},"delayMinutes":{"type":"integer","nullable":true,"description":"Só em DELAYED: de 60 a 129600 (90 dias)"},"priceDuration":{"type":"string","enum":["FOREVER","FIRST_CHARGE","CYCLES"],"description":"Padrão FOREVER"},"priceCycles":{"type":"integer","nullable":true,"description":"Só em CYCLES: de 2 a 36 cobranças"},"ttlMinutes":{"type":"integer","description":"De 60 a 43200. Padrão 2880 (48 h)"},"isActive":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Oferta criada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/subscription-groups/{groupId}/downsell-offers/{offerId}":{"put":{"operationId":"putCommunitiesByCommunityIdSubscriptionGroupsByGroupIdDownsellOffersByOfferId","tags":["Downsell"],"summary":"Edita uma oferta de downsell","description":"F-39. Owner ou admin. Campos parciais, com as mesmas recusas da criação; o adicional da oferta não muda (400 `productId`). Vale para as exibições criadas daí em diante: quem já recebeu a oferta paga o que leu. Desligar (`isActive: false`) cancela as exibições ainda não mostradas.\n","parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"}},{"in":"path","name":"offerId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"discountPercent":{"type":"number"},"timing":{"type":"string","enum":["IMMEDIATE","DELAYED"]},"delayMinutes":{"type":"integer","nullable":true},"priceDuration":{"type":"string","enum":["FOREVER","FIRST_CHARGE","CYCLES"]},"priceCycles":{"type":"integer","nullable":true},"ttlMinutes":{"type":"integer"},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Oferta atualizada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCommunitiesByCommunityIdSubscriptionGroupsByGroupIdDownsellOffersByOfferId","tags":["Downsell"],"summary":"Exclui uma oferta de downsell","description":"F-39. Owner ou admin. Exclusão lógica; as exibições ainda não mostradas são canceladas, as já disponíveis valem até vencer.\n","parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"}},{"in":"path","name":"offerId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Oferta excluída.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/downsell-impressions/by-token/{token}":{"get":{"tags":["Downsell"],"summary":"Lê a oferta de downsell do link do e-mail","description":"F-39. Sem login: o token do e-mail é a credencial, só desta oferta. Nenhum efeito (nem \"visto\"), porque leitores de e-mail abrem links sozinhos. Traz a cotação (como `POST /:id/quote`, sem cupom), `shortDescription`, `community` (`id`, `name`, `logoUrl`, `themeColor`) e `paymentOptions` (`savedCard` com `brand` e `last4` quando há cartão salvo, `methods`, `defaultMethod`). Token inexistente, vencido ou já usado: 404 com `param = token`. Limite de 30 requisições por IP a cada 15 minutos nas rotas por token (429).\n","security":[],"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"A oferta.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Requisições demais deste IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getDownsellImpressionsByTokenByToken"}},"/api/downsell-impressions/by-token/{token}/seen":{"post":{"tags":["Downsell"],"summary":"Marca como vista a oferta do link do e-mail","description":"F-39. Sem login. Grava `shownAt` uma vez (idempotente). Sem efeito de cobrança.","security":[],"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Marcada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Requisições demais deste IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByTokenByTokenSeen"}},"/api/downsell-impressions/by-token/{token}/accept":{"post":{"tags":["Downsell"],"summary":"Aceita a oferta do link do e-mail","description":"F-39. Sem login. `paymentMethod` opcional: sem ele, o cartão salvo padrão do dono da oferta; `PIX` ou `BOLETO` geram um pedido só do adicional com os dados do pagador do plano. Cartão novo exige login (400 `param = paymentMethod`). Resposta 201 igual à de `POST /:id/accept`. 409 se a oferta deixou de estar disponível no meio do caminho.\n","security":[],"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"paymentMethod":{"type":"string","enum":["CREDIT_CARD","PIX","BOLETO"]}}}}}},"responses":{"201":{"description":"Aceita.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"402":{"description":"Pagamento recusado pelo provedor."},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A oferta não está mais disponível."},"429":{"description":"Requisições demais deste IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByTokenByTokenAccept"}},"/api/downsell-impressions/by-token/{token}/decline":{"post":{"tags":["Downsell"],"summary":"Recusa a oferta do link do e-mail (\"Não, obrigado\")","description":"F-39. Sem login: o token do e-mail é a credencial, só desta oferta. Mesmo efeito de `POST /:id/decline` (status `DECLINED`, conta nas métricas da oferta); uma oferta atrasada do mesmo adicional ainda pode chegar depois. Token inexistente, vencido ou já usado: 404 com `param = token`; oferta que deixou de estar disponível no meio do caminho: 409 com `param = token`. Limite de 30 requisições por IP a cada 15 minutos nas rotas por token (429).\n","security":[],"parameters":[{"in":"path","name":"token","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Recusada (`data` com `id` e `status = DECLINED`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A oferta não está mais disponível."},"429":{"description":"Requisições demais deste IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByTokenByTokenDecline"}},"/api/downsell-impressions":{"get":{"tags":["Downsell"],"summary":"Ofertas de downsell disponíveis para quem está logado","description":"F-39. Exibições `AVAILABLE` e não vencidas do perfil do `X-CommunityId` (uma por adicional, a mais recente), opcionalmente de uma assinatura de plano (`subscriptionId`). Cada uma com `id`, `productId`, `title`, `shortDescription`, `currency`, `interval`, `regularAmount`, `discountPercent`, `discountedPeriodAmount`, `priceDuration`, `priceCycles`, `expiresAt`, `discountEndsAt`, `shownAt` e `quote` (`amountDueNow`, `amountToCharge`, `floorApplied`, `nextChargeDate`: o valor de agora, sem cupom). Sem perfil na comunidade: 403.\n","parameters":[{"in":"query","name":"subscriptionId","schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Ofertas disponíveis.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getDownsellImpressions"}},"/api/downsell-impressions/{id}/seen":{"post":{"tags":["Downsell"],"summary":"Marca a oferta como vista","description":"F-39. Grava `shownAt` quando a tela mostra a oferta (idempotente). Exibição de outra pessoa, 404.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Marcada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByIdSeen"}},"/api/downsell-impressions/{id}/quote":{"post":{"tags":["Downsell"],"summary":"Cota o aceite da oferta, com cupom opcional","description":"F-39. Sem efeito. Valor do período no ritmo do plano → pró-rata até a próxima cobrança (ou nada agora, abaixo do piso de 3 dias ou R$ 10) → menos o downsell → menos o cupom (FIN-7) → taxa da plataforma sobre o resultado, percentual e fixo (pedido à parte; a taxa da plataforma independe do método de pagamento). Resposta: `periodAmount`, `regularAmount`, `discountPercent`, `discountedPeriodAmount`, `prorataAmount`, `floorApplied`, `downsellDiscount`, `couponDiscount`, `discountAmount`, `amountDueNow`, `amountToCharge`, `maxInstallments`, `discountEndsAt`, `nextChargeDate`, `expiresAt`, `feeBreakdown` e `coupon` quando houver. Recusas: 409 oferta não disponível; 400/404 do cupom com `param = couponCode` (inclusive cupom abaixo do piso, onde nada é cobrado agora); 429 depois de 10 cupons recusados em 15 minutos.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"couponCode":{"type":"string"},"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO"]},"installments":{"type":"integer"}}}}}},"responses":{"200":{"description":"Cotação.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A oferta não está mais disponível."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByIdQuote"}},"/api/downsell-impressions/{id}/accept":{"post":{"tags":["Downsell"],"summary":"Aceita a oferta de downsell","description":"F-39. Compra o adicional com o desconto, num pedido à parte: cartão salvo (`paymentMethodId`), cartão novo (`cardToken`), PIX ou boleto; abaixo do piso nada é cobrado agora e o adicional entra com desconto na próxima cobrança do plano. Resposta 201 igual à de `POST /subscriptions/:id/add-ons` (`purchaseId`, `subscriptionId`, `status`, `charged`, `amount`, `currency`, `floorApplied`, `nextChargeDate` e, cobrado, `paymentMethod`, `installments`, `feeBreakdown`, `orderId`, `qrCode`, `pixCode`, `boletoUrl`, `boletoBarcode`) mais `impressionId`, `discountPercent`, `discountEndsAt` e `discountAmount`. A assinatura do adicional nasce no pagamento confirmado, com `regularAmount`, `discountPercent` e `discountEndsAt`. PIX ou boleto não pago devolve a oferta enquanto ela valer. Recusas: 409 oferta não disponível; 400 método/cartão/cupom; 403 (`param = id`) quando a comunidade não tem informações comerciais `APPROVED`; 402/502 do provedor.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO"]},"paymentMethodId":{"type":"string","format":"uuid"},"cardToken":{"type":"string"},"installments":{"type":"integer"},"customerData":{"type":"object"},"couponCode":{"type":"string"}}}}}},"responses":{"201":{"description":"Aceita.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Pagamento recusado pelo provedor."},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A oferta não está mais disponível."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByIdAccept"}},"/api/downsell-impressions/{id}/decline":{"post":{"tags":["Downsell"],"summary":"Recusa a oferta (\"Agora não\")","description":"F-39. A pessoa não vê mais esta oferta; uma oferta atrasada do mesmo adicional ainda pode chegar depois. 409 se ela não está mais disponível.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Recusada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A oferta não está mais disponível."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postDownsellImpressionsByIdDecline"}},"/api/dashboard/monetization":{"get":{"tags":["Dashboard"],"summary":"Lista ou consulta monetization","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getDashboardMonetization"}},"/api/dashboard/customers":{"get":{"tags":["Dashboard"],"summary":"Lista ou consulta customers","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getDashboardCustomers"}},"/api/courses":{"get":{"tags":["Courses"],"summary":"Lista courses","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID required if provided"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCourses"},"post":{"tags":["Courses"],"summary":"Cria ou executa courses","description":"Sujeito a verificação de papel (RBAC). Além disso, respeita o\n`canCreate` do space: `staff` aceita owner, admin e moderator;\n`admins` aceita owner e admin; `anyone` não restringe. Fora da\nregra, 403 com `errors[0].param = \"spaceId\"`. SuperAdmin sempre passa.\nO curso nasce na comunidade do `X-CommunityId`; `communityId` no corpo é\nopcional e, se vier diferente do header, 403 com `param = communityId`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["slug","title","level"],"properties":{"communityId":{"type":"string","format":"uuid","description":"Valid community ID is required"},"spaceId":{"type":"string","format":"uuid","description":"Valid space ID required if provided"},"slug":{"type":"string","description":"Slug is required"},"title":{"type":"string","description":"Title is required"},"level":{"type":"string","enum":["beginner","intermediate","advanced"],"description":"Valid course level is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCourses"}},"/api/courses/{identifier}":{"get":{"tags":["Courses"],"summary":"Detalha courses por id","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"in":"path","name":"identifier","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCoursesByIdentifier"}},"/api/courses/{id}":{"put":{"tags":["Courses"],"summary":"Atualiza courses","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCoursesById"},"delete":{"tags":["Courses"],"summary":"Remove courses","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCoursesById"}},"/api/courses/module":{"post":{"tags":["Courses"],"summary":"Cria ou executa module","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["courseId","title"],"properties":{"courseId":{"type":"string","format":"uuid","description":"Valid course ID is required"},"title":{"type":"string","description":"Title is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCoursesModule"}},"/api/courses/lesson":{"post":{"tags":["Courses"],"summary":"Cria ou executa lesson","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["moduleId","title","type"],"properties":{"moduleId":{"type":"string","format":"uuid","description":"Valid module ID is required"},"title":{"type":"string","description":"Title is required"},"type":{"type":"string","enum":["text","image","video","link"],"description":"Valid content type is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCoursesLesson"}},"/api/courses/module/{moduleId}":{"put":{"tags":["Courses"],"summary":"Renomeia ou reordena um módulo do curso","description":"Owner ou admin da comunidade do `X-CommunityId`. O módulo precisa ser de um curso dessa comunidade; de outra, 404. Só muda o que vier no corpo.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"moduleId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":255},"order":{"type":"integer","minimum":0}}},"example":{"title":"Módulo 2 — Fórmulas","order":2}}}},"responses":{"200":{"description":"Módulo atualizado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCoursesModuleByModuleId"},"delete":{"tags":["Courses"],"summary":"Exclui um módulo do curso e as aulas dele","description":"Owner ou admin da comunidade do `X-CommunityId`. Exclusão lógica do módulo e de todas as aulas dele; o progresso de quem já assistiu fica guardado. Módulo de outra comunidade, 404.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"moduleId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Módulo excluído.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCoursesModuleByModuleId"}},"/api/courses/lesson/{lessonId}":{"put":{"tags":["Courses"],"summary":"Edita uma aula (título, tipo, duração, ordem ou módulo)","description":"Owner ou admin da comunidade do `X-CommunityId`. `moduleId` move a aula para outro módulo do mesmo curso (vai para o fim, se `order` não vier). A aula guarda título, tipo e duração; o conteúdo da aula ainda não tem onde ficar no banco. Aula de outra comunidade, 404.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"lessonId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","maxLength":255},"type":{"type":"string","enum":["text","image","video","link"]},"duration":{"type":"string","nullable":true,"maxLength":50},"order":{"type":"integer","minimum":0},"moduleId":{"type":"string","format":"uuid"}}},"example":{"title":"Aula 3 — PROCV na prática","type":"video","duration":"14 min"}}}},"responses":{"200":{"description":"Aula atualizada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCoursesLessonByLessonId"},"delete":{"tags":["Courses"],"summary":"Exclui uma aula","description":"Owner ou admin da comunidade do `X-CommunityId`. Exclusão lógica; o progresso de quem já assistiu fica guardado. Aula de outra comunidade, 404.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"lessonId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Aula excluída.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCoursesLessonByLessonId"}},"/api/courses/{courseId}/enroll":{"post":{"tags":["Courses"],"summary":"Cria ou executa enroll","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"courseId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCoursesByCourseIdEnroll"}},"/api/courses/{courseId}/lesson/{lessonId}/progress":{"post":{"tags":["Courses"],"summary":"Cria ou executa progress","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"courseId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"lessonId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCoursesByCourseIdLessonByLessonIdProgress"}},"/api/coupons":{"get":{"operationId":"getCommunitiesByCommunityIdCoupons","tags":["Coupons"],"summary":"Lista coupons","description":"Owner, admin ou finance da comunidade do `X-CommunityId`. O caminho não leva a comunidade.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["ACTIVE","INACTIVE","EXPIRED"]}},{"in":"query","name":"type","required":false,"schema":{"type":"string","enum":["PERCENTAGE","FIXED","FREE_TRIAL"]}},{"in":"query","name":"search","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdCoupons","tags":["Coupons"],"summary":"Cria ou executa coupons","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","name","type","discountValue","duration","startDate"],"properties":{"code":{"type":"string","description":"Coupon code is required"},"name":{"type":"string","description":"Name is required"},"description":{"type":"string"},"type":{"type":"string","enum":["PERCENTAGE","FIXED","FREE_TRIAL"],"description":"Invalid coupon type"},"discountValue":{"type":"number","description":"Discount value must be positive"},"maxDiscount":{"type":"number"},"trialExtensionDays":{"type":"integer"},"duration":{"type":"string","enum":["ONCE","FOREVER","REPEATING"],"description":"Invalid duration"},"durationInMonths":{"type":"integer"},"maxUses":{"type":"integer"},"maxUsesPerUser":{"type":"integer"},"startDate":{"type":"string","format":"date-time","description":"Valid start date required"},"endDate":{"type":"string","format":"date-time"},"restriction":{"type":"string","enum":["NONE","FIRST_PURCHASE","NEW_CUSTOMER"]},"minPurchaseAmount":{"type":"number"},"applicableProducts":{"type":"array"},"excludedProducts":{"type":"array"},"applicableToOneTime":{"type":"boolean"},"applicableToSubscription":{"type":"boolean"},"applicableToInstallment":{"type":"boolean"},"isStackable":{"type":"boolean"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/coupons/{idOrCode}":{"get":{"operationId":"getCommunitiesByCommunityIdCouponsByIdOrCode","tags":["Coupons"],"summary":"Detalha coupons por id","description":"Owner, admin ou finance da comunidade do `X-CommunityId`. Cupom de outra comunidade responde 404. Comprador valida código por `POST /coupons/validate`.\n","parameters":[{"in":"path","name":"idOrCode","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/coupons/validate":{"post":{"operationId":"postCommunitiesByCommunityIdCouponsValidate","tags":["Coupons"],"summary":"Cria ou executa validate","description":"Aberto a qualquer pessoa autenticada (é o caminho do comprador) e devolve só validade e desconto. A comunidade é a do `X-CommunityId`. FIN-7: cupom excluído não é encontrado; `maxUses` conta também os pedidos com o cupom ainda em aberto; o limite por pessoa e a restrição de primeira compra valem para quem tem perfil na comunidade; `productId` de outra comunidade dá 404. Recusas trazem `errors[0].param = code`. Para não servir de oráculo de códigos, depois de 10 códigos recusados em 15 minutos (por conta e comunidade) a resposta é 429 até a janela passar, mesmo para um código bom. O mesmo contador vale para `couponCode` em `calculate-price` e `POST /checkout`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code","amount"],"properties":{"code":{"type":"string","description":"Coupon code is required"},"productId":{"type":"string","format":"uuid","description":"Valid product ID required"},"amount":{"type":"number","description":"Amount must be greater than 0"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Códigos de cupom recusados demais em pouco tempo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/coupons/{id}/usage":{"get":{"operationId":"getCommunitiesByCommunityIdCouponsByIdUsage","tags":["Coupons"],"summary":"Lista ou consulta usage","description":"Owner, admin ou finance da comunidade do `X-CommunityId`. Cupom de outra comunidade responde 404.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"page","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/coupons/{id}":{"put":{"operationId":"putCommunitiesByCommunityIdCouponsById","tags":["Coupons"],"summary":"Atualiza coupons","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"discountValue":{"type":"number"},"maxDiscount":{"type":"number"},"trialExtensionDays":{"type":"integer"},"duration":{"type":"string","enum":["ONCE","FOREVER","REPEATING"]},"durationInMonths":{"type":"integer"},"maxUses":{"type":"integer"},"maxUsesPerUser":{"type":"integer"},"startDate":{"type":"string","format":"date-time"},"endDate":{"type":"string","format":"date-time"},"minPurchaseAmount":{"type":"number"},"applicableProducts":{"type":"array"},"excludedProducts":{"type":"array"},"applicableToOneTime":{"type":"boolean"},"applicableToSubscription":{"type":"boolean"},"applicableToInstallment":{"type":"boolean"},"isStackable":{"type":"boolean"},"status":{"type":"string","enum":["ACTIVE","INACTIVE"]}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCommunitiesByCommunityIdCouponsById","tags":["Coupons"],"summary":"Remove coupons","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/coupons/{id}/status":{"patch":{"operationId":"patchCommunitiesByCommunityIdCouponsByIdStatus","tags":["Coupons"],"summary":"Atualiza parcialmente status","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["ACTIVE","INACTIVE"],"description":"Status must be ACTIVE or INACTIVE"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/content":{"get":{"tags":["Content"],"summary":"Lista content","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Valid space ID required if provided"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getContent"},"post":{"tags":["Content"],"summary":"Cria ou executa content","description":"Sujeito a verificação de papel (RBAC). Além disso, respeita o\n`canCreate` do space: `staff` aceita owner, admin e moderator;\n`admins` aceita owner e admin; `anyone` não restringe. Fora da\nregra, 403 com `errors[0].param = \"spaceId\"`. SuperAdmin sempre passa.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"spaceId":"b1e2c3d4-5f6a-4b7c-8d9e-0f1a2b3c4d5e","title":"Boas-vindas à comunidade","content":"<p>Que bom ter você aqui! Comece se apresentando nos comentários.</p>","type":"text"},"schema":{"type":"object","required":["title","type"],"properties":{"spaceId":{"type":"string","format":"uuid","description":"Valid space ID required if provided"},"title":{"type":"string","description":"Title is required"},"type":{"type":"string","enum":["text","image","video","link"],"description":"Valid content type is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postContent"}},"/api/content/{id}":{"get":{"tags":["Content"],"summary":"Detalha content por id","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado. Sujeito a verificação de papel (RBAC).","security":[],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getContentById"},"put":{"tags":["Content"],"summary":"Atualiza content","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"title":"Boas-vindas à comunidade (atualizado)"},"schema":{"type":"object","properties":{"spaceId":{"type":"string","format":"uuid","description":"Valid space ID required if provided"},"title":{"type":"string","description":"Title cannot be empty"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putContentById"},"delete":{"tags":["Content"],"summary":"Remove content","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteContentById"}},"/api/content/{id}/move":{"put":{"tags":["Content"],"summary":"Move um post para outro space","description":"Owner, admin ou moderador da comunidade do `X-CommunityId`. O space de destino precisa ser dessa comunidade e do módulo `content` ou `feed`; o item do feed vai junto. Post ou space de outra comunidade, 404; space de outro módulo, 400 com `errors[0].param = \"spaceId\"`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["spaceId"],"properties":{"spaceId":{"type":"string","format":"uuid","description":"Space de destino"}}},"example":{"spaceId":"6f1c2b8e-3d4a-4b5c-9e7f-1a2b3c4d5e6f"}}}},"responses":{"200":{"description":"Post movido; devolve `id`, `spaceId` e `previousSpaceId`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putContentByIdMove"}},"/api/content/{id}/react":{"post":{"tags":["Content"],"summary":"Cria ou executa react","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["🎉","❤️","👍","🔥","🙌","😊","👏"],"description":"Reaction type is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postContentByIdReact"}},"/api/content/{id}/comment":{"post":{"tags":["Content"],"summary":"Cria ou executa comment","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"comment":"Ótimo conteúdo, obrigado por compartilhar!"},"schema":{"type":"object","required":["comment"],"properties":{"comment":{"type":"string","description":"Comment is required"},"parentId":{"type":"string","format":"uuid","description":"Invalid parent comment ID format"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postContentByIdComment"}},"/api/content/{id}/comments":{"get":{"tags":["Content"],"summary":"Lista ou consulta comments","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado. Sujeito a verificação de papel (RBAC).","security":[],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getContentByIdComments"}},"/api/content/{id}/comment/{commentId}/react":{"post":{"tags":["Content"],"summary":"Cria ou executa react","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["🎉","❤️","👍","🔥","🙌","😊","👏"],"description":"Reaction type is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postContentByIdCommentByCommentIdReact"}},"/api/content/{contentId}/comment/{commentId}":{"put":{"tags":["Content"],"summary":"Atualiza comment","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"contentId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"comment":"Corrigindo: o encontro é na quinta-feira."},"schema":{"type":"object","required":["comment"],"properties":{"comment":{"type":"string","minLength":1,"maxLength":2000,"description":"Comment must be between 1 and 2000 characters"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putContentByContentIdCommentByCommentId"},"delete":{"tags":["Content"],"summary":"Remove comment","description":"Sujeito a verificação de papel (RBAC). O item precisa ser da comunidade do `X-CommunityId`: de outra comunidade, responde 404, como se não existisse.","parameters":[{"in":"path","name":"contentId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"commentId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteContentByContentIdCommentByCommentId"}},"/api/subscriptions/me":{"get":{"operationId":"getCommunitiesByCommunityIdSubscriptionsMe","tags":["Subscriptions"],"summary":"Lista ou consulta me","description":"Traz `commitmentEndsAt`, `cancelEffectiveAt` e `product.commitmentMonths` (F-35). F-37: um adicional cobrado junto com um plano (`billedWithId`) nunca é a assinatura devolvida aqui; o plano é. A resposta traz `billedWithId`, `addOns` e `nextChargeTotal` (ver `GET /api/subscriptions`). Traz também `pendingRenewal`, a cobrança de renovação em aberto, ou `null` (ver `GET /api/subscriptions`): é o que a tela de \"Pagar agora\" e o PIX de renovação mostram.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/purchases/me":{"get":{"operationId":"getCommunitiesByCommunityIdPurchasesMe","tags":["Checkout"],"summary":"Lista ou consulta me","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/communities/plans":{"post":{"tags":["Subscriptions"],"summary":"Cria ou executa subscriptions","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCommunitiesPlans"},"get":{"tags":["Subscriptions"],"summary":"Lista subscriptions","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCommunitiesPlans"}},"/api/communities/plans/{id}":{"get":{"tags":["Subscriptions"],"summary":"Detalha subscriptions por id","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCommunitiesPlansById"},"put":{"tags":["Subscriptions"],"summary":"Atualiza subscriptions","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCommunitiesPlansById"},"delete":{"tags":["Subscriptions"],"summary":"Remove subscriptions","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCommunitiesPlansById"}},"/api/communities":{"post":{"tags":["Communities"],"summary":"Cria ou executa communities","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"name":"Comunidade Dev São Paulo","slug":"dev-sao-paulo"},"schema":{"type":"object","required":["name","slug"],"properties":{"name":{"type":"string","description":"Community name is required"},"slug":{"type":"string","description":"Slug is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCommunities"}},"/api/communities/my":{"get":{"tags":["Communities"],"summary":"Lista ou consulta my","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCommunitiesMy"}},"/api/communities/domain":{"post":{"tags":["Communities"],"summary":"Cria ou executa domain","description":"Autenticação opcional: o conteúdo retornado varia conforme o membro autenticado.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"example":{"domain":"comunidade.devsp.com.br"},"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Valid domain is required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCommunitiesDomain"}},"/api/communities/{id}":{"put":{"tags":["Communities"],"summary":"Atualiza communities","description":"Sujeito a verificação de papel (RBAC) na comunidade do X-CommunityId. O `{id}` do caminho precisa ser essa mesma comunidade; um id diferente responde 403 (SEC-15).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":false,"content":{"application/json":{"example":{"name":"Comunidade Dev São Paulo","description":"Encontros, cursos e conversas para quem desenvolve software em São Paulo.","metaTitle":"Comunidade Dev São Paulo","metaDescription":"A comunidade de quem desenvolve software em São Paulo.","themeColor":"#ec4899","language":"pt-BR"},"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"domain":{"type":"string"},"googleAnalyticsId":{"type":"string"},"logoUrl":{"type":"string"},"faviconUrl":{"type":"string"},"ogImageUrl":{"type":"string"},"metaTitle":{"type":"string"},"metaDescription":{"type":"string"},"metaKeywords":{"type":"string"},"themeColor":{"type":"string","description":"Cor da barra de endereço em dispositivos móveis (PWA)."},"themePalette":{"type":"object","nullable":true,"description":"Paleta de cores da interface. Cada escala aceita os tons 50 a 950 em hexadecimal; o tom 500 é obrigatório e os tons omitidos são derivados dele. `null` restaura a paleta padrão do produto.\n","properties":{"primary":{"$ref":"#/components/schemas/ThemeColorScale"},"secondary":{"$ref":"#/components/schemas/ThemeColorScale"}}},"active":{"type":"boolean"},"signupEnabled":{"type":"boolean"},"signupModel":{"type":"string","enum":["FREE","PAID"]},"guestAccess":{"type":"boolean"},"contentModeration":{"type":"boolean"},"payoutEnabled":{"type":"boolean"},"globalRanking":{"type":"boolean"},"language":{"type":"string","enum":["en-US","pt-BR","pt-PT","es-ES","es-MX","es-AR","it-IT","de-DE","de-AT","de-CH"],"description":"Idioma padrão da comunidade: o dos e-mails e o de quem ainda não escolheu um idioma. Só as variantes regionais; um valor fora da lista responde 400.\n"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCommunitiesById"},"delete":{"tags":["Communities"],"summary":"Remove communities","description":"Sujeito a verificação de papel (RBAC) na comunidade do X-CommunityId. O `{id}` do caminho precisa ser essa mesma comunidade; um id diferente responde 403 (SEC-15).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCommunitiesById"}},"/api/communities/{id}/members":{"get":{"tags":["Communities"],"summary":"Lista ou consulta members","description":"Sujeito a verificação de papel (RBAC) na comunidade do X-CommunityId. O `{id}` do caminho precisa ser essa mesma comunidade; um id diferente responde 403 (SEC-15).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCommunitiesByIdMembers"}},"/api/communities/{id}/settings":{"patch":{"tags":["Communities"],"summary":"Atualiza parcialmente settings","description":"Sujeito a verificação de papel (RBAC) na comunidade do X-CommunityId. O `{id}` do caminho precisa ser essa mesma comunidade; um id diferente responde 403 (SEC-15).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"content":{"application/json":{"example":{"signupEnabled":true,"guestAccess":false,"contentModeration":true},"schema":{"type":"object","properties":{"signupEnabled":{"type":"boolean"},"signupModel":{"type":"string","enum":["FREE","PAID"]},"guestAccess":{"type":"boolean"},"contentModeration":{"type":"boolean"},"payoutEnabled":{"type":"boolean"},"globalRanking":{"type":"boolean"},"linkedinOrganizationId":{"type":"string","nullable":true,"description":"F-42: ID da página da comunidade no LinkedIn, só dígitos (até 32). Com ele, o Adicionar ao perfil dos certificados mostra o logo da página; vazio ou null limpa."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"patchCommunitiesByIdSettings"}},"/api/checkout/subscription-groups":{"get":{"tags":["Checkout"],"summary":"Lista ou consulta subscription groups","description":"Endpoint público — não exige autenticação. Adicionais (produtos com `prerequisiteGroupIds`) só aparecem para quem tem assinatura ACTIVE ou TRIALING num dos grupos exigidos; o token é opcional e, sem ele, nenhum adicional aparece. Cada produto traz `prerequisiteGroupIds` (vazio quando não é adicional). Cada grupo traz `slug`, o endereço do plano nos links públicos (`/pricing/<slug>/<optionKey>`). Cada produto traz `optionKey`, o segmento da opção de cobrança nesse link: `mensal` (MONTHLY sem contrato), `N-meses` (MONTHLY com commitmentMonths N), `anual` (YEARLY), ou null nos demais intervalos. Dois produtos do mesmo grupo podem ter o mesmo `optionKey`. F-37: cada grupo traz `addOns`, os adicionais da lista do plano à venda, visíveis a qualquer um, com ou sem plano: `productId`, `title`, `shortDescription`, `price` (mensal), `currency`, `feePayer` e `sellsWithPlan` (`SUBSCRIPTION` `MONTHLY`: pode ser comprado junto com o plano). Cada opção que aceita adicional (MONTHLY ou YEARLY, sem teste) traz `addOnAmounts`: `[{ productId, amount, interval }]`, o valor de cada adicional vendido junto no ritmo da opção (o mensal, ou 12 × o mensal no anual), sem a taxa paga pelo comprador. Opção que não aceita adicional não traz o campo. Cada produto traz `thankYouMessage` e `redirectUrl` (opcionais, null quando vazios).\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutSubscriptionGroups"}},"/api/checkout/subscriptions":{"get":{"tags":["Checkout"],"summary":"Lista ou consulta subscriptions","description":"Endpoint público — não exige autenticação. Adicionais (produtos com `prerequisiteGroupIds`) só aparecem para quem tem assinatura ACTIVE ou TRIALING num dos grupos exigidos; o token é opcional e, sem ele, nenhum adicional aparece. Cada produto traz `prerequisiteGroupIds` (vazio quando não é adicional).\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutSubscriptions"}},"/api/checkout/products":{"get":{"tags":["Checkout"],"summary":"Lista ou consulta products","description":"Endpoint público — não exige autenticação. Lista só produtos avulsos ativos com `directLinkEnabled`; os vendidos apenas numa Loja são listados por `GET /api/storefront/spaces/{spaceId}/products`. Comunidade pelo `X-CommunityId`. `imageUrl` vem de `featuredImageUrl`, com `bannerUrl` como alternativa. Adicionais (produtos com `prerequisiteGroupIds`) só aparecem para quem tem assinatura ACTIVE ou TRIALING num dos grupos exigidos; o token é opcional e, sem ele, nenhum adicional aparece. Cada produto traz `prerequisiteGroupIds` (vazio quando não é adicional).\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutProducts"}},"/api/checkout/config":{"get":{"tags":["Checkout"],"summary":"Configuração de pagamento da comunidade","description":"Endpoint público — não exige autenticação. A comunidade é a do `X-CommunityId`; sem o header, 400 com `param = X-CommunityId`. Comunidade inexistente, 404; sem configuração de pagamento aprovada, 400.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutConfig"}},"/api/checkout/calculate-price":{"post":{"tags":["Checkout"],"summary":"Cria ou executa calculate price","description":"Endpoint público — não exige autenticação. FIN-54: cota só produto da comunidade do `X-CommunityId`; sem comunidade, 400 com `param = X-CommunityId`; produto de outra comunidade, 404. Com token de quem já assina o plano, a resposta traz o campo opcional `alreadySubscribed: { subscriptionId, status, productId }`. `allowedPaymentMethods` do produto é lido tanto como array quanto como string JSON; método fora da lista ou parcelas acima de `maxInstallments` respondem 400 com `errors[].param`. Parcelas só valem no cartão de crédito (PIX e boleto respondem `installments = 1`). F-43, juros de parcelamento da Memberfy (% total por número de parcelas, da tabela de taxas da plataforma ou da comunidade), depois dos descontos e da taxa da plataforma, que não muda: com `installmentInterestPayer = BUYER` somam ao preço; com `ORGANIZATION` o comprador paga o preço e a comunidade recebe menos. Campos novos e opcionais: `installmentInterestPayer`, `installmentInterestPercent`, `installmentInterest` (juros pagos pelo comprador; `0.00` quando a comunidade absorve), `totalWithInterest` (o que o cartão cobra), `installmentAmount` e, no cartão, `installmentOptions` (`[{ installments, percent, totalAmount, installmentAmount }]`, de 1 até `maxInstallments`). `totalAmount` segue sendo o valor antes dos juros. Com adicionais, os mesmos campos em cada item. F-37: `addOnProductIds` (array de UUID, opcional) cota a opção de plano com adicionais, como `POST /checkout` cobraria num pedido só. A resposta ganha `items` (`productId`, `title`, `basePrice`, `feePayer`, `fees` quando o comprador paga a taxa, `totalAmount`), e `totalAmount` e `breakdown.total` passam a ser o total do pedido; os demais campos continuam descrevendo a opção do plano. A taxa fixa entra uma vez, no plano. Recusas com 400 e `param = addOnProductIds`: adicional fora da lista do plano, que não é `SUBSCRIPTION` `MONTHLY` à venda, repetido, ou opção que não aceita adicional (intervalo sem fator, ou com teste). FIN-7: `couponCode` (string, opcional) aplica o cupom da comunidade do produto antes da taxa, como `POST /checkout` cobraria: a taxa da plataforma é calculada sobre o valor com desconto. Com cupom, a resposta ganha `coupon` (`code`, `type`, `discountValue`, `duration`, `durationInMonths`), `discountAmount` (o desconto do pedido), `breakdown.discount` (o da opção) e `items` mesmo sem adicionais, cada item com `discountAmount`; `basePrice` e `breakdown.product` continuam sendo o preço cheio, e `totalAmount`/`breakdown.total` já vêm com o desconto. `PERCENTAGE` (limitado por `maxDiscount`) e `FIXED` valem uma vez para o pedido, divididos entre os itens a que o cupom se aplica. Recusas com `param = couponCode`: 404 cupom inexistente; 400 inativo, fora da validade, sem usos (`maxUses`, contando pedidos ainda em aberto), pedido abaixo do mínimo, produto fora da lista, cupom `FREE_TRIAL`, ou desconto que zera um item. Com login (opcional), também o limite por pessoa e a restrição de primeira compra. Depois de 10 códigos recusados em 15 minutos, 429 por quem chama (conta ou IP).\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalculatePriceInput"},"example":{"productId":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60","paymentMethod":"CREDIT_CARD","installments":3}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Códigos de cupom recusados demais em pouco tempo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCheckoutCalculatePrice"}},"/api/checkout":{"post":{"tags":["Checkout"],"summary":"Cria ou executa checkout","description":"Primeira recusa depois de achar o produto: 403 quando a comunidade não tem informações comerciais `APPROVED`, para **todo** produto (antes só quando `requiresApproval` era verdadeiro), antes de gravar qualquer coisa — inclusive o `saveDocument` — ou chamar o provedor. Produto avulso (`ONE_TIME`/`INSTALLMENT`) só é comprável quando aparece num space Loja (`storefront`) que o comprador enxerga, ou quando tem `directLinkEnabled`. Fora disso responde 403 com `errors[0].param = productId`, antes de criar a compra ou chamar o provedor. Assinaturas não mudam. Também antes de gravar qualquer coisa: 403 (`param = X-CommunityId`) para quem não tem perfil na comunidade; 400 (`param = paymentMethod` ou `installments`) quando o método não está em `allowedPaymentMethods` ou as parcelas passam de `maxInstallments`; 400 (`param = customerData`) sem nome e e-mail do comprador (os da conta valem quando o corpo não traz). CPF/CNPJ: sem `customerData.document`, vale o salvo na conta (`document` de `GET /api/auth/me`). Campo opcional `saveDocument` (boolean): `true` grava `customerData.document` na conta, substituindo o salvo (ex.: comprar como empresa); CPF/CNPJ com dígito verificador errado responde 400 (`param = customerData.document`) sem criar nada. Sem `saveDocument`, o documento e o telefone do pedido são gravados no primeiro pagamento confirmado só se a conta não tiver (telefone existente nunca é trocado). Plano já assinado: 409 (`param = productId`, mensagem \"Você já assina este plano\") quando o comprador tem assinatura `ACTIVE`, `TRIALING` ou `PAST_DUE` de qualquer opção do mesmo plano (grupo); `data: { subscriptionId, subscriptionStatus, productId }` para o app levar a Cobrança. PIX ou boleto do mesmo plano ainda em aberto: 409 (`param = productId`) sem criar outro pedido, com `data.openPayment: { purchaseId, orderId, productId, paymentMethod, status, amount, currency, qrCode, pixCode, expiresAt, boletoUrl, boletoBarcode, boletoDueAt }` para mostrar o mesmo QR (ou cancelar em `POST /checkout/{purchaseId}/cancel`). O pedido aberto é lido na Pagar.me antes: pago vira o 409 de plano assinado; expirado ou falho deixa seguir. Outro plano da comunidade não é bloqueado. A resposta 201 traz os campos opcionais `thankYouMessage` e `redirectUrl` do produto. O valor cobrado (`amount`) é o preço, mais a taxa da plataforma quando `feePayer = BUYER`. Quando o provedor recusa o pagamento, a compra fica `FAILED` e a resposta é 402, com o motivo do provedor em `errors[].param = provider`; provedor fora do ar responde 502. Parcelas (`installments`, 1–12, até `maxInstallments`) só valem no cartão de crédito: PIX e boleto são à vista, e a resposta e a compra trazem `installments = 1`. Assinatura `YEARLY` vende o ano em parcelas, com os juros de parcelamento da Memberfy (F-43) pagos por quem o produto diz (`installmentInterestPayer`), e a renovação anual cobra o ano de novo no cartão salvo, nas mesmas parcelas da compra, com a tabela vigente. A resposta ganha os campos opcionais `installmentInterestPayer`, `installmentInterestPercent`, `installmentInterest`, `totalWithInterest` e `installmentAmount` (`amount` já é o total cobrado). O cartão com que uma assinatura é paga vira o cartão padrão do membro (`/payment-methods`), para a renovação. Adicional (produto com `prerequisiteGroupIds`) só é vendido a quem tem assinatura ACTIVE ou TRIALING num dos grupos exigidos, inclusive por link direto: sem isso, 403 com `errors[0].param = productId` (`monetization.purchase.prerequisiteRequired`), antes de criar a compra ou chamar o provedor. F-37: `addOnProductIds` (array de UUID, opcional) compra a opção de plano e os adicionais da lista do plano num pedido só, numa cobrança (um PIX, um boleto ou uma transação no cartão, nas parcelas da opção). É o que permite comprar o adicional sem ainda ter o plano. Cada adicional vira uma compra própria ligada à do plano e, pago o pedido, uma assinatura cobrada junto com a do plano (`billedWithId`), no ritmo da opção (o mensal, ou 12 × o mensal no anual). A taxa fixa da plataforma entra uma vez, na compra do plano. Recusas com 400 e `param = addOnProductIds`, antes de gravar: adicional fora da lista do plano, que não é `SUBSCRIPTION` `MONTHLY` à venda, repetido, já assinado pelo comprador, ou opção que não aceita adicional (intervalo sem fator, ou com teste). Com o campo, a resposta ganha `items` (`[{ purchaseId, productId, title, amount, feeBreakdown }]`, o plano primeiro), `amount` passa a ser o total do pedido e `feeBreakdown` a soma; `purchaseId` continua sendo o da compra do plano. FIN-7: `couponCode` (opcional) aplica o cupom antes da taxa: a taxa da plataforma, o valor cobrado (`pricePaid`), o ledger e um reembolso seguem o valor com desconto. Com cupom, a resposta ganha `coupon` (`code`, `type`, `discountValue`, `duration`, `durationInMonths`), `discountAmount` (do pedido) e `items` mesmo sem adicionais, cada item com `baseAmount` (antes do desconto) e `discountAmount`. O uso do cupom (`CouponUsage`, `currentUses`) só é registrado quando o pagamento é confirmado; até lá o pedido em aberto segura um dos `maxUses`. Na renovação, `ONCE` vale só na primeira cobrança, `REPEATING` enquanto o período começa dentro de `durationInMonths` desde o início da assinatura, `FOREVER` sempre. Recusas com `param = couponCode`, antes de cobrar: 404 cupom inexistente; 400 inativo, fora da validade, sem usos, limite por pessoa, só primeira compra, pedido abaixo do mínimo, produto fora da lista, cupom `FREE_TRIAL`, ou desconto que zera um item. Depois de 10 códigos recusados em 15 minutos, 429.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutInput"},"example":{"productId":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60","paymentMethod":"PIX","customerData":{"name":"Maria Silva","email":"maria.silva@memberfy.net","document":"12345678909"}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Códigos de cupom recusados demais em pouco tempo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCheckout"}},"/api/checkout/purchases":{"get":{"tags":["Checkout"],"summary":"Lista ou consulta purchases","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutPurchases"}},"/api/checkout/{purchaseId}":{"get":{"tags":["Checkout"],"summary":"Detalha checkout por id","parameters":[{"in":"path","name":"purchaseId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCheckoutByPurchaseId"}},"/api/checkout/{purchaseId}/cancel":{"post":{"tags":["Checkout"],"summary":"Cria ou executa cancel","description":"Fecha como `FAILED` uma compra `PENDING` ou `PROCESSING` que não foi paga. Para `PROCESSING`, consulta o pedido no provedor antes: pago responde 409; cobranças abertas são canceladas no provedor quando ele permite (PIX aguardando pagamento não é cancelável e expira sozinho; um pagamento que ainda chegue é reconhecido pelo webhook). Provedor fora do ar responde 502 sem alterar nada. F-37: cancelar a compra do plano de um pedido com adicionais fecha também as compras dos adicionais do mesmo pedido. A compra de um adicional dentro do pedido do plano responde 409 (`param = purchaseId`): o pedido é um só.\n","parameters":[{"in":"path","name":"purchaseId","required":true,"schema":{"type":"string"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCheckoutByPurchaseIdCancel"}},"/api/certificates/spaces/{spaceId}":{"get":{"tags":["Certificates"],"summary":"Regra do space de certificados e o que quem pergunta pode fazer","description":"Devolve `whoCanIssue` (`staff` | `admins`) e, para quem pergunta, `canIssue`, `canManageTemplates` e `canRevoke`. Visitante recebe os três como `false`.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesSpacesBySpaceId"},"put":{"tags":["Certificates"],"summary":"Define quem emite no space de certificados","description":"Owner ou admin da comunidade do header. \"Qualquer um\" não existe neste módulo.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["whoCanIssue"],"properties":{"whoCanIssue":{"type":"string","enum":["staff","admins"]}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCertificatesSpacesBySpaceId"}},"/api/certificates/fonts":{"get":{"tags":["Certificates"],"summary":"Catálogo de fontes dos modelos","description":"As fontes OFL embutidas na API, com os pesos de cada uma. Noto Sans é a reserva para caracteres que a fonte escolhida não tem.","security":[],"parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}}},"operationId":"getCertificatesFonts"}},"/api/certificates/templates":{"get":{"tags":["Certificates"],"summary":"Lista os modelos de um space","description":"Quem emite no space (`whoCanIssue`). Cada modelo vem com `issuedCount`, `visibleArea` (a parte da arte que fica no A4) e `canEdit`/`canIssue`.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string","enum":["DRAFT","ACTIVE","ARCHIVED"]}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesTemplates"},"post":{"tags":["Certificates"],"summary":"Cria um modelo em rascunho","description":"`PLATFORM` usa o layout padrão com o logo e as cores da comunidade; `IMAGE` usa a arte enviada depois por `POST /api/upload/certificate-template/{templateId}/background`, com os retângulos em `layout`. Idioma nasce com o da comunidade; fuso, com o enviado (o app manda o do navegador).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/CertificateTemplateInput"},{"type":"object","required":["spaceId","name","kind","title"],"properties":{"spaceId":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["PLATFORM","IMAGE"]}}}]}}}},"responses":{"201":{"description":"Modelo criado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesTemplates"}},"/api/certificates/templates/{id}":{"get":{"tags":["Certificates"],"summary":"Detalhe de um modelo","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesTemplatesById"},"put":{"tags":["Certificates"],"summary":"Edita um modelo","description":"Se o modelo já emitiu, `version` sobe; os certificados emitidos guardam a cópia do modelo usado e não mudam. Um modelo ativo que fique sem os campos obrigatórios volta a rascunho.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateTemplateInput"}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCertificatesTemplatesById"}},"/api/certificates/templates/{id}/activate":{"post":{"tags":["Certificates"],"summary":"Ativa um modelo (só modelos ativos emitem)","description":"Um modelo IMAGE precisa da arte e dos retângulos obrigatórios (nome, data e hora, QR) fora da faixa cortada.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesTemplatesByIdActivate"}},"/api/certificates/templates/{id}/archive":{"post":{"tags":["Certificates"],"summary":"Arquiva um modelo","description":"Para de emitir; os certificados já emitidos continuam válidos.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesTemplatesByIdArchive"}},"/api/certificates/templates/{id}/duplicate":{"post":{"tags":["Certificates"],"summary":"Duplica um modelo como rascunho","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Cópia criada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesTemplatesByIdDuplicate"}},"/api/certificates/templates/{id}/preview":{"post":{"tags":["Certificates"],"summary":"Pré-visualização do modelo renderizada pelo servidor","description":"O mesmo motor da emissão, com dados fictícios (nome longo de propósito). O corpo é opcional e pode trazer edições não salvas (`layout`, `title`, `signers`...). Responde a imagem PNG (1600 px de largura) ou o PDF com `?format=pdf`. O header `X-Certificate-Warnings` lista campos cujo texto não coube nem no tamanho mínimo.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"format","schema":{"type":"string","enum":["png","pdf"]}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CertificateTemplateInput"}}}},"responses":{"200":{"description":"A imagem ou o PDF.","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesTemplatesByIdPreview"}},"/api/certificates":{"get":{"tags":["Certificates"],"summary":"Lista os certificados emitidos num space (aba \"Emitidos\")","description":"Quem emite no space. Cada item traz `recipient` (com `removed: true` quando a pessoa foi removida pela equipe, cujos certificados são preservados), `status`, `source`, URLs e as permissões `canRevoke`, `canReissue`, `canResendEmail`, `canRetry` e `canDelete`. Um certificado substituído por reemissão traz `replacedById` e `replacedByCode` (o novo).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"templateId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"batchId","schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","schema":{"type":"string","enum":["PENDING","ISSUED","FAILED","REVOKED"]}},{"in":"query","name":"q","description":"Busca por nome impresso ou código.","schema":{"type":"string"}},{"in":"query","name":"page","schema":{"type":"integer","minimum":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificates"},"post":{"tags":["Certificates"],"summary":"Emite certificados de um modelo ativo","description":"O modelo vem por `templateId` ou `templateSlug`. Para quem: qualquer combinação de `profileIds`, `memberGroupIds` e `tags` (nomes) / `tagIds`, só membros da comunidade; a união das pessoas, sem repetir quem está em mais de um. `memberGroupId` e `tagId` no singular continuam aceitos. Emissão por e-mail não existe mais: `emails` responde 400. Quem já tem um certificado vigente do modelo é avisado e pulado (`skipped`, motivo `alreadyHas`), a menos que `issueAnyway: true`. Nome com caractere que nenhuma fonte desenha é pulado (`unsupportedName`). `dryRun: true` responde 200 com essa conferência sem gravar. Emitindo, responde **202**: as linhas nascem `PENDING` com a data e hora deste pedido, e a renderização vai para a fila; com mais de uma pessoa há um `batch` para acompanhar. Limite de 1.000 pessoas por pedido.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string","format":"uuid","description":"Ou `templateSlug`."},"templateSlug":{"type":"string","example":"conclusao-de-curso"},"profileIds":{"type":"array","items":{"type":"string","format":"uuid"}},"memberGroupIds":{"type":"array","items":{"type":"string","format":"uuid"}},"tags":{"type":"array","items":{"type":"string"},"description":"Nomes das tags, como em `GET /api/profiles/tags`."},"tagIds":{"type":"array","items":{"type":"string","format":"uuid"},"description":"Ids de `CommunityTag` (só existem para tags com cor)."},"memberGroupId":{"type":"string","format":"uuid","deprecated":true},"tagId":{"type":"string","format":"uuid","deprecated":true},"overrides":{"type":"object","description":"Valores desta emissão; ausentes vêm do modelo.","properties":{"title":{"type":"string"},"description":{"type":"string"},"workloadHours":{"type":"number"},"subjectTitle":{"type":"string","description":"Do que é o certificado (um curso, um evento, uma mentoria). Preenche {assunto} e o campo `subjectTitle` da arte."},"courseTitle":{"type":"string","deprecated":true,"description":"Apelido de `subjectTitle`."},"eventTitle":{"type":"string","deprecated":true,"description":"Apelido de `subjectTitle`."}}},"sendEmail":{"type":"boolean","default":true},"issueAnyway":{"type":"boolean","default":false,"description":"\"Emitir mesmo assim\" para quem já tem."},"dryRun":{"type":"boolean","default":false}}}}}},"responses":{"200":{"description":"Conferência (`dryRun`) ou nada a emitir.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"202":{"description":"Emissão aceita, renderizando na fila.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificates"}},"/api/certificates/batches/{id}":{"get":{"tags":["Certificates"],"summary":"Progresso de um lote de emissão","description":"`total`, `pending`, `issued`, `failed`, `revoked` e `finishedAt` (preenchido quando nada mais está pendente).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesBatchesById"}},"/api/certificates/mine":{"get":{"tags":["Certificates"],"summary":"Os certificados de quem pergunta (aba \"Meus certificados\")","description":"Do próprio perfil na comunidade do header, de um space se `spaceId` vier. Inclui `pdfUrl`, `imageUrl` (1200×630), `squareImageUrl` (1080×1080), `pageImageUrl` (a página do certificado, 2480×1754, sem o fundo dos cards), `verificationUrl`, `linkedinAddUrl`, `indexable` e `canSetIndexing`. Revogado vem sem URLs de arquivo.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"spaceId","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesMine"}},"/api/certificates/verify/{code}":{"get":{"tags":["Certificates"],"summary":"Verificação pública de um certificado pelo código","description":"Sem login e sem `X-CommunityId` (o código é global). A página do app que consome esta rota é `https://{domínio da comunidade}/_/certificates/verify/{código}`, o `verificationUrl` e o QR dos certificados emitidos a partir de 2026-10-06; os anteriores trazem `/verify/{código}`, que o app redireciona. Válido: nome como emitido, título, descrição, carga horária, `subjectTitle` (do que é o certificado; `courseTitle` e `eventTitle` trazem o mesmo valor, por compatibilidade), comunidade, data e hora, quem assinou e as URLs do PDF e das imagens. Revogado: só título, comunidade, data de emissão e `revokedAt`. Nunca e-mail, quem emitiu nem o motivo da revogação. `indexable` diz se a página pode ir para buscadores (nasce `false`; o dono liga). Código inexistente, apagado (a pessoa saiu da comunidade) ou malformado: o mesmo 404. Aceita o código com ou sem hífens, em minúsculas. Limite de 60 consultas por minuto por IP.\n","security":[],"parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"code","required":true,"schema":{"type":"string","example":"K7Q3-9XWD-2MFA"}}],"responses":{"200":{"description":"Certificado encontrado (válido ou revogado).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"429":{"description":"Muitas consultas."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesVerifyByCode"}},"/api/certificates/{id}":{"get":{"tags":["Certificates"],"summary":"Detalhe de um certificado","description":"Para o dono ou para quem emite no space. Qualquer outro recebe 404.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesById"},"delete":{"tags":["Certificates"],"summary":"Exclui um certificado que não vale mais","description":"Owner ou admin. Só certificado **revogado** (inclusive o substituído por uma reemissão, `replacedById` preenchido) ou **com falha**. Válido (`ISSUED`): 409 \"revogue antes de excluir\"; ainda gerando (`PENDING`): 409. Apaga os arquivos (PDF, imagem da página e cards) e a linha, de vez: a verificação do código passa a responder 404, igual a um código que nunca existiu. A exclusão fica registrada no log (quem, qual código, quando).\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Excluído. `data` traz `id` e `code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Certificado válido ou ainda gerando."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCertificatesById"}},"/api/certificates/{id}/pdf":{"get":{"tags":["Certificates"],"summary":"Redireciona para o PDF do certificado","description":"Dono ou quem emite. Regenera na hora se o arquivo sumiu. 410 se revogado; 409 enquanto ainda está sendo gerado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"302":{"description":"Redireciona para o arquivo."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Ainda gerando."},"410":{"description":"Certificado revogado."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesByIdPdf"}},"/api/certificates/{id}/image":{"get":{"tags":["Certificates"],"summary":"Redireciona para a imagem compartilhável","description":"`size=1200x630` (padrão; LinkedIn, WhatsApp, X), `1080x1080` (Instagram) ou `page`: a página do próprio certificado, 2480×1754, igual à página do PDF e sem o fundo colorido dos cards (PNG no modelo padrão, JPEG no de arte). Certificado emitido antes de existir a imagem da página a ganha no primeiro pedido. Mesmas regras do PDF.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"size","schema":{"type":"string","enum":["1200x630","1080x1080","page"]}}],"responses":{"302":{"description":"Redireciona para o arquivo."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Ainda gerando."},"410":{"description":"Certificado revogado."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCertificatesByIdImage"}},"/api/certificates/{id}/indexing":{"patch":{"tags":["Certificates"],"summary":"Liga ou desliga \"Mostrar em buscadores\" na página de verificação","description":"Só o dono do certificado. Desligado (padrão), a página sai com noindex; ela continua pública por código nos dois casos.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["indexable"],"properties":{"indexable":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"410":{"description":"Certificado revogado."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"patchCertificatesByIdIndexing"}},"/api/certificates/{id}/revoke":{"post":{"tags":["Certificates"],"summary":"Revoga um certificado","description":"Owner ou admin, com motivo (interno, nunca público). A verificação passa a dizer \"revogado\", os arquivos são apagados e os links diretos param; a linha fica.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","maxLength":1000}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Já revogado."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesByIdRevoke"}},"/api/certificates/{id}/reissue":{"post":{"tags":["Certificates"],"summary":"Reemite um certificado com o nome atual do perfil","description":"Owner ou admin. Emite um novo (código novo, 202, fila) e revoga o anterior com o motivo \"reemissão\". Usado para corrigir nome.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"sendEmail":{"type":"boolean","default":true}}}}}},"responses":{"202":{"description":"Reemissão aceita.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesByIdReissue"}},"/api/certificates/{id}/resend-email":{"post":{"tags":["Certificates"],"summary":"Reenvia o e-mail \"Seu certificado chegou\"","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Certificado não emitido."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesByIdResendEmail"}},"/api/certificates/{id}/retry":{"post":{"tags":["Certificates"],"summary":"Refaz a geração de um certificado que falhou","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"De volta à fila.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Não está com falha."},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCertificatesByIdRetry"}},"/api/upload/certificate-template/{templateId}/background":{"post":{"tags":["Uploads"],"summary":"Envia a arte de um modelo de certificado (tipo IMAGE)","description":"PNG ou JPEG, mínimo 2000 px de largura (recomendado 3508×2480, A4 a 300 dpi), até 20 MB; acima de 3 MB é recomprimida em JPEG. Devolve `url`, `width`, `height`, `visibleArea` (a parte da arte que fica no A4, em %) e `layoutWarnings` (retângulos que caíram na faixa cortada). A arte antiga fica no S3: certificados emitidos apontam para ela.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"templateId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["background"],"properties":{"background":{"type":"string","format":"binary"}}}}}},"responses":{"201":{"description":"Arte enviada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCertificateTemplateByTemplateIdBackground"}},"/api/upload/certificate-template/{templateId}/signature":{"post":{"tags":["Uploads"],"summary":"Envia a imagem de uma assinatura (PNG com transparência)","description":"Devolve a `url`; o editor a grava em `signers[i].signatureImageUrl` pelo PUT do modelo.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"templateId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["signature"],"properties":{"signature":{"type":"string","format":"binary"}}}}}},"responses":{"201":{"description":"Assinatura enviada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postUploadCertificateTemplateByTemplateIdSignature"}},"/api/call4papers/spaces/{spaceId}":{"get":{"tags":["Call for Papers"],"summary":"Configuração do space de chamadas","description":"Devolve o modo do space (`single`/`multi`) e as chamadas visíveis a quem pergunta. Em `single` o edital vem embutido em `data.call`. Rascunhos só aparecem para quem administra — é filtro de servidor, não de interface.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSpacesBySpaceId"},"put":{"tags":["Call for Papers"],"summary":"Define o modo do space de chamadas","description":"Owner ou admin da comunidade do header. Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["single","multi"]},"whoCanOpenCall":{"type":"string","enum":["owners","staff","members"]},"requireApprovalToOpen":{"type":"boolean"},"defaultSettings":{"type":"object"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersSpacesBySpaceId"}},"/api/call4papers/spaces/{spaceId}/calls":{"get":{"tags":["Call for Papers"],"summary":"Lista as chamadas de um space","description":"Autenticação opcional: o conteúdo varia conforme quem pergunta. Cada item traz `canEdit`, `canDelete`, `canViewSubmissions` e `canReview` — permissão vem do servidor, por item. O `status` de cada item é o **efetivo**: passado o prazo de submissão, uma chamada `open` sai como `closed` (ou `reviewing`, se há janela de avaliação ainda por vir ou em curso), mesmo antes de o job gravar a mudança. O filtro `?status=` compara esse mesmo valor — \"open\" não lista chamada vencida. Cada item traz `timeZone`: o fuso (IANA) em que as datas, sem fuso, são lidas.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"status","required":false,"schema":{"type":"string","enum":["draft","open","reviewing","deciding","closed","archived"]}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSpacesBySpaceIdCalls"}},"/api/call4papers/spaces/{spaceId}/calls/{slug}":{"get":{"tags":["Call for Papers"],"summary":"Detalhe de uma chamada pelo slug","description":"O slug é único dentro do space. Rascunho responde 404 para quem não administra.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"spaceId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"slug","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSpacesBySpaceIdCallsBySlug"}},"/api/call4papers/me/submissions":{"get":{"tags":["Call for Papers"],"summary":"Minhas propostas na comunidade","description":"Passa pelo `formatSubmissionForSpeaker()`: nunca traz `internalNotes`, pareceres nem consolidação de notas.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersMeSubmissions"}},"/api/call4papers/speakers":{"get":{"tags":["Call for Papers"],"summary":"Quem já propôs nesta comunidade, agrupado por pessoa","description":"Consulta sobre as propostas, não cadastro: a lista se monta a partir de quem enviou, com o que enviou e como terminou. Só para quem administra — a ficha traz nota média, que é interna.\n","parameters":[{"in":"query","name":"spaceId","required":false,"schema":{"type":"string","format":"uuid"},"description":"Recorta pelas chamadas de um space."},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSpeakers"}},"/api/call4papers/{id}/invite-speaker":{"post":{"tags":["Call for Papers"],"summary":"Convida alguém do banco de proponentes a submeter nesta chamada","description":"O efeito é um e-mail, e só. Não cria proposta nem reserva vaga — a pessoa submete do jeito normal, ou não submete. Por isso não há tabela de convites: ou a proposta chega, ou não chega.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["profileId"],"properties":{"profileId":{"type":"string","format":"uuid"},"message":{"type":"string","description":"Recado pessoal no corpo do convite."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdInviteSpeaker"}},"/api/call4papers/me/reviews":{"get":{"tags":["Call for Papers"],"summary":"Minha fila de avaliação","description":"Une as propostas de todas as trilhas em que o convite foi aceito. Nunca inclui as próprias propostas.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersMeReviews"}},"/api/call4papers/me/invitations":{"get":{"tags":["Call for Papers"],"summary":"Convites pendentes (dono e avaliador)","description":"Convite sem resposta não é comitê — esta rota é o que permite cobrar quem ainda não respondeu.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersMeInvitations"}},"/api/call4papers/submissions/{sid}":{"get":{"tags":["Call for Papers"],"summary":"Detalhe de uma proposta","description":"Contextual. Dono e avaliador da trilha recebem o formato do comitê (com pareceres); quem propôs recebe o formato do palestrante, sem `internalNotes`. Quem não é nenhum dos três recebe 403.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSubmissionsBySid"},"put":{"tags":["Call for Papers"],"summary":"Edita a própria proposta (só em rascunho)","description":"Depois de enviada, a proposta muda por negociação, não por edição. Passado o prazo de submissão, o rascunho não pode mais ser enviado e por isso também não é editado: 400 `submissionsClosed`. Se o prazo for estendido, volta a ser editável.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CfpSubmissionInput"}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersSubmissionsBySid"}},"/api/call4papers/submissions/{sid}/submit":{"post":{"tags":["Call for Papers"],"summary":"Envia a proposta (rascunho → enviada)","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidSubmit"}},"/api/call4papers/submissions/{sid}/withdraw":{"post":{"tags":["Call for Papers"],"summary":"Retira a própria proposta","description":"Disponível a quem propôs até a confirmação. Acrescenta uma rodada `withdraw` ao histórico.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidWithdraw"}},"/api/call4papers/submissions/{sid}/review":{"put":{"tags":["Call for Papers"],"summary":"Cria ou atualiza a minha avaliação","description":"Uma avaliação por avaliador por proposta, então é upsert. `submit: false` guarda rascunho; enviada, trava. `internalNotes` fica entre comitê e donos — nunca chega a quem propôs.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["score"],"properties":{"score":{"type":"integer","minimum":1,"maximum":5},"recommendation":{"type":"string","enum":["accept","reject"]},"internalNotes":{"type":"string"},"commentsToSpeaker":{"type":"string"},"submit":{"type":"boolean","description":"false guarda como rascunho"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersSubmissionsBySidReview"}},"/api/call4papers/submissions/{sid}/reviews":{"get":{"tags":["Call for Papers"],"summary":"Consolidação das avaliações de uma proposta","description":"Dono ou avaliador da trilha. Quem propôs recebe 403 — `internalNotes` mora nesta resposta. O avaliador que ainda não enviou a sua recebe `pendingMyReview: true` em vez da média: ver o número antes de pontuar ancora a nota.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSubmissionsBySidReviews"}},"/api/call4papers/submissions/{sid}/vote":{"put":{"tags":["Call for Papers"],"summary":"Vota numa proposta (1 a 5)","description":"Um voto por pessoa, editável enquanto a janela estiver aberta. O voto aberto não é anônimo — identificar quem votou é o que impede voto múltiplo. Ninguém vota na própria proposta.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["value"],"properties":{"value":{"type":"integer","minimum":1,"maximum":5}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersSubmissionsBySidVote"},"delete":{"tags":["Call for Papers"],"summary":"Remove o meu voto","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersSubmissionsBySidVote"}},"/api/call4papers/submissions/{sid}/negotiation":{"get":{"tags":["Call for Papers"],"summary":"Histórico da negociação","description":"Só as partes — organização e quem propôs. Append-only, em ordem cronológica.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSubmissionsBySidNegotiation"}},"/api/call4papers/submissions/{sid}/counter-offer":{"post":{"tags":["Call for Papers"],"summary":"Contraproposta da organização","description":"Acrescenta uma rodada — nunca reescreve a anterior. `feeCurrency` é ignorado se enviado: a moeda é da comunidade e quem grava é o servidor.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"terms":{"$ref":"#/components/schemas/CfpNegotiationTerms"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidCounterOffer"}},"/api/call4papers/submissions/{sid}/counter-offer/retract":{"post":{"tags":["Call for Papers"],"summary":"A organização retira a contraproposta que fez","description":"Tira a oferta da mesa e devolve a proposta a `under_review`. Não é recusa. A rodada fica no histórico com tipo `retracted` — a timeline da negociação não pode ter buraco. Só vale para a última rodada, se for da organização e ainda estiver aberta.\n","parameters":[{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"O recado que acompanha a retirada."}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidCounterOfferRetract"}},"/api/call4papers/submissions/{sid}/speaker-counter":{"post":{"tags":["Call for Papers"],"summary":"Contraproposta de quem propôs","description":"Só quando a bola está com o palestrante (`counter_offered`). A réplica fica na mesma rodada.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"terms":{"$ref":"#/components/schemas/CfpNegotiationTerms"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidSpeakerCounter"}},"/api/call4papers/submissions/{sid}/accept":{"post":{"tags":["Call for Papers"],"summary":"Aceita a contraproposta em aberto","description":"Só a parte da vez — `counter_offered` é a bola com quem propôs; `speaker_countered`, com a organização.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidAccept"}},"/api/call4papers/submissions/{sid}/decline":{"post":{"tags":["Call for Papers"],"summary":"Recusa da organização","description":"Recusa é da organização; a desistência de quem propôs é `/withdraw`. São desfechos diferentes.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidDecline"}},"/api/call4papers/submissions/{sid}/decide":{"post":{"tags":["Call for Papers"],"summary":"Decide direto — aceitar ou recusar","description":"O ciclo inteiro de uma chamada simples. Também vale na avançada, quando não há o que negociar.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decision"],"properties":{"decision":{"type":"string","enum":["accept","reject"]},"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidDecide"}},"/api/call4papers/submissions/{sid}/confirm":{"post":{"tags":["Call for Papers"],"summary":"Confirma a agenda — o estado final do módulo","description":"`confirmed` significa \"proposta fechada e agenda confirmada\", não \"virou evento\". A exportação é ortogonal ao ciclo de vida.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"scheduledAt":{"type":"string","description":"Datetime flutuante, sem fuso: 2027-11-12T14:00:00.000"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersSubmissionsBySidConfirm"}},"/api/call4papers/submissions/{sid}/agreement":{"get":{"tags":["Call for Papers"],"summary":"A proposta fechada","description":"Projeção dos termos da última contraproposta anterior ao aceite. Sem negociação, valem os termos do próprio envio somados à política do edital.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"sid","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersSubmissionsBySidAgreement"}},"/api/call4papers/tracks/{trackId}":{"put":{"tags":["Call for Papers"],"summary":"Edita uma trilha","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"trackId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"purpose":{"type":"string","description":"O que a trilha busca e o que não busca"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersTracksByTrackId"},"delete":{"tags":["Call for Papers"],"summary":"Remove uma trilha","description":"Recusado enquanto houver proposta na trilha — a proposta ficaria órfã de régua.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"trackId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersTracksByTrackId"}},"/api/call4papers/tracks/{trackId}/reviewers":{"get":{"tags":["Call for Papers"],"summary":"Avaliadores de uma trilha","description":"Só donos. O convite tem estado — `invitedAt` sem resposta é pendente.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"trackId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersTracksByTrackIdReviewers"},"post":{"tags":["Call for Papers"],"summary":"Convida um avaliador para a trilha","description":"Qualquer dono convida — não há hierarquia entre donos, então ninguém vira gargalo.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"trackId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["profileId"],"properties":{"profileId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersTracksByTrackIdReviewers"}},"/api/call4papers/track-reviewers/{reviewerId}":{"delete":{"tags":["Call for Papers"],"summary":"Remove um avaliador de uma trilha","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"reviewerId","required":true,"schema":{"type":"string","format":"uuid"},"description":"Id do VÍNCULO, não do perfil: a mesma pessoa pode avaliar várias trilhas"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersTrackReviewersByReviewerId"}},"/api/call4papers/track-reviewers/{reviewerId}/accept":{"post":{"tags":["Call for Papers"],"summary":"Aceita o convite para avaliar","description":"Só o próprio convidado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"reviewerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersTrackReviewersByReviewerIdAccept"}},"/api/call4papers/track-reviewers/{reviewerId}/decline":{"post":{"tags":["Call for Papers"],"summary":"Recusa o convite para avaliar","description":"Só o próprio convidado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"reviewerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersTrackReviewersByReviewerIdDecline"}},"/api/call4papers/owners/{ownerId}":{"delete":{"tags":["Call for Papers"],"summary":"Remove um dono da chamada","description":"Recusado se for o último dono aceito — a chamada ficaria sem quem a administre.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"ownerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersOwnersByOwnerId"}},"/api/call4papers/owners/{ownerId}/accept":{"post":{"tags":["Call for Papers"],"summary":"Aceita o convite para ser dono","description":"Só o próprio convidado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"ownerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersOwnersByOwnerIdAccept"}},"/api/call4papers/owners/{ownerId}/decline":{"post":{"tags":["Call for Papers"],"summary":"Recusa o convite para ser dono","description":"Só o próprio convidado.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"ownerId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersOwnersByOwnerIdDecline"}},"/api/call4papers/event-dates/{dateId}":{"put":{"tags":["Call for Papers"],"summary":"Edita um dia da chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"dateId","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","example":"2027-11-12"},"startTime":{"type":"string","example":"09:00"},"endTime":{"type":"string","example":"18:00"},"order":{"type":"integer"}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersEventDatesByDateId"},"delete":{"tags":["Call for Papers"],"summary":"Remove um dia da chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"dateId","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersEventDatesByDateId"}},"/api/call4papers":{"post":{"tags":["Call for Papers"],"summary":"Abre uma chamada de trabalhos","description":"Quem pode abrir vem de `whoCanOpenCall` do space. Quem cria vira dono, com o convite já aceito. `speakerFeeCurrency` é gravado pelo servidor a partir da comunidade — se o cliente enviar, é ignorado.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CfpCallInput"}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papers"}},"/api/call4papers/{id}":{"get":{"tags":["Call for Papers"],"summary":"Detalhe de uma chamada","description":"Rascunho responde 404 para quem não administra — o payload não deve conter o que não foi publicado. O `status` é o efetivo: passado `submissionClosesAt`, uma chamada `open` sai como `closed` (ou `reviewing`, se há janela de avaliação ainda por vir ou em curso). As datas são horário de parede, sem fuso, e valem no fuso do país da comunidade, que vem em `timeZone` (IANA, ex. `America/Sao_Paulo`): \"até 23:59\" fecha às 23:59 locais.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersById"},"put":{"tags":["Call for Papers"],"summary":"Edita a chamada","description":"Dono da chamada, equipe ou admin. `status` não entra por aqui — há rota própria, com as transições verificadas. Rebaixar de `advanced` para `simple` é recusado depois que existir nota ou negociação registrada.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CfpCallInput"}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putCall4papersById"},"delete":{"tags":["Call for Papers"],"summary":"Exclui a chamada (soft delete)","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteCall4papersById"}},"/api/call4papers/{id}/status":{"patch":{"tags":["Call for Papers"],"summary":"Muda o status da chamada","description":"O organizador pode fechar antes do prazo, reabrir ou mover entre estados. Uma exceção vem das datas: passado `submissionClosesAt`, a chamada deixa de estar `open` sozinha — um job grava `closed` (ou `reviewing`) e a leitura já mostra isso antes. Para reabrir, estenda o prazo primeiro; reabrir com o prazo vencido devolve o status efetivo (`closed`), não `open`.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["draft","open","reviewing","deciding","closed","archived"]}}}}}},"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"patchCall4papersByIdStatus"}},"/api/call4papers/{id}/publish":{"post":{"tags":["Call for Papers"],"summary":"Publica a chamada","description":"Carimba `publishedAt` na primeira ida ao ar. Despublicar depois não apaga a data.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdPublish"}},"/api/call4papers/{id}/unpublish":{"post":{"tags":["Call for Papers"],"summary":"Despublica a chamada (volta a rascunho)","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdUnpublish"}},"/api/call4papers/{id}/close":{"post":{"tags":["Call for Papers"],"summary":"Encerra a chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdClose"}},"/api/call4papers/{id}/reopen":{"post":{"tags":["Call for Papers"],"summary":"Reabre a chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdReopen"}},"/api/call4papers/{id}/tracks":{"get":{"tags":["Call for Papers"],"summary":"Trilhas da chamada","description":"Cada trilha traz o `purpose` — a régua que o avaliador usa e que quem propõe lê antes de escolher.","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdTracks"},"post":{"tags":["Call for Papers"],"summary":"Cria uma trilha","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","purpose"],"properties":{"name":{"type":"string"},"purpose":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdTracks"}},"/api/call4papers/{id}/event-dates":{"get":{"tags":["Call for Papers"],"summary":"Em que dias a chamada acontece","description":"Uma linha por dia, não uma janela só — uma conferência de três dias tem três janelas, e uma janela única diria que a sessão pode cair às 3h da manhã.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdEventDates"},"post":{"tags":["Call for Papers"],"summary":"Acrescenta um dia à chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["date","startTime","endTime"],"properties":{"date":{"type":"string","example":"2027-11-12"},"startTime":{"type":"string","example":"09:00"},"endTime":{"type":"string","example":"18:00"},"order":{"type":"integer"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdEventDates"}},"/api/call4papers/{id}/owners":{"get":{"tags":["Call for Papers"],"summary":"Donos da chamada","description":"Todos com o mesmo poder. `addedByProfileId` é só auditoria, não hierarquia.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdOwners"},"post":{"tags":["Call for Papers"],"summary":"Convida outro dono","description":"O convidado precisa ter perfil na comunidade do header — o convite não é porta lateral para quem está fora dela.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["profileId"],"properties":{"profileId":{"type":"string","format":"uuid"}}}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdOwners"}},"/api/call4papers/{id}/submissions":{"get":{"tags":["Call for Papers"],"summary":"Propostas da chamada — contextual","description":"A mesma rota devolve coisas diferentes conforme quem pergunta, e isso é filtro de AUTORIZAÇÃO, não de query.\n* **dono** (`viewerRole: owner`) — todas as propostas enviadas, com pareceres,\n  notas internas e consolidação;\n* **avaliador** (`reviewer`) — só as da sua trilha, nunca a própria, e sem o autor\n  quando a chamada é cega;\n* **quem propôs** (`speaker`) — só as suas, pelo formatador que não conhece\n  `internalNotes`.\n\nQuem não é nenhum dos três recebe 403, não lista vazia.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdSubmissions"},"post":{"tags":["Call for Papers"],"summary":"Submete uma proposta","description":"`submit: false` guarda como rascunho. `requestedFeeCurrency` é gravado pelo servidor; `deliveryMode` só é perguntado — e exigido — em chamada híbrida. Passado o prazo de submissão (`submissionClosesAt`), nada novo entra: nem envio nem rascunho. Responde 400 `submissionsClosed`, para qualquer papel.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CfpSubmissionInput"}}}},"responses":{"201":{"description":"Criado com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postCall4papersByIdSubmissions"}},"/api/call4papers/{id}/my-submissions":{"get":{"tags":["Call for Papers"],"summary":"Minhas propostas nesta chamada","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdMySubmissions"}},"/api/call4papers/{id}/review-progress":{"get":{"tags":["Call for Papers"],"summary":"Andamento da avaliação","description":"Só donos. Quantas avaliações cada proposta recebeu e quanto cada avaliador já fez.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdReviewProgress"}},"/api/call4papers/{id}/votable-submissions":{"get":{"tags":["Call for Papers"],"summary":"A cédula do voto aberto","description":"Só campos públicos — nunca `internalNotes`. O que o placar mostra depende de `voteVisibility`: `hidden` (padrão recomendado) esconde tudo enquanto a janela está aberta, porque placar ao vivo cria efeito manada.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdVotableSubmissions"}},"/api/call4papers/{id}/vote-results":{"get":{"tags":["Call for Papers"],"summary":"Resultado da votação","description":"Respeita `voteVisibility`. Donos sempre veem; os demais, conforme a configuração e a janela.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getCall4papersByIdVoteResults"}},"/api/business-information":{"get":{"operationId":"getCommunitiesByCommunityIdBusinessInformation","tags":["Business"],"summary":"Lista ou consulta business information","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"postCommunitiesByCommunityIdBusinessInformation","tags":["Business"],"summary":"Cria ou executa business information","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["country","type"],"properties":{"country":{"type":"string","minLength":2,"maxLength":2,"description":"País é obrigatório."},"type":{"type":"string","enum":["individual","corporation"],"description":"Tipo de negócio é obrigatório."},"registerInformation":{"type":"object","description":"registerInformation deve ser um objeto."},"globalInformation":{"type":"object","description":"globalInformation deve ser um objeto."}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/business-information/submit":{"post":{"operationId":"postCommunitiesByCommunityIdBusinessInformationSubmit","tags":["Business"],"summary":"Cria ou executa submit","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/business-information/status":{"get":{"operationId":"getCommunitiesByCommunityIdBusinessInformationStatus","tags":["Business"],"summary":"Lista ou consulta status","description":"Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/auth/register":{"post":{"tags":["Auth"],"summary":"Registra um novo membro","description":"Cria um membro e, quando o header `X-CommunityId` é enviado, já o vincula\nà comunidade com o papel `MEMBER`. Não exige autenticação.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fullName","email","password"],"properties":{"fullName":{"type":"string","example":"Maria Silva"},"email":{"type":"string","format":"email","example":"maria.silva@memberfy.net"},"password":{"type":"string","format":"password","minLength":8,"example":"Senha@123","description":"Regra única (AUTH-5): mínimo de 8 caracteres, com letra maiúscula, letra minúscula e número. Fora dela, 400 com param = password e a regra que faltou."}}}}}},"responses":{"201":{"description":"Membro criado com sucesso.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"member":{"$ref":"#/components/schemas/Member"},"token":{"type":"string"}}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAuthRegister"}},"/api/auth/login":{"post":{"tags":["Auth"],"summary":"Autentica um membro e retorna o JWT","description":"Endpoint público. O token retornado vale 7 dias.","security":[],"parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password"],"properties":{"email":{"type":"string","format":"email","example":"david@memberfy.net"},"password":{"type":"string","format":"password","example":"Senha@123"}}}}}},"responses":{"200":{"description":"Login realizado com sucesso.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"type":"object","properties":{"member":{"$ref":"#/components/schemas/Member"},"token":{"type":"string","description":"JWT para o header Authorization."},"mustChangePassword":{"type":"boolean"}}}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"}},"operationId":"postAuthLogin"}},"/api/auth/me":{"get":{"tags":["Auth"],"summary":"Retorna o membro autenticado","description":"Traz `isSuperAdmin`, o mesmo flag que o login devolve, para o app reconstruir a sessão no reload sem rebaixar o SuperAdmin. Traz também `document` (CPF ou CNPJ, só dígitos) e `documentType` (`CPF` | `CNPJ`), ambos opcionais e null quando não há, para preencher o checkout. São gravados no primeiro pagamento confirmado (se a conta não tem) ou quando o comprador manda `saveDocument: true` no `POST /api/checkout`. Só o próprio membro lê; nenhuma resposta de comunidade traz esses campos.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Dados do membro autenticado.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/SuccessResponse"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Member"}}}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"operationId":"getAuthMe"}},"/api/auth/change-password":{"put":{"tags":["Auth"],"summary":"Altera a senha do membro autenticado","description":"Senha atual errada é erro de negócio, não de sessão: responde **400** com\n`errors[0].param = currentPassword` e a mensagem traduzida pelo\n`Accept-Language` (AUTH-6). O 401 fica só para token ausente ou inválido.\n","parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["currentPassword","newPassword"],"properties":{"currentPassword":{"type":"string","format":"password","example":"oldpassword"},"newPassword":{"type":"string","format":"password","minLength":8,"example":"NovaSenha@1","description":"Regra única (AUTH-5): mínimo de 8 caracteres, com letra maiúscula, letra minúscula e número."}}}}}},"responses":{"200":{"description":"Senha alterada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Validação (`newPassword` fora da regra, `currentPassword` ausente) ou\nsenha atual incorreta, com `param = currentPassword`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"A senha atual está incorreta.","errors":[{"param":"currentPassword","message":"A senha atual está incorreta."}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"}},"operationId":"putAuthChangePassword"}},"/api/auth/recovery-password":{"post":{"tags":["Auth"],"summary":"Inicia a recuperação de senha","description":"Dispara o email de recuperação. Responde sucesso mesmo quando o email não\nexiste, de propósito — não revela quais emails estão cadastrados.\n","security":[],"parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","example":"maria.silva@memberfy.net"}}}}}},"responses":{"200":{"description":"Solicitação registrada (resposta idêntica para email existente ou não).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"}},"operationId":"postAuthRecoveryPassword"}},"/api/auth/set-password":{"post":{"tags":["Auth"],"summary":"Define a senha pelo link do convite","description":"Sem login: o link de uso único do e-mail de convite\n(`https://<app da comunidade>/_/auth/set-password?id=<id>&token=<token>`) é a\ncredencial. Vale 7 dias e uma vez. A senha segue a regra do cadastro\n(mínimo de 8 caracteres, com letra maiúscula, letra minúscula e número; AUTH-5). `id` inexistente ou `token` errado: 400 com\n`param = token`. Link já usado ou vencido: 410 com `param = token`. Limite\nde 10 requisições por IP a cada 15 minutos (429). Não abre sessão: depois,\na pessoa entra com `POST /api/auth/login`, e `data.email` serve para\npreencher o campo.\n","security":[],"parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id","token","password"],"properties":{"id":{"type":"string","format":"uuid","example":"c9c35f8c-7757-4d6b-bd3a-e6ffb6385e66"},"token":{"type":"string","example":"a3f9c2e1b7d84f6a9e0c1b2d3e4f5a6b"},"password":{"type":"string","format":"password","minLength":8,"example":"Senha@123"}}}}}},"responses":{"200":{"description":"Senha definida (`data.email`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"410":{"description":"Link já usado ou vencido.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"description":"Requisições demais deste IP.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAuthSetPassword"}},"/api/activity-logs":{"get":{"operationId":"getActivityLogs","tags":["Activity Logs"],"summary":"Lista os registros de atividade da comunidade","description":"Linha do tempo única do que aconteceu na comunidade do `X-CommunityId`, mais recentes\nprimeiro. Exige owner ou admin dessa comunidade (moderator e member recebem 403).\n\nTrês origens (`source`):\n- `team`: ações da equipe sobre assinaturas (cancelar, reativar, desconto, cortesia,\n  prorrogação, adicional, link de pagamento). `details` traz o que mudou (`before`,\n  `after`) e o papel de quem agiu (`actorRole`).\n- `assistant`: o que um assistente de IA (Claude, ChatGPT, Cursor) fez pela conexão MCP\n  — ferramentas chamadas, conexões autorizadas e revogadas. `details.args` é um\n  **resumo** dos argumentos: tokens de confirmação e de idempotência, imagens em base64\n  e qualquer campo com nome de segredo ficam de fora; textos são cortados em 200\n  caracteres e listas de objetos viram `{ count }`.\n- `members`: ações de membros que pontuam no ranking (publicar, comentar, curtir,\n  participar de evento, se inscrever em curso, login diário). `details.points` é a\n  pontuação ganha.\n\nCada item: `id`, `at`, `source`, `actor` (`profileId`, `name`, `avatarUrl`; `profileId`\nnulo quando quem agiu não tem perfil na comunidade; `actor` nulo quando não se sabe),\n`action` (chave estável para o app traduzir: `subscription.CANCEL_NOW`,\n`mcp.tool.create_post`, `mcp.oauth.consent`, `game.LIKE_POST`), `actionLabel` (a ação\nno idioma do `Accept-Language`), `target` (`type`, `id`, `label`; nulo no login\ndiário) e `details`.\n\nQuando o alvo vive dentro de um space (`target.type` `content`, `event`, `status` ou\n`course`), `target` traz também `spaceId`, para abrir o item no space dele. Vem `null`\nquando o item foi excluído ou não está em nenhum space; nos outros tipos o campo não\naparece.\n\nFiltros: `source`, `profileId` (a pessoa que agiu; perfil de outra comunidade não traz\nnada), `from` e `to` (ISO 8601; uma data sem hora em `to` inclui o dia inteiro, em UTC).\nA paginação é exata entre as três origens.\n","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"},{"in":"query","name":"source","schema":{"type":"string","enum":["team","assistant","members"]},"description":"Só uma origem. Sem ele, as três."},{"in":"query","name":"profileId","schema":{"type":"string","format":"uuid"},"description":"Só o que essa pessoa fez."},{"in":"query","name":"from","schema":{"type":"string","format":"date-time"},"description":"A partir de (inclusive)."},{"in":"query","name":"to","schema":{"type":"string","format":"date-time"},"description":"Até (inclusive). `2026-10-06` inclui o dia todo."},{"in":"query","name":"page","schema":{"type":"integer","minimum":1,"default":1}},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Lista paginada, mais recentes primeiro.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Registros de atividade obtidos com sucesso","data":[{"id":"7c1e9a2b-3d4f-4a5b-8c6d-9e0f1a2b3c4d","at":"2026-10-06T14:32:10.512Z","source":"team","actor":{"profileId":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","name":"Maria Silva","avatarUrl":null},"action":"subscription.DISCOUNT_SET","actionLabel":"Aplicou desconto na assinatura","target":{"type":"subscription","id":"d4f7a2b9-6c1e-4a3d-9b8f-2e5c7a1d3f60","label":"João Souza · Plano Pro mensal"},"details":{"percent":20,"endsAt":"2026-12-31T23:59:59.000Z","actorRole":"owner","before":{"discountPercent":null},"after":{"discountPercent":"20"}}},{"id":"2b4d6f8a-1c3e-4a5b-9d7f-0e2c4a6b8d1f","at":"2026-10-06T13:05:44.020Z","source":"assistant","actor":{"profileId":"6a8c0e2f-4b6d-4f8a-b0c2-e4f6a8b0c2d4","name":"Maria Silva","avatarUrl":null},"action":"mcp.tool.create_post","actionLabel":"Assistente de IA usou a ferramenta create_post","target":{"type":"mcp_tool","id":"create_post","label":"create_post"},"details":{"event":"tool.call","tool":"create_post","status":"ok","httpStatus":201,"durationMs":412,"error":null,"client":"Claude","args":{"title":"Boas-vindas à turma de outubro","body":"<p>Olá, pessoal!</p>"}}},{"id":"9f1a3c5e-7b2d-4e6f-8a0c-1d3e5f7a9b2c","at":"2026-10-06T12:47:03.881Z","source":"members","actor":{"profileId":"1e3c5a7b-9d2f-4b6a-8c0e-2f4a6b8c0d1e","name":"Ana Lima","avatarUrl":"https://cdn.memberfy.net/avatars/ana.jpg"},"action":"game.COMMENT_POST","actionLabel":"Comentar","target":{"type":"content","id":"5b7d9f1a-3c5e-4a7b-9d1f-3a5c7e9b1d3f","label":"Boas-vindas à turma de outubro","spaceId":"3e5a7c9b-1d3f-4b5d-8f7a-9c1e3b5d7f9a"},"details":{"points":5,"sectionId":null}}],"pagination":{"page":1,"limit":20,"total":3,"totalPages":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/admin/fee-rules":{"get":{"tags":["Admin"],"summary":"Lista as regras de taxa da plataforma, com os juros de parcelamento","description":"Exige SuperAdmin. Cada regra traz suas condições, a taxa da plataforma e\n`installmentRates`: os juros de parcelamento da Memberfy, % total sobre o valor\npor número de parcelas no cartão (`{ \"2\": \"4.29\", ..., \"12\": \"6.00\" }`; 1× é 0).\n","parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Regras.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminFeeRules"},"post":{"tags":["Admin"],"summary":"Cria uma regra de taxa da plataforma","description":"Exige SuperAdmin. Toda alteração grava na auditoria (quem, quando, antes e depois). Erro de validação: 400 com `errors[].param` no campo e mensagem traduzida. Obrigatórios: `name`, `percentageFee`, `fixedFee`. `anticipationFee` padrão 3;\njuros de parcelamento padrão 0. Dica: crie inativa (`isActive: false`), simule e ative.\n","parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","percentageFee","fixedFee"],"properties":{"name":{"type":"string","maxLength":120},"priority":{"type":"integer","minimum":-1000,"maximum":1000,"description":"Maior vence; empate: a mais antiga"},"minAmount":{"type":"number","nullable":true,"description":"Condição: venda a partir de; null = sem piso"},"maxAmount":{"type":"number","nullable":true,"description":"Condição: venda até; null = sem teto"},"description":{"type":"string","nullable":true,"maxLength":500},"percentageFee":{"type":"number","description":"% da venda, 0 a menos de 100, até 2 casas"},"fixedFee":{"type":"number","description":"Valor fixo por venda, >= 0"},"transferFee":{"type":"number","nullable":true,"description":"Taxa por saque, >= 0"},"anticipationFee":{"type":"number","description":"% de antecipação (só quando a comunidade pede), 0 a menos de 100"},"installmentRates":{"type":"object","description":"Juros de parcelamento da Memberfy, % total por parcelas: { \"2\": 4.29, ..., \"12\": 6.00 }"},"currency":{"type":"string","nullable":true,"enum":["BRL","USD","EUR","GBP","MXN","ARS"],"description":"Condição; null = qualquer"},"countryCode":{"type":"string","nullable":true,"description":"Condição; ISO de 2 letras; null = qualquer"},"paymentMethod":{"type":"string","nullable":true,"enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER","WALLET_BALANCE"],"description":"Condição; null = qualquer"},"productType":{"type":"string","nullable":true,"enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"],"description":"Condição; null = qualquer"},"validFrom":{"type":"string","format":"date-time","nullable":true},"validUntil":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"}}}}}},"responses":{"201":{"description":"A regra criada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminFeeRules"}},"/api/admin/fee-rules/{id}/installment-rates":{"put":{"tags":["Admin"],"summary":"Edita os juros de parcelamento de uma regra de taxa da plataforma","description":"Exige SuperAdmin. `rates` é um mapa `{ \"2\": 4.29, ..., \"12\": 6.00 }`: chaves de \"2\"\na \"12\", valores de 0 a menos de 100 com até 2 casas. Só as linhas enviadas mudam.\nValor fora disso: 400 com `param = rates`. Regra inexistente: 404.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rates"],"properties":{"rates":{"type":"object","additionalProperties":{"type":"number"}}}}}}},"responses":{"200":{"description":"Regra atualizada.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminFeeRulesByIdInstallmentRates"}},"/api/admin/communities/{communityId}/fee-overrides":{"get":{"tags":["Admin"],"summary":"Lista os overrides de taxa de uma comunidade e os juros efetivos","description":"Exige SuperAdmin. `overrides` traz cada override com `installmentRates` (linha\nnula = usa a regra da plataforma); `effectiveInstallmentRates` é o que as vendas\nda comunidade usam hoje, linha a linha.\n","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Overrides e juros efetivos.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminCommunitiesByCommunityIdFeeOverrides"},"post":{"tags":["Admin"],"summary":"Cria um override de taxa para uma comunidade","description":"Exige SuperAdmin. Toda alteração grava na auditoria (quem, quando, antes e depois). Erro de validação: 400 com `errors[].param` no campo e mensagem traduzida. Todo campo é opcional: vazio (ou `null`) usa o valor da regra da plataforma, campo a\ncampo (FIN-58). As condições (`currency`, `countryCode`, `paymentMethod`, `productType`) e a\nvalidade restringem quando o override vale. `reason` é nota interna.\n","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","nullable":true,"maxLength":500},"percentageFee":{"type":"number","description":"% da venda, 0 a menos de 100, até 2 casas"},"fixedFee":{"type":"number","description":"Valor fixo por venda, >= 0"},"transferFee":{"type":"number","nullable":true,"description":"Taxa por saque, >= 0"},"anticipationFee":{"type":"number","description":"% de antecipação (só quando a comunidade pede), 0 a menos de 100"},"installmentRates":{"type":"object","description":"Juros de parcelamento da Memberfy, % total por parcelas: { \"2\": 4.29, ..., \"12\": 6.00 }"},"currency":{"type":"string","nullable":true,"enum":["BRL","USD","EUR","GBP","MXN","ARS"],"description":"Condição; null = qualquer"},"countryCode":{"type":"string","nullable":true,"description":"Condição; ISO de 2 letras; null = qualquer"},"paymentMethod":{"type":"string","nullable":true,"enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER","WALLET_BALANCE"],"description":"Condição; null = qualquer"},"productType":{"type":"string","nullable":true,"enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"],"description":"Condição; null = qualquer"},"validFrom":{"type":"string","format":"date-time","nullable":true},"validUntil":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"}}}}}},"responses":{"201":{"description":"O override criado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminCommunitiesByCommunityIdFeeOverrides"}},"/api/admin/fee-rules/simulate":{"post":{"tags":["Admin"],"summary":"Simula qual regra de taxa e override valem para uma venda, e o resultado","description":"Exige SuperAdmin. Mesma resolução de uma venda real (condições da regra filtram desde o\nFIN-57; campo vazio do override usa a regra, FIN-58). Responde `rule` (`id`, `name`,\n`priority`), `override` (`id`, `reason`), `effective` (`percentageFee`, `fixedFee`,\n`transferFee` e `installmentRate` aplicados) e `result` (o cálculo da taxa da plataforma e\ndos juros de parcelamento, como a comunidade vê). Nunca traz custo do provedor. Serve para\nver o efeito antes de salvar ou ativar uma regra.\n","parameters":[{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["amount","paymentMethod","productType"],"properties":{"communityId":{"type":"string","format":"uuid","description":"Para considerar o override da comunidade"},"amount":{"type":"number"},"paymentMethod":{"type":"string","enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO"]},"productType":{"type":"string","enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"]},"installments":{"type":"integer","minimum":1,"maximum":12},"currency":{"type":"string","enum":["BRL","USD","EUR","GBP","MXN","ARS"],"description":"Padrão BRL"},"countryCode":{"type":"string","description":"Padrão BR"},"feePayer":{"type":"string","enum":["ORGANIZATION","BUYER"],"description":"Padrão BUYER, o mesmo de um produto (FIN-56)"},"installmentInterestPayer":{"type":"string","enum":["ORGANIZATION","BUYER"],"description":"Padrão BUYER"}}}}}},"responses":{"200":{"description":"Regra aplicada e resultado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminFeeRulesSimulate"}},"/api/admin/fee-rules/{id}":{"get":{"tags":["Admin"],"summary":"Uma regra de taxa da plataforma, com o histórico de alterações","description":"Exige SuperAdmin. Todos os campos e `history` (as últimas 100 alterações: `action`, `actorMemberId`, `before`, `after`, `createdAt`).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"A regra.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminFeeRulesById"},"put":{"tags":["Admin"],"summary":"Edita uma regra de taxa da plataforma (todos os campos)","description":"Exige SuperAdmin. Toda alteração grava na auditoria (quem, quando, antes e depois). Erro de validação: 400 com `errors[].param` no campo e mensagem traduzida. Só os campos enviados mudam; `null` limpa um campo que aceita vazio (condições,\n`transferFee`, datas). `minAmount` não pode passar de `maxAmount`, nem `validFrom` de\n`validUntil`. **Atenção:** ativar ou mudar uma regra muda o que as vendas reais cobram a\npartir de agora; use `POST /api/admin/fee-rules/simulate` antes. Uma edição que tira de uso\na última **regra geral** em vigor (ativa, válida hoje e sem nenhuma condição) é recusada com\n400 e `param = id`: `isActive: false`, qualquer condição nova (país, método, tipo de produto,\nmoeda, faixa de valor), `validUntil` no passado ou `validFrom` no futuro. Ative outra regra antes.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"priority":{"type":"integer","minimum":-1000,"maximum":1000,"description":"Maior vence; empate: a mais antiga"},"minAmount":{"type":"number","nullable":true,"description":"Condição: venda a partir de; null = sem piso"},"maxAmount":{"type":"number","nullable":true,"description":"Condição: venda até; null = sem teto"},"description":{"type":"string","nullable":true,"maxLength":500},"percentageFee":{"type":"number","description":"% da venda, 0 a menos de 100, até 2 casas"},"fixedFee":{"type":"number","description":"Valor fixo por venda, >= 0"},"transferFee":{"type":"number","nullable":true,"description":"Taxa por saque, >= 0"},"anticipationFee":{"type":"number","description":"% de antecipação (só quando a comunidade pede), 0 a menos de 100"},"installmentRates":{"type":"object","description":"Juros de parcelamento da Memberfy, % total por parcelas: { \"2\": 4.29, ..., \"12\": 6.00 }"},"currency":{"type":"string","nullable":true,"enum":["BRL","USD","EUR","GBP","MXN","ARS"],"description":"Condição; null = qualquer"},"countryCode":{"type":"string","nullable":true,"description":"Condição; ISO de 2 letras; null = qualquer"},"paymentMethod":{"type":"string","nullable":true,"enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER","WALLET_BALANCE"],"description":"Condição; null = qualquer"},"productType":{"type":"string","nullable":true,"enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"],"description":"Condição; null = qualquer"},"validFrom":{"type":"string","format":"date-time","nullable":true},"validUntil":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"A regra depois da edição.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"description":"Erro de validação, ou a edição tiraria de uso a última regra geral em vigor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Esta é a última regra geral em vigor. Ative outra regra antes de excluí-la ou desativá-la.","errors":[{"param":"id","message":"Esta é a última regra geral em vigor. Ative outra regra antes de excluí-la ou desativá-la."}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminFeeRulesById"},"delete":{"tags":["Admin"],"summary":"Exclui uma regra de taxa da plataforma","description":"Exige SuperAdmin; auditado (`action = DELETE`). A exclusão é lógica: a regra deixa de\nprecificar vendas e some da listagem, da consulta, da simulação e do cálculo de taxas,\nmas as vendas que já a usaram continuam resolvendo a regra por id nos relatórios e na\nconciliação. Não é possível excluir a última **regra geral** em vigor (ativa, válida hoje\ne sem nenhuma condição): a resposta é 400 com `param = id`, pedindo para ativar outra\nregra antes. Regra inexistente ou já excluída: 404.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Regra excluída.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Regra de taxa excluída.","data":{"id":"3f6c2a1e-8b7d-4c1a-9e2f-5a4b3c2d1e0f","deletedAt":"2026-10-06T23:50:00.000Z"}}}}},"400":{"description":"É a última regra geral em vigor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"success":false,"message":"Esta é a última regra geral em vigor. Ative outra regra antes de excluí-la ou desativá-la.","errors":[{"param":"id","message":"Esta é a última regra geral em vigor. Ative outra regra antes de excluí-la ou desativá-la."}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteAdminFeeRulesById"}},"/api/admin/fee-rules/{id}/activate":{"post":{"tags":["Admin"],"summary":"Ativa uma regra de taxa da plataforma","description":"Exige SuperAdmin; auditado. Passa a valer nas vendas que casarem com as condições dela (FIN-57).","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"A regra ativa.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminFeeRulesByIdActivate"}},"/api/admin/fee-rules/{id}/deactivate":{"post":{"tags":["Admin"],"summary":"Desativa uma regra de taxa da plataforma","description":"Exige SuperAdmin; auditado. Desativar tira a regra de uso sem excluí-la. Sem nenhuma regra\nativa que case, a venda falha. Por isso não é possível desativar a última **regra geral**\nem vigor (ativa, válida hoje e sem nenhuma condição: país, método, tipo de produto, moeda\nou faixa de valor): a resposta é 400 com `param = id`, pedindo para ativar outra regra antes.\n","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"A regra inativa.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminFeeRulesByIdDeactivate"}},"/api/admin/communities/{communityId}/fee-overrides/installment-rates":{"put":{"tags":["Admin"],"summary":"Edita os juros de parcelamento de uma comunidade (override)","description":"Exige SuperAdmin. `rates` como na regra, e `null` numa linha volta aquela linha\npara a regra da plataforma. Grava no override sem condições da comunidade, criado\nquando não existe (os demais campos ficam vazios e usam a regra). A resposta traz\no override e `effectiveInstallmentRates`.\n","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rates"],"properties":{"rates":{"type":"object","additionalProperties":{"type":"number","nullable":true}}}}}}},"responses":{"200":{"description":"Override gravado.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminCommunitiesByCommunityIdFeeOverridesInstallmentRates"}},"/api/admin/communities/{communityId}/fee-overrides/{id}":{"get":{"tags":["Admin"],"summary":"Um override de taxa da comunidade, com o histórico","description":"Exige SuperAdmin. Todos os campos e `history` (últimas 100 alterações).","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"O override.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminCommunitiesByCommunityIdFeeOverridesById"},"put":{"tags":["Admin"],"summary":"Edita um override de taxa da comunidade (todos os campos)","description":"Exige SuperAdmin. Toda alteração grava na auditoria (quem, quando, antes e depois). Erro de validação: 400 com `errors[].param` no campo e mensagem traduzida. Só os campos enviados mudam; `null` faz o campo voltar a usar a regra da plataforma.\n","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","nullable":true,"maxLength":500},"percentageFee":{"type":"number","description":"% da venda, 0 a menos de 100, até 2 casas"},"fixedFee":{"type":"number","description":"Valor fixo por venda, >= 0"},"transferFee":{"type":"number","nullable":true,"description":"Taxa por saque, >= 0"},"anticipationFee":{"type":"number","description":"% de antecipação (só quando a comunidade pede), 0 a menos de 100"},"installmentRates":{"type":"object","description":"Juros de parcelamento da Memberfy, % total por parcelas: { \"2\": 4.29, ..., \"12\": 6.00 }"},"currency":{"type":"string","nullable":true,"enum":["BRL","USD","EUR","GBP","MXN","ARS"],"description":"Condição; null = qualquer"},"countryCode":{"type":"string","nullable":true,"description":"Condição; ISO de 2 letras; null = qualquer"},"paymentMethod":{"type":"string","nullable":true,"enum":["CREDIT_CARD","DEBIT_CARD","PIX","BOLETO","BANK_TRANSFER","WALLET_BALANCE"],"description":"Condição; null = qualquer"},"productType":{"type":"string","nullable":true,"enum":["SUBSCRIPTION","ONE_TIME","INSTALLMENT"],"description":"Condição; null = qualquer"},"validFrom":{"type":"string","format":"date-time","nullable":true},"validUntil":{"type":"string","format":"date-time","nullable":true},"isActive":{"type":"boolean"}}}}}},"responses":{"200":{"description":"O override depois da edição.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminCommunitiesByCommunityIdFeeOverridesById"},"delete":{"tags":["Admin"],"summary":"Exclui um override de taxa da comunidade","description":"Exige SuperAdmin; auditado (`action = DELETE`). A exclusão é lógica: o override some da\nlistagem e do cálculo, e a comunidade volta a usar a regra da plataforma. Vendas que já o\nusaram continuam resolvendo o override por id nos relatórios e na conciliação. Override\ninexistente, já excluído ou de outra comunidade: 404.\n","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Override excluído.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"},"example":{"success":true,"message":"Regra de taxa excluída.","data":{"id":"7a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d","deletedAt":"2026-10-06T23:50:00.000Z"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"deleteAdminCommunitiesByCommunityIdFeeOverridesById"}},"/api/admin/communities/{communityId}/fee-overrides/{id}/activate":{"post":{"tags":["Admin"],"summary":"Ativa um override de taxa da comunidade","description":"Exige SuperAdmin; auditado.","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"O override ativo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminCommunitiesByCommunityIdFeeOverridesByIdActivate"}},"/api/admin/communities/{communityId}/fee-overrides/{id}/deactivate":{"post":{"tags":["Admin"],"summary":"Desativa um override de taxa da comunidade","description":"Exige SuperAdmin; auditado. A comunidade volta a usar a regra da plataforma. Para tirar o override de vez, use a exclusão.","parameters":[{"in":"path","name":"communityId","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"O override inativo.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminCommunitiesByCommunityIdFeeOverridesByIdDeactivate"}},"/api/admin/communities/provision":{"post":{"tags":["Admin"],"summary":"Cria ou executa provision","description":"Endpoint administrativo — exige SuperAdmin. Sujeito a verificação de papel (RBAC).","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["communityName","communitySlug","domain","adminEmail","adminPassword","adminFullName"],"properties":{"communityName":{"type":"string","minLength":2,"maxLength":100,"description":"validation.required"},"communitySlug":{"type":"string","minLength":2,"maxLength":50,"description":"validation.required"},"domain":{"type":"string","minLength":4,"maxLength":100,"description":"validation.required"},"adminEmail":{"type":"string","format":"email","description":"validation.required"},"adminPassword":{"type":"string","minLength":8,"description":"Regra única de senha (AUTH-5): mínimo de 8 caracteres, com letra maiúscula, letra minúscula, número e caractere especial"},"adminFullName":{"type":"string","minLength":2,"maxLength":100,"description":"validation.required"}}}}}},"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminCommunitiesProvision"}},"/api/admin/business-information":{"get":{"tags":["Admin"],"summary":"Consulta business information","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminBusinessInformation"}},"/api/admin/business-information/{id}/status":{"put":{"tags":["Admin"],"summary":"Atualiza business information :id status","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminBusinessInformationByIdStatus"}},"/api/admin/payout/settings":{"get":{"tags":["Admin"],"summary":"Consulta payout settings","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminPayoutSettings"}},"/api/admin/payout/settings/{id}/status":{"put":{"tags":["Admin"],"summary":"Atualiza payout settings :id status","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"putAdminPayoutSettingsByIdStatus"}},"/api/admin/payout/pagarme/sync":{"post":{"tags":["Admin"],"summary":"Executa payout pagarme sync","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminPayoutPagarmeSync"}},"/api/admin/payout/pagarme/recipient":{"get":{"tags":["Admin"],"summary":"Consulta payout pagarme recipient","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminPayoutPagarmeRecipient"}},"/api/admin/payout/pagarme/balance":{"get":{"tags":["Admin"],"summary":"Consulta payout pagarme balance","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"200":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"getAdminPayoutPagarmeBalance"}},"/api/admin/payout/pagarme/sync-from":{"post":{"tags":["Admin"],"summary":"Executa payout pagarme sync from","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminPayoutPagarmeSyncFrom"}},"/api/admin/payout/pagarme/sync-to":{"post":{"tags":["Admin"],"summary":"Executa payout pagarme sync to","description":"Endpoint administrativo — exige SuperAdmin.","parameters":[{"$ref":"#/components/parameters/CommunityIdHeader"},{"$ref":"#/components/parameters/AcceptLanguageHeader"}],"responses":{"201":{"description":"Operação realizada com sucesso.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/InternalError"}},"operationId":"postAdminPayoutPagarmeSyncTo"}}}}