Skip to content

FDPlay API — Plataforma de Streaming com Assinaturas

Versao da Documentacao: 1.1.0 | Atualizado em: 2026-03-29 (UTC-3)

Bem-vindo à documentação completa da FDPlay API, uma plataforma de streaming de vídeos com sistema de assinaturas recorrentes integrado ao Stripe e Asaas.


🚀 Início Rápido

Documentação Interativa

Acesse a documentação interativa da API para testar endpoints diretamente no navegador:

Documentação Interativa da API

Acesse os endpoints diretamente no navegador:


📚 Documentação da API

Guias Completos

Tópico Descrição
Visão Geral Introdução à API, tipos de usuários e fluxos principais
Autenticação Sistema JWT, login, refresh tokens e segurança
Clientes Cadastro (signup), perfil e gerenciamento de assinaturas
Signup — Modo A vs Modo B 🆕 Verificação de email imediata vs postergada (verify_email_now) — guia para frontend
Planos Listagem pública e administração de planos de assinatura
Vídeos CRUD, controle de acesso e thumbnails
Streaming HLS URLs assinadas Bunny CDN com Token Auth V2
Categorias & Tags Sistema de organização de conteúdo
Perfil Avatar e histórico de reprodução (Admin e Customer)
Webhooks Integração Stripe, Asaas e logs de auditoria
Stripe Integração completa Stripe Billing para frontend
Asaas Integração Asaas (cartão + PIX) para billing BR
Promo Codes Cupons promocionais e ingressos
Cupom com Filhos PromoCode com children_code_ids (agrupamento)
Eventos & Ingressos Events, Tickets e integração com PromoCode
Admin Dashboard Gestão de assinaturas, estatísticas e logs
Subscriptions Dashboard 🆕 Visão 360 de assinaturas (totals, gateway, payment method, alerts)
Subscriptions Insights 🆕 Análise interpretada com labels, severities e oportunidades
Customers Export 🆕 Exportar clientes segmentados por status (CSV/XLSX/JSON)
Dashboard Financeiro MRR, churn, inadimplentes e exportação multi-formato (XLSX/CSV/JSON)

⚙️ Configuração de Ambiente

A API suporta dois ambientes controlados pela variável FDPLAY_ENV:

Ambiente Valor Gateways Uso
Development development (padrão) Stripe Test + Asaas Sandbox Testes
Production production Stripe Live + Asaas Producao Cobranças reais

Como Usar

# Development (padrão - não precisa definir)
uvicorn application.main:app --reload

# Production (explícito)
FDPLAY_ENV=production uvicorn application.main:app --reload

Documentação Completa

Para detalhes sobre configuração de ambiente, deploy e CI/CD: - Configuração Local: docs/ENVIRONMENT_CONFIG.md - Deploy GitHub Actions: docs/DEPLOY_ENVIRONMENT.md - Handoff Técnico: docs/IMPLEMENTATION_HANDOFF_2026-01-19_FDPLAY_ENV.md


🏗️ Arquitetura

Clean Architecture

A API segue os princípios de Clean Architecture com separação em camadas:

📁 application/
├── 📁 domain/             # Camada de Domínio
│   ├── entities/         # Entidades de negócio
│   ├── repositories/     # Interfaces de repositórios
│   └── usecases/        # Casos de uso
├── 📁 adapters/        # Camada de Adaptadores
│   ├── controllers/      # Controladores
│   ├── routes/       # Rotas FastAPI
│   ├── presenters/   # Formatação de respostas
│   └── middleware/   # Middleware (auth, subscription)
└── 📁 infrastructure/    # Camada de Infraestrutura
    ├── db/           # MongoDB (Motor)
    ├── external/       # Stripe, Asaas, SMTP
    ├── storages/       # GridFS
    └── notifications/   # Email service

Stack Tecnológica

  • Framework: FastAPI 0.104+
  • Database: MongoDB (Motor - async driver)
  • Auth: JWT (OAuth2 Password Bearer)
  • Payments: Stripe Billing API + Asaas API
  • Storage: GridFS (MongoDB)
  • Email: SMTP + Resend API (fallback automatico)
  • Docs: OpenAPI 3.0 + MkDocs

🔐 Autenticação

Todos os endpoints protegidos exigem token JWT no header:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Obter Token

