{"openapi":"3.1.0","info":{"title":"IndicaSaaS — API","version":"1.0.0","description":"Marketplace de programas de afiliados para SaaS — multi-gateway, Brasil-first.\n\n**Dois lados:** o **Afiliado** (descobre programas, gera links/deeplinks, configura postback, acompanha cliques/vendas/comissões) e o **Dono do SaaS / Anunciante** (cria o SaaS e programas, conecta gateway, aprova afiliados, vê analytics, registra repasses, gerencia a equipe).\n\n**Superfícies & auth:**\n- `/api/public/*` — catálogo público, sem auth.\n- `/api/v1/*` — marketplace autenticado (cookie de sessão Better Auth). Escrita do anunciante exige role owner/admin.\n- `/sdk/v1/*` — SDK do widget, bearer `sk_` (no backend do SaaS).\n- `/api/auth/*` — Better Auth (magic link, Google, passkey, 2FA, organization/membros).\n- `/webhooks/*` — eventos de gateway (assinatura verificada).\n- `/go/:code`, `/cread` — redirect/deeplink de afiliado.\n\nAtribuição last-click, refund-hold + clawback, postback S2S. Detalhes em /docs.","contact":{"name":"IndicaSaaS","url":"https://indicasaas.com/docs"}},"servers":[{"url":"/","description":"origem atual (preview/prod)"}],"tags":[{"name":"Catálogo","description":"Público, sem auth — descoberta de programas e SaaS."},{"name":"Conta","description":"Sessão, perfil/foto do usuário, contratos, preferências e link-preview (ambos os lados)."},{"name":"Afiliado","description":"Lado do afiliado: afiliações, perfil/canais, links/deeplink, postback e analytics próprios."},{"name":"Anunciante","description":"Lado do dono do SaaS: SaaS/anunciante, programas, afiliados, gateways, repasses e analytics."},{"name":"SDK","description":"Widget \"indicar e ganhar\" — chamado do BACKEND do SaaS com bearer `sk_`."},{"name":"Tracking","description":"Redirect de link de afiliado e deeplink (grava clique + atribuição)."},{"name":"Webhooks","description":"Recebimento de eventos de gateway (assinatura verificada; não chamar manualmente)."},{"name":"Auth","description":"Better Auth em `/api/auth/*` (magic link, Google, passkey, 2FA, organization/membros)."}],"components":{"securitySchemes":{"cookieSession":{"type":"apiKey","in":"cookie","name":"better-auth.session_token","description":"Cookie de sessão emitido por Better Auth (`/api/auth/*`)."},"bearerSk":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_*","description":"Secret key do SDK (`sk_live_...`). Use no backend do SaaS, nunca no browser."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}},"example":{"error":{"code":"invalid_body"}}},"Advertiser":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"website":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"category":{"type":["string","null"]},"description":{"type":["string","null"]},"status":{"type":"string","enum":["active","paused","archived"]}}},"Program":{"type":"object","properties":{"id":{"type":"string"},"advertiserId":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"terms":{"type":["string","null"],"description":"regras próprias do programa"},"commissionType":{"type":"string","enum":["percent","fixed"]},"commissionValue":{"type":"integer","description":"percent = basis points (2000 = 20%); fixed = centavos"},"currency":{"type":"string","example":"BRL"},"recurrence":{"type":"string","enum":["first_only","first_n","lifetime"]},"recurrenceN":{"type":["integer","null"]},"cookieWindowDays":{"type":"integer","enum":[7,14,30]},"attributionModel":{"type":"string","enum":["last_click","first_click"]},"newCustomersOnly":{"type":"boolean"},"autoApproveAffiliates":{"type":"boolean"},"couponEnabled":{"type":"boolean"},"refundHoldDaysCard":{"type":"integer","example":120},"refundHoldDaysPix":{"type":"integer","example":7},"allowedPromoTypes":{"type":["array","null"],"items":{"type":"string"}},"isPublic":{"type":"boolean"},"status":{"type":"string","enum":["draft","active","paused"]},"pendingChange":{"type":["object","null"],"description":"mudança agendada com aviso prévio","properties":{"summary":{"type":"string"},"effectiveAt":{"type":"integer"}}}}},"Affiliation":{"type":"object","properties":{"id":{"type":"string"},"programId":{"type":"string"},"status":{"type":"string","enum":["pending","active","paused","rejected"]},"linkCode":{"type":"string"},"couponCode":{"type":["string","null"]},"postbackUrl":{"type":["string","null"],"description":"URL de postback S2S com macros"},"link":{"type":"string","description":"URL pronta do link de afiliado (go.../<linkCode>)"}}},"SaasItem":{"type":"object","properties":{"orgId":{"type":"string"},"name":{"type":"string"},"slug":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"hasAdvertiser":{"type":"boolean"},"status":{"type":"string","enum":["active","paused","archived"]},"role":{"type":"string","enum":["owner","admin","member"]},"isActive":{"type":"boolean","description":"é o SaaS ativo (org ativa da sessão)"}}},"AffiliateProfile":{"type":"object","properties":{"displayName":{"type":["string","null"]},"companyName":{"type":["string","null"]},"taxId":{"type":["string","null"]},"pixKey":{"type":["string","null"],"description":"chave Pix p/ o anunciante repassar a comissão"},"website":{"type":["string","null"]},"phone":{"type":["string","null"]},"address":{"type":["string","null"]},"country":{"type":["string","null"]},"audience":{"type":["string","null"]},"notes":{"type":["string","null"]},"promotionalTypes":{"type":"array","items":{"type":"string"}},"primaryType":{"type":["string","null"]},"documents":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"url":{"type":"string"}}}}}},"AffiliateChannel":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"description":{"type":["string","null"]},"sectors":{"type":"array","items":{"type":"string"}},"sortOrder":{"type":"integer"}}},"Conversion":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"amountPaidCents":{"type":"integer"},"currency":{"type":"string"},"paymentMethod":{"type":"string","enum":["card","pix","boleto","unknown"]},"type":{"type":"string","enum":["first","recurring"]},"gateway":{"type":"string"},"status":{"type":"string","enum":["pending","approved","refunded"],"description":"status EXIBIDO da venda (pendente 15d → aprovada)"},"commissionCents":{"type":["integer","null"]},"commissionStatus":{"type":["string","null"],"enum":["pending","paid","clawed_back",null]}}},"Click":{"type":"object","properties":{"id":{"type":"string"},"occurredAt":{"type":"string","format":"date-time"},"subId":{"type":["string","null"],"description":"clickref / ?sub"},"country":{"type":["string","null"]},"referrer":{"type":["string","null"]},"programName":{"type":"string"},"advertiserName":{"type":"string"}}},"Screenshot":{"type":"object","properties":{"id":{"type":"string"},"advertiserId":{"type":"string"},"url":{"type":"string"},"sortOrder":{"type":"integer"}}},"GatewayConnection":{"type":"object","properties":{"gateway":{"type":"string","enum":["stripe","mercadopago","asaas","abacatepay"]},"connectionType":{"type":"string","enum":["oauth","api_key"]},"status":{"type":"string","enum":["active","paused"]},"gatewayAccountId":{"type":["string","null"]},"lastEventAt":{"type":["integer","null"]},"webhookToken":{"type":["string","null"],"description":"p/ exibir a URL do webhook (API-key)"}}},"SetupStep":{"type":"object","properties":{"id":{"type":"string","enum":["contract","program","publish","gateway","webhook","tracking"]},"label":{"type":"string"},"done":{"type":"boolean"},"partial":{"type":"boolean"},"hint":{"type":"string"}}},"OwedItem":{"type":"object","properties":{"affiliateUserId":{"type":"string"},"owedCents":{"type":"integer","description":"líquido de clawbacks"},"payableNowCents":{"type":"integer","description":"parcela já fora do refund-hold"}}},"AffiliateStats":{"type":"object","properties":{"clicks":{"type":"integer"},"conversions":{"type":"integer"},"releasedCents":{"type":"integer"},"heldCents":{"type":"integer"},"paidCents":{"type":"integer"}}}}},"security":[{"cookieSession":[]}],"paths":{"/api/public/catalog":{"get":{"tags":["Catálogo"],"summary":"Lista programas públicos (cards usam a foto do SaaS)","security":[],"responses":{"200":{"description":"Programas públicos + ativos","content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"type":"array","items":{"$ref":"#/components/schemas/Program"}}}}}}}}}},"/api/public/catalog/{slug}":{"get":{"tags":["Catálogo"],"summary":"Anunciante + seus programas públicos + screenshots","security":[],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Anunciante, programas e screenshots","content":{"application/json":{"schema":{"type":"object","properties":{"advertiser":{"$ref":"#/components/schemas/Advertiser"},"programs":{"type":"array","items":{"$ref":"#/components/schemas/Program"}},"screenshots":{"type":"array","items":{"type":"string"}}}}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me":{"get":{"tags":["Conta"],"summary":"Sessão atual (usuário + org ativa)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string"},"email":{"type":"string"},"orgId":{"type":"string"},"orgRole":{"type":"string"},"isPlatformAdmin":{"type":"boolean"}}}}}},"401":{"description":"Não autenticado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/avatar":{"post":{"tags":["Conta"],"summary":"Foto do usuário (avatar) — upload da imagem crua","description":"Imagem CRUA no body (≤512 KB, PNG/JPEG/WebP/SVG). Grava no R2 (`avatars/`) e devolve a URL; o front aplica via Better Auth `updateUser({ image })`.","requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","example":"/media/avatars/u/abc.png"}}}}}},"400":{"description":"Arquivo inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/contracts/status":{"get":{"tags":["Conta"],"summary":"Versões dos contratos + se já foram aceitos","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"versions":{"type":"object"},"advertiserAccepted":{"type":"boolean"},"affiliateAccepted":{"type":"boolean"}}}}}}}}},"/api/v1/contracts/accept":{"post":{"tags":["Conta"],"summary":"Aceitar contrato de plataforma (anunciante exige owner/admin)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["platform_advertiser","platform_affiliate"]}}}}}},"responses":{"200":{"description":"Aceito","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"version":{"type":"string"}}}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/email-preferences":{"get":{"tags":["Conta"],"summary":"Preferência de e-mails de notificação","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"boolean"}}}}}}}},"post":{"tags":["Conta"],"summary":"Atualiza preferência de e-mails","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["notifications"],"properties":{"notifications":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"boolean"}}}}}}}}},"/api/v1/link-preview":{"get":{"tags":["Conta"],"summary":"Metadados (OG) de uma URL — auto-preenche canais (com guarda anti-SSRF)","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"preview":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"image":{"type":"string"},"siteName":{"type":"string"},"favicon":{"type":"string"}}}}}}}},"400":{"description":"URL inválida / não permitida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/affiliations":{"get":{"tags":["Afiliado"],"summary":"Minhas afiliações (com link pronto e postbackUrl)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"affiliations":{"type":"array","items":{"$ref":"#/components/schemas/Affiliation"}}}}}}}}},"post":{"tags":["Afiliado"],"summary":"Aderir a um programa (gera link + cupom)","description":"Exige `accept:true` no 1º ingresso (aceite do contrato de afiliado + termos do programa).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["programId"],"properties":{"programId":{"type":"string"},"accept":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Já afiliado"},"201":{"description":"Afiliado","content":{"application/json":{"schema":{"type":"object","properties":{"affiliation":{"$ref":"#/components/schemas/Affiliation"},"link":{"type":"string"}}}}}},"400":{"description":"terms_required (precisa aceitar) — devolve programId + termsVersion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Programa indisponível","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/affiliations/{id}/postback":{"post":{"tags":["Afiliado"],"summary":"Configura o postback S2S da afiliação (URL com macros)","description":"Macros suportadas: `{clickref}` `{clickref2..6}` `{subid}` `{commission}` `{commission_cents}` `{sale_amount}` `{currency}` `{order_id}` `{transaction_id}` `{status}` (first/recurring/reversed) `{program}` `{program_id}` `{advertiser}` `{link_code}` `{payment_method}` `{timestamp}`. Enviar `null`/vazio remove o postback.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"postbackUrl":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"postbackUrl":{"type":["string","null"]}}}}}},"400":{"description":"URL inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Afiliação não encontrada","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/affiliate-profile":{"get":{"tags":["Afiliado"],"summary":"Meu perfil de afiliado (padrão AWIN) + canais","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"profile":{"oneOf":[{"$ref":"#/components/schemas/AffiliateProfile"},{"type":"null"}]},"channels":{"type":"array","items":{"$ref":"#/components/schemas/AffiliateChannel"}}}}}}}}},"post":{"tags":["Afiliado"],"summary":"Salva o perfil de afiliado (contato, empresa, tipos promocionais, documentos)","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AffiliateProfile"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Body inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/affiliate-channels":{"post":{"tags":["Afiliado"],"summary":"Adiciona um canal (onde divulga) — até 50","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"description":{"type":"string"},"sectors":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"$ref":"#/components/schemas/AffiliateChannel"}}}}}},"400":{"description":"too_many_channels / inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/affiliate-channels/{id}":{"delete":{"tags":["Afiliado"],"summary":"Remove um canal","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/api/v1/me/affiliate/overview":{"get":{"tags":["Afiliado"],"summary":"Resumo do afiliado (cliques, conversões, comissões)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"type":"integer"},"clicks":{"type":"integer"},"conversions":{"type":"integer"},"pendingCents":{"type":"integer"},"releasedCents":{"type":"integer"},"paidCents":{"type":"integer"}}}}}}}}},"/api/v1/me/affiliate/clicks":{"get":{"tags":["Afiliado"],"summary":"Meus cliques (recentes, ≤200)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"clicks":{"type":"array","items":{"$ref":"#/components/schemas/Click"}}}}}}}}}},"/api/v1/me/affiliate/conversions":{"get":{"tags":["Afiliado"],"summary":"Minhas vendas atribuídas (com comissão e status)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"conversions":{"type":"array","items":{"$ref":"#/components/schemas/Conversion"}}}}}}}}}},"/api/v1/advertiser":{"get":{"tags":["Anunciante"],"summary":"Anunciante da org ativa (ou null)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"advertiser":{"oneOf":[{"$ref":"#/components/schemas/Advertiser"},{"type":"null"}]}}}}}}}},"post":{"tags":["Anunciante"],"summary":"Cria/atualiza o anunciante (owner/admin)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2},"website":{"type":"string","format":"uri"},"logoUrl":{"type":"string","format":"uri"},"category":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"advertiser":{"$ref":"#/components/schemas/Advertiser"}}}}}},"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"advertiser":{"$ref":"#/components/schemas/Advertiser"}}}}}},"400":{"description":"Body inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/advertiser/logo":{"post":{"tags":["Anunciante"],"summary":"Upload do logo do anunciante (owner/admin)","requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"logoUrl":{"type":"string"}}}}}},"400":{"description":"Arquivo inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/advertiser/sdk-keys":{"post":{"tags":["Anunciante"],"summary":"(Re)gera as chaves do SDK (owner/admin). secretKey exibida 1×.","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"publicKey":{"type":"string"},"secretKey":{"type":"string"},"note":{"type":"string"}}}}}},"400":{"description":"Sem anunciante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/advertiser/screenshots":{"get":{"tags":["Anunciante"],"summary":"Screenshots do SaaS (galeria, máx 8)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"screenshots":{"type":"array","items":{"$ref":"#/components/schemas/Screenshot"}}}}}}}}},"post":{"tags":["Anunciante"],"summary":"Adiciona screenshot (owner/admin) — imagem crua","requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"screenshot":{"$ref":"#/components/schemas/Screenshot"}}}}}},"400":{"description":"too_many_screenshots / inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/advertiser/screenshots/{sid}":{"delete":{"tags":["Anunciante"],"summary":"Remove screenshot (owner/admin)","parameters":[{"name":"sid","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/my/saas":{"get":{"tags":["Anunciante"],"summary":"Lista meus SaaS (1 SaaS = 1 org) + qual está ativo","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"activeOrgId":{"type":"string"},"saas":{"type":"array","items":{"$ref":"#/components/schemas/SaasItem"}}}}}}}}},"post":{"tags":["Anunciante"],"summary":"Cria um novo SaaS (org + anunciante) e deixa ativo","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":2},"website":{"type":"string","format":"uri"},"category":{"type":"string"},"description":{"type":"string"}}}}}},"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"orgId":{"type":"string"},"advertiser":{"$ref":"#/components/schemas/Advertiser"}}}}}},"400":{"description":"saas_limit_reached / inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/my/saas/switch":{"post":{"tags":["Anunciante"],"summary":"Troca o SaaS ativo (grava na sessão)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orgId"],"properties":{"orgId":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"activeOrgId":{"type":"string"}}}}}},"403":{"description":"Não participa deste SaaS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/my/saas/{orgId}/archive":{"post":{"tags":["Anunciante"],"summary":"Arquiva/reativa um SaaS (owner-only)","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"}}}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/my/saas/{orgId}":{"delete":{"tags":["Anunciante"],"summary":"Exclui um SaaS PERMANENTEMENTE (owner-only; não o último)","parameters":[{"name":"orgId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"cannot_delete_last_saas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Sem permissão","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/programs":{"get":{"tags":["Anunciante"],"summary":"Lista meus programas (com pendingChange)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"type":"array","items":{"$ref":"#/components/schemas/Program"}}}}}}}}},"post":{"tags":["Anunciante"],"summary":"Cria programa (owner/admin)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","commissionType"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"terms":{"type":"string"},"commissionType":{"type":"string","enum":["percent","fixed"]},"commissionPercent":{"type":"number","minimum":0,"maximum":100,"description":"obrigatório se percent"},"commissionFixedCents":{"type":"integer","minimum":0,"description":"obrigatório se fixed"},"recurrence":{"type":"string","enum":["first_only","first_n","lifetime"],"default":"lifetime"},"recurrenceN":{"type":"integer","minimum":1},"cookieWindowDays":{"type":"integer","enum":[7,14,30],"default":30},"attributionModel":{"type":"string","enum":["last_click","first_click"],"default":"last_click"},"newCustomersOnly":{"type":"boolean","default":true},"autoApproveAffiliates":{"type":"boolean","default":false},"couponEnabled":{"type":"boolean","default":false},"allowedPromoTypes":{"type":"array","items":{"type":"string"}},"isPublic":{"type":"boolean","default":false}}}}}},"responses":{"201":{"description":"Criado","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"$ref":"#/components/schemas/Program"}}}}}},"400":{"description":"Body inválido / sem anunciante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/programs/{id}":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["Anunciante"],"summary":"Detalhe de um programa meu","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"$ref":"#/components/schemas/Program"}}}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Anunciante"],"summary":"Atualiza programa (owner/admin) — status, isPublic, comissão (com aviso prévio)","description":"Campos opcionais + `status: draft|active|paused`. Ativar exige setup completo (contrato + gateway) — senão `setup_incomplete` com `missing`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["draft","active","paused"]},"isPublic":{"type":"boolean"},"commissionPercent":{"type":"number"},"commissionFixedCents":{"type":"integer"},"recurrence":{"type":"string"},"terms":{"type":"string"}}}}}},"responses":{"200":{"description":"Atualizado","content":{"application/json":{"schema":{"type":"object","properties":{"program":{"$ref":"#/components/schemas/Program"},"scheduledChange":{"type":["object","null"]}}}}}},"400":{"description":"setup_incomplete / commission_value_required / inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/programs/{id}/affiliations":{"get":{"tags":["Anunciante"],"summary":"Afiliados de um programa meu (com perfil + canais)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"affiliations":{"type":"array","items":{"type":"object"}}}}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/affiliations/{id}/{action}":{"post":{"tags":["Anunciante"],"summary":"Aprovar/rejeitar afiliação (owner/admin do programa)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"action","in":"path","required":true,"schema":{"type":"string","enum":["approve","reject"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"affiliation":{"$ref":"#/components/schemas/Affiliation"}}}}}},"400":{"description":"invalid_action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Não é dono do programa","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/advertiser/overview":{"get":{"tags":["Anunciante"],"summary":"Contadores do SaaS (programas, afiliados, cliques, conversões, receita)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"programs":{"type":"integer"},"affiliates":{"type":"integer"},"clicks":{"type":"integer"},"conversions":{"type":"integer"},"revenueCents":{"type":"integer"}}}}}}}}},"/api/v1/advertiser/conversions":{"get":{"tags":["Anunciante"],"summary":"Vendas traqueadas (≤200) com status da venda","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"conversions":{"type":"array","items":{"$ref":"#/components/schemas/Conversion"}}}}}}}}}},"/api/v1/advertiser/customers":{"get":{"tags":["Anunciante"],"summary":"Clientes indicados (agrupados por cliente do gateway)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"customers":{"type":"array","items":{"type":"object"}}}}}}}}}},"/api/v1/advertiser/clicks":{"get":{"tags":["Anunciante"],"summary":"Cliques que vieram pelo SaaS (≤200)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"clicks":{"type":"array","items":{"type":"object"}}}}}}}}}},"/api/v1/advertiser/setup":{"get":{"tags":["Anunciante"],"summary":"Checklist de instalação (o que falta p/ rastrear vendas)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"steps":{"type":"array","items":{"$ref":"#/components/schemas/SetupStep"}},"complete":{"type":"boolean"},"counts":{"type":"object"}}}}}}}}},"/api/v1/gateways":{"get":{"tags":["Anunciante"],"summary":"Conexões de gateway do anunciante (sem segredos)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"gateways":{"type":"array","items":{"$ref":"#/components/schemas/GatewayConnection"}}}}}}}}}},"/api/v1/gateways/{gateway}/connect-url":{"get":{"tags":["Anunciante"],"summary":"URL de autorização OAuth (Stripe/Mercado Pago) — owner/admin","parameters":[{"name":"gateway","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}},"400":{"description":"Sem anunciante / falha","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/gateways/connect-apikey":{"post":{"tags":["Anunciante"],"summary":"Conecta gateway por API-key (Asaas/AbacatePay) — devolve webhook URL + secret","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["gateway","apiKey"],"properties":{"gateway":{"type":"string","enum":["asaas","abacatepay","pagarme"]},"apiKey":{"type":"string"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"gateway":{"type":"string"},"webhookUrl":{"type":"string"},"webhookSecret":{"type":"string"},"note":{"type":"string"}}}}}}}}},"/api/v1/gateways/{gateway}":{"delete":{"tags":["Anunciante"],"summary":"Desconecta gateway (pausa programas se for o último ativo)","parameters":[{"name":"gateway","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"programsPaused":{"type":"integer"}}}}}}}}},"/api/v1/payouts/owed":{"get":{"tags":["Anunciante"],"summary":"Quanto devo a cada afiliado (líquido + parcela liberada)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"owed":{"type":"array","items":{"$ref":"#/components/schemas/OwedItem"}}}}}}}}}},"/api/v1/payouts/mark-paid":{"post":{"tags":["Anunciante"],"summary":"Registrar repasse pago — baixa comissões liberadas","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["affiliateUserId"],"properties":{"affiliateUserId":{"type":"string"},"periodLabel":{"type":"string","example":"2026-06"},"note":{"type":"string"}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"payout":{"type":"object"},"settledCount":{"type":"integer"}}}}}},"400":{"description":"Body inválido / sem anunciante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/payouts/history":{"get":{"tags":["Anunciante"],"summary":"Histórico de repasses do anunciante (com flag de comprovante)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"type":"object"}}}}}}}}}},"/api/v1/payouts/{id}/proof":{"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["Anunciante"],"summary":"Anexa o comprovante do repasse (imagem ou PDF, ≤5MB) — owner/admin","requestBody":{"required":true,"content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/jpeg":{"schema":{"type":"string","format":"binary"}},"image/webp":{"schema":{"type":"string","format":"binary"}},"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Arquivo inválido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Repasse não encontrado","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"tags":["Conta"],"summary":"Serve o comprovante (autenticado: só o anunciante que pagou ou o afiliado que recebeu)","responses":{"200":{"description":"Arquivo (imagem/PDF)"},"403":{"description":"Sem acesso","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Sem comprovante","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/me/affiliate/payouts":{"get":{"tags":["Afiliado"],"summary":"Repasses recebidos pelo afiliado (com flag de comprovante)","responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"payouts":{"type":"array","items":{"type":"object"}}}}}}}}}},"/sdk/v1/affiliate":{"post":{"tags":["SDK"],"summary":"Find-or-create do afiliado (cliente do SaaS) → link + cupom","security":[{"bearerSk":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"name":{"type":"string"},"programId":{"type":"string"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"affiliate":{"type":"object","properties":{"link":{"type":"string"},"couponCode":{"type":["string","null"]},"status":{"type":"string"}}},"program":{"type":"object"}}}}}},"400":{"description":"Body inválido / sem programa ativo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"sk_ inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sdk/v1/affiliate/stats":{"get":{"tags":["SDK"],"summary":"Stats do afiliado (por email) neste anunciante","security":[{"bearerSk":[]}],"parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"stats":{"$ref":"#/components/schemas/AffiliateStats"}}}}}},"400":{"description":"email ausente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"sk_ inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/sdk/v1/afs.js":{"get":{"tags":["SDK"],"summary":"Client helper (público): persiste ?ref + renderReferralWidget","security":[],"responses":{"200":{"description":"JavaScript","content":{"application/javascript":{}}}}}},"/go/{code}":{"get":{"tags":["Tracking"],"summary":"Redirect de link de afiliado (grava clique + cookie + ?ref) → site do SaaS","security":[],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"linkCode da afiliação"},{"name":"sub","in":"query","required":false,"schema":{"type":"string"},"description":"sub-tag (= clickref)"},{"name":"clickref","in":"query","required":false,"schema":{"type":"string"}},{"name":"ued","in":"query","required":false,"schema":{"type":"string","format":"uri"},"description":"deeplink: destino (só honrado se for do domínio do anunciante)"}],"responses":{"302":{"description":"Redirect para o site do anunciante com ?ref=<click_id>"}}}},"/cread":{"get":{"tags":["Tracking"],"summary":"Deeplink longo estilo AWIN (forma apex)","description":"Equivalente a `go.../<code>?ued=...`. `ued` só é honrado se for o domínio do anunciante (anti open-redirect).","security":[],"parameters":[{"name":"code","in":"query","required":true,"schema":{"type":"string"},"description":"linkCode da afiliação"},{"name":"ued","in":"query","required":false,"schema":{"type":"string","format":"uri"},"description":"URL de destino (deeplink)"},{"name":"clickref","in":"query","required":false,"schema":{"type":"string"},"description":"sub1"},{"name":"clickref2","in":"query","required":false,"schema":{"type":"string"}},{"name":"clickref3","in":"query","required":false,"schema":{"type":"string"}},{"name":"clickref4","in":"query","required":false,"schema":{"type":"string"}},{"name":"clickref5","in":"query","required":false,"schema":{"type":"string"}},{"name":"clickref6","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect (deeplink ou home do anunciante) com ?ref"}}}},"/webhooks/{gateway}":{"post":{"tags":["Webhooks"],"summary":"Webhook OAuth (Stripe/Mercado Pago) — multi-tenant por evento","security":[],"parameters":[{"name":"gateway","in":"path","required":true,"schema":{"type":"string","enum":["stripe","mercadopago"]}}],"description":"Assinatura verificada (Web Crypto). Idempotente por (gateway, id). Não chamar manualmente.","responses":{"200":{"description":"Aceito (idempotente)"},"400":{"description":"Assinatura inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Secret de plataforma ausente","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{gateway}/{token}":{"post":{"tags":["Webhooks"],"summary":"Webhook API-key (Asaas/AbacatePay) — token = merchant","security":[],"parameters":[{"name":"gateway","in":"path","required":true,"schema":{"type":"string","enum":["asaas","abacatepay","pagarme"]}},{"name":"token","in":"path","required":true,"schema":{"type":"string"},"description":"webhookToken único por merchant"}],"responses":{"200":{"description":"Aceito (idempotente)"},"400":{"description":"Assinatura inválida","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Merchant desconhecido","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/auth/{action}":{"parameters":[{"name":"action","in":"path","required":true,"schema":{"type":"string"},"description":"ex.: sign-in/magic-link, update-user, organization/invite-member, organization/list-members, organization/accept-invitation"}],"get":{"tags":["Auth"],"summary":"Better Auth (GET) — sessão, callbacks OAuth, etc.","security":[],"responses":{"200":{"description":"Depende da ação"}}},"post":{"tags":["Auth"],"summary":"Better Auth (POST) — magic link, updateUser (nome/foto), organization (membros/equipe)","security":[],"description":"Plugins ativos: magicLink, organization, passkey, twoFactor, oneTap (Google). Gestão de equipe do SaaS: `organization/invite-member`, `organization/list-members`, `organization/remove-member`, `organization/update-member-role`, `organization/accept-invitation`.","responses":{"200":{"description":"Depende da ação"}}}}}}