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:
- Swagger UI (OpenAPI): https://fdplay-api.infraifd.com/api/v1/docs
- ReDoc: https://fdplay-api.infraifd.com/api/v1/redoc
- Fluxo para Frontend — Guia de implementação completo em Dart/Flutter
📚 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:
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:
- Login falha com
401→ Frontend detecta que é primeiro acesso (ou exibe opção "Esqueci minha senha") POST /auth/forgot-passwordcom email → Recebe código de 6 dígitos por emailPOST /auth/reset-passwordcom email + código + nova senha → Senha redefinida + flag limpa- 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) + tratarpassword_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/subscribeou/stripe/subscribecompromo_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.