curl -X POST "https://fdplay-api.infraifd.com/api/v1/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=user@example.com&password=senha123"

Response:

{
  "access_token": "eyJhbGci...",
  "token_type": "bearer",
  "id_token": "507f1f77bcf86cd799439011",
  "expiration": "2026-01-19T04:30:00Z"
}

Ver Documentação de Autenticação completa.


👥 Tipos de Usuários (STI)

A API utiliza Single Table Inheritance (STI) — todos os usuários são armazenados na collection users, diferenciados pelo campo user_type.

user_type Endpoint Descrição
admin /api/v1/users Administradores da plataforma
customer /api/v1/customers Clientes/assinantes

Admin

  • Acesso completo a todos os recursos
  • Bypass de validação de assinatura
  • Endpoints exclusivos de administração

Customer

  • Acesso a vídeos mediante assinatura ativa
  • Gerenciamento de próprio perfil
  • Renovação e cancelamento de assinatura

🎯 Fluxos Principais

1. Signup de Customer

graph LR
    A[Frontend] -->|POST /customers/signup| B[API]
    B -->|Save MongoDB| D[(Database)]
    B -->|Send email| E[Customer]
    B -->|Return JWT| A

Ver Customer Signup detalhado.

2. Acesso a Vídeos

graph LR
    A[Customer] -->|GET /videos| B[Middleware]
    B -->|Check subscription| C{Active?}
    C -->|Yes| D[Return videos]
    C -->|No| E[403 Forbidden]

Ver Videos API completa.

O contrato de vídeo inclui is_show_in_slide_carousel, usado pelo frontend para decidir quais vídeos entram no slide carousel.

3. Webhooks (Stripe + Asaas)

graph LR
    A[Stripe] -->|POST /webhooks/stripe| B[API]
    A2[Asaas] -->|POST /webhooks/asaas| B
    B -->|Validate signature| C{Valid?}
    C -->|Yes| D[Process event]
    C -->|No| E[401 Unauthorized]
    D -->|Update DB| F[(Database)]
    D -->|Save log| F

Ver Webhooks detalhados.

4. Assinatura via Stripe

graph LR
    A[Flutter] -->|Stripe SDK| B[pm_xxx]
    B -->|POST /stripe/subscribe| C[API]
    C -->|Create sub| D[Stripe]
    D -->|sub_xxx| C
    C -->|Save| E[(MongoDB)]

Ver Integração Stripe completa.


📦 Base URL

Produção: https://fdplay-api.infraifd.com
Staging: https://staging-fdplay-api.infraifd.com
Local: http://localhost:8000

Versão da API: /api/v1


🛠️ Ferramentas de Desenvolvimento

Testar Endpoints

  • Swagger UI: {BASE_URL}/api/v1/docs — Interface interativa
  • ReDoc: {BASE_URL}/api/v1/redoc — Documentação limpa
  • Postman: Importe o schema OpenAPI de {BASE_URL}/api/v1/openapi.json

Monitoramento

  • Health Check: GET /api/v1/health
  • Webhook Logs: GET /api/v1/webhook-logs (admin)
  • Subscription Stats: GET /api/v1/subscriptions/stats (admin)

🎯 Fluxo para Frontend

Guia Completo de Implementação

Este guia apresenta o fluxo completo que o frontend deve seguir para integrar com a API.


1. Página de Pricing (Sem Autenticação)

Objetivo: Mostrar planos disponíveis para assinatura.

Endpoint: GET /api/v1/plans (público, sem autenticação)

// Buscar planos ativos
const response = await fetch('https://fdplay-api.infraifd.com/api/v1/plans');
const data = await response.json();

// Exibir cards de planos
data.docs.forEach(plan => {
  console.log(plan.name, plan.amount / 100, plan.features);
});

Ver documentação completa: Plans API


2. Signup (Cadastro + Assinatura)

Objetivo: Criar customer e assinatura em uma única requisição.

Endpoint: POST /api/v1/customers/signup

const signupData = {
  email: "customer@example.com",
  password: "senha123",
  full_name: "João Silva",
  cpf: "12345678900",
  phone: "+5511999999999",
  plan_id: "plan-basic",
  payment_method: "credit_card",
  payment_data: {
    card: {
      number: "4539620659922097",
      exp_month: "12",
      exp_year: "2030",
      security_code: "123",
      holder: { name: "JOAO SILVA" }
    }
  }
};

const response = await fetch('https://fdplay-api.infraifd.com/api/v1/customers/signup', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify([signupData])
});

const result = await response.json();
// result.auth.access_token -> Salvar no localStorage

Ver documentação completa: Customer Signup


3. Login

Objetivo: Autenticar usuário existente.

Endpoint: POST /api/v1/token

const formData = new URLSearchParams();
formData.append('username', 'customer@example.com');
formData.append('password', 'senha123');

const response = await fetch('https://fdplay-api.infraifd.com/api/v1/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: formData
});

const data = await response.json();

// ⚠️ Diferenciar erro de senha errada vs usuário legado
if (!response.ok) {
  const errorCode = data.error?.code;

  if (errorCode === 'PASSWORD_RESET_REQUIRED') {
    // Usuário legado com senha placeholder → redirecionar para forgot-password
    alert('Primeiro acesso? Redefina sua senha pelo email.');
    window.location.href = `/forgot-password?email=${encodeURIComponent(username)}`;
  } else {
    // Senha errada normal (INVALID_CREDENTIALS)
    alert('Email ou senha incorretos.');
  }
} else if (data.password_reset_required) {
  // Caso raro: legado que sabe a senha mas flag ainda ativa
  sessionStorage.setItem('temp_token', data.access_token);
  sessionStorage.setItem('temp_password', password);
  window.location.href = '/change-password';
} else {
  // Login normal — salvar token
  localStorage.setItem('access_token', data.access_token);
  localStorage.setItem('id_token', data.id_token);
  localStorage.setItem('token_expires_at', new Date(data.expiration).getTime().toString());
}

Ver documentação completa: Authentication


3.1. Troca de Senha Obrigatória (Usuários Legados)

Objetivo: Forçar troca de senha para usuários migrados do sistema antigo.

Endpoint: POST /api/v1/auth/change-password

Quando usar

Este fluxo é obrigatório quando o login retorna password_reset_required: true. O usuário não deve acessar outras funcionalidades até trocar a senha.

Usuários legados: login vai FALHAR

Usuários migrados do sistema SQL anterior têm senha placeholder — o login com a senha antiga retorna 401 INVALID_CREDENTIALS. Nesses casos, o frontend deve redirecionar para o fluxo de forgot-password (reset via código por email), não para change-password (que exige senha atual).

Fluxo recomendado para legados:

  1. Login falha com 401 → Frontend detecta que é primeiro acesso (ou exibe opção "Esqueci minha senha")
  2. POST /auth/forgot-password com email → Recebe código de 6 dígitos por email
  3. POST /auth/reset-password com email + código + nova senha → Senha redefinida + flag limpa
  4. Novo login funciona normalmente
const tempToken = sessionStorage.getItem('temp_token');
const currentPassword = sessionStorage.getItem('temp_password');

const response = await fetch('https://fdplay-api.infraifd.com/api/v1/auth/change-password', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${tempToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    current_password: currentPassword,
    new_password: novaSenhaDoUsuario
  })
});

if (response.ok) {
  // Limpar dados temporários
  sessionStorage.removeItem('temp_token');
  sessionStorage.removeItem('temp_password');

  // Agora sim, persistir token e liberar acesso
  localStorage.setItem('access_token', tempToken);
  window.location.href = '/dashboard';
}

Ver documentação completa: Fluxo de Reset Obrigatório


4. Acessar Vídeos (Com Assinatura Ativa)

Objetivo: Listar vídeos disponíveis.

Endpoint: GET /api/v1/videos

⚠️ IMPORTANTE: Requer token JWT + assinatura ativa (customers).

const token = localStorage.getItem('access_token');

const response = await fetch('https://fdplay-api.infraifd.com/api/v1/videos?query={"enable":true}', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

if (response.status === 403) {
  // Sem assinatura ativa -> Redirecionar para /plans
  window.location.href = '/plans';
}

const data = await response.json();
// data.docs -> Lista de vídeos

Ver documentação completa: Videos API


5. Filtrar por Categoria/Tags

Objetivo: Filtrar vídeos por categoria ou tags.

Endpoints: - GET /api/v1/categories - Listar categorias - GET /api/v1/tags - Listar tags - GET /api/v1/videos?query={...} - Filtrar vídeos

// Buscar vídeos de uma categoria
const categoryId = "507f1f77bcf86cd799439011";
const query = JSON.stringify({ enable: true, category_id: categoryId });

const response = await fetch(
  `https://fdplay-api.infraifd.com/api/v1/videos?query=${encodeURIComponent(query)}`,
  {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Content-Type': 'application/json'
    }
  }
);

Ver documentação completa: Categories & Tags


6. Gerenciar Assinatura

Objetivo: Visualizar, renovar ou cancelar assinatura.

Endpoints: - GET /api/v1/customers/me/subscription - Ver assinatura ativa - DELETE /api/v1/customers/me/subscription - Cancelar assinatura - PUT /api/v1/customers/me/subscription/renew - Trocar metodo de pagamento (cancela antiga + cria nova)

// Verificar assinatura atual
const response = await fetch('https://fdplay-api.infraifd.com/api/v1/customers/me/subscription', {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
});

const data = await response.json();
// data.subscription.status -> 'active', 'suspended', 'cancelled'

Ver documentação completa: Customers API


📊 Diagrama do Fluxo Completo

graph TD
    A[Usuário acessa site] --> B{Autenticado?}
    B -->|Não| C[Ver Pricing /plans]
    B -->|Sim| PR{password_reset_required?}
    PR -->|Sim - sabe senha| PR1[POST /auth/change-password]
    PR -->|Sim - legado| PR2[POST /auth/forgot-password → reset-password]
    PR1 --> G
    PR2 --> G
    PR -->|Não| G[Verificar Assinatura]

    C --> D[Escolher Plano]
    D --> E[Signup + Pagamento]
    E --> F[Receber JWT Token]
    F --> G

    G --> H{Assinatura Ativa?}
    H -->|Sim| I[Acessar Vídeos]
    H -->|Não| C

    I --> J[Filtrar por Categoria/Tags]
    J --> K[Assistir Vídeo]

    K --> L{Quer Cancelar?}
    L -->|Sim| M[DELETE /customers/me/subscription]
    L -->|Não| N[Continuar Usando]

    M --> O[Assinatura Cancelada]
    O --> C

🔄 Webhooks (Backend Process)

Quando eventos ocorrem nos gateways de pagamento (pagamento aprovado, falha, etc.), o backend recebe webhooks automaticamente.

O frontend NÃO precisa se preocupar com isso. O backend atualiza automaticamente: - Status da assinatura - Próxima data de cobrança - Falhas de pagamento

Ver documentação completa: Webhooks


Checklist de Implementacao Frontend

  • [ ] Pagina de pricing (GET /api/v1/plans)
  • [ ] Signup com verificacao de email (POST /api/v1/customers/signup)
  • [ ] Login (POST /api/v1/token) + tratar password_reset_required
  • [ ] Troca de senha obrigatoria (POST /api/v1/auth/change-password)
  • [ ] Salvar JWT token + auto-refresh antes de expirar
  • [ ] Listagem de videos (GET /api/v1/videos) + filtros categoria/tags
  • [ ] Streaming HLS (GET /api/v1/videos/{id}/stream-url)
  • [ ] Upload/remocao de avatar (POST/DELETE /api/v1/me/avatar)
  • [ ] Historico de reproducao (PUT/GET/DELETE /api/v1/me/watch-history)
  • [ ] Alteracao de dados pessoais (PUT /api/v1/customers/me)
  • [ ] Alteracao de email com re-verificacao (POST /customers/me/change-email + confirm-email)
  • [ ] Gerenciamento de assinatura (ver/cancelar/renovar)
  • [ ] Validar promo code (GET /customers/validate-promo-code) — sempre enviar Bearer token
  • [ ] Resgatar promo code (PUT /customers/me/redeem-promo-code)
  • [ ] Listar ingressos (GET /api/v1/me/tickets) + consumir (PUT /tickets/{id}/consume)
  • [ ] Subscribe com promo code (POST /asaas/subscribe ou /stripe/subscribe com promo_code)
  • [ ] Tratar erro 403 (sem assinatura) → redirecionar para /plans

📞 Suporte

  • GitHub: fdplay-api/issues
  • Email: suporte@fdplay.com
  • Documentação: Esta página que você está lendo

📄 Licença

© 2026 FDPlay. Todos os direitos reservados.