Skip to content

API de Dashboard Financeiro

Endpoints para o painel administrativo financeiro. Fornece KPIs, series temporais para graficos, lista de inadimplentes, analise de churn e exportacao Excel.

Prefixo: /api/v1/admin/finance Autenticacao: Bearer token (JWT) + user_type='admin'


Endpoints

Metodo Endpoint Descricao
GET /admin/finance/overview KPIs consolidados (MRR, ARR, inadimplentes, churn)
GET /admin/finance/revenue Serie temporal de receita (diario/mensal)
GET /admin/finance/overdue Lista de clientes inadimplentes
GET /admin/finance/churn Analise de churn mensal
GET /admin/finance/export Exportar dados financeiros em Excel (.xlsx)

1. GET /admin/finance/overview

KPIs financeiros consolidados. Dados prontos para cards de dashboard.

GET /api/v1/admin/finance/overview
Authorization: Bearer <admin_token>

Response (200 OK)

{
  "mrr": 384070,
  "mrr_stripe": 246760,
  "mrr_asaas": 137310,
  "arr": 4608840,
  "total_customers": 13797,
  "active_subscriptions": 193,
  "overdue_count": 34,
  "churn_rate_30d": 4.0,
  "total_refunded": 0,
  "total_chargebacks": 0,
  "net_revenue_30d": 384070,
  "average_ticket": 1990,
  "payment_success_rate": 19.7,
  "by_payment_method": {
    "credit_card": { "count": 112, "mrr": 222880 },
    "pix": { "count": 81, "mrr": 161190 }
  },
  "by_plan": {
    "plan-basic": { "count": 193, "mrr": 384070, "name": "Plano Mensal Basico" }
  }
}

Campos

Campo Tipo Descricao
mrr int Monthly Recurring Revenue (centavos)
mrr_stripe int MRR somente Stripe (centavos)
mrr_asaas int MRR somente Asaas (centavos)
arr int Annual Recurring Revenue = MRR * 12 (centavos)
total_customers int Total de customers cadastrados
active_subscriptions int Assinaturas com status active
overdue_count int Assinaturas com payment_failures > 0 ou suspended
churn_rate_30d float Taxa de churn ultimos 30 dias (%)
total_refunded int Total reembolsado (centavos)
total_chargebacks int Total de chargebacks
net_revenue_30d int Receita liquida 30d = MRR - refunds (centavos)
average_ticket int Ticket medio = MRR / ativos (centavos)
payment_success_rate float Taxa de sucesso de pagamento (%)
by_payment_method dict Breakdown por metodo (credit_card, pix, boleto)
by_plan dict Breakdown por plano (count, mrr, name)

Uso no frontend (cards)

// Converter centavos para reais
String formatBRL(int cents) => 'R\$ ${(cents / 100).toStringAsFixed(2)}';

// Cards sugeridos:
// - MRR: formatBRL(overview.mrr)
// - ARR: formatBRL(overview.arr)
// - Assinaturas ativas: overview.active_subscriptions
// - Inadimplentes: overview.overdue_count (vermelho se > 0)
// - Churn 30d: "${overview.churn_rate_30d}%"
// - Ticket medio: formatBRL(overview.average_ticket)

2. GET /admin/finance/revenue

Serie temporal de receita. Dados formatados para graficos de linha/barra.

GET /api/v1/admin/finance/revenue?period=monthly&start=2026-01&end=2026-03
Authorization: Bearer <admin_token>

Query Parameters

Parametro Tipo Default Descricao
period string monthly monthly ou daily
start string 6 meses atras Inicio (YYYY-MM mensal, YYYY-MM-DD diario)
end string hoje Fim (mesmo formato)

Response (200 OK)

{
  "period": "monthly",
  "data": [
    {
      "date": "2026-01",
      "gross": 79600,
      "refunds": 0,
      "chargebacks": 0,
      "net": 79600,
      "new_subscriptions": 7,
      "cancellations": 0,
      "stripe": 45000,
      "asaas": 34600
    },
    {
      "date": "2026-02",
      "gross": 246760,
      "refunds": 0,
      "chargebacks": 0,
      "net": 246760,
      "new_subscriptions": 85,
      "cancellations": 3,
      "stripe": 150000,
      "asaas": 96760
    },
    {
      "date": "2026-03",
      "gross": 218900,
      "refunds": 0,
      "chargebacks": 0,
      "net": 218900,
      "new_subscriptions": 0,
      "cancellations": 0,
      "stripe": 130000,
      "asaas": 88900
    }
  ],
  "totals": {
    "gross": 545260,
    "refunds": 0,
    "chargebacks": 0,
    "net": 545260,
    "new_subscriptions": 92,
    "cancellations": 3
  }
}

Uso no frontend (graficos)

// Grafico de linha: Receita mensal
// X: data[].date
// Y1: data[].gross (receita bruta)
// Y2: data[].net (receita liquida)

// Grafico de barras empilhadas: Stripe vs Asaas
// X: data[].date
// Stack 1: data[].stripe
// Stack 2: data[].asaas

// Grafico de linha: Novas vs Cancelamentos
// X: data[].date
// Y1: data[].new_subscriptions (verde)
// Y2: data[].cancellations (vermelho)

3. GET /admin/finance/overdue

Lista paginada de clientes com pagamentos em atraso.

GET /api/v1/admin/finance/overdue?page=0&limit=20
Authorization: Bearer <admin_token>

Query Parameters

Parametro Tipo Default Descricao
page int 0 Pagina (zero-indexed)
limit int 20 Itens por pagina (max 100)

Response (200 OK)

{
  "total_overdue": 34,
  "total_amount_at_risk": 39800,
  "customers": [
    {
      "customer_id": "69b1a2b3c4d5e6f7a8b9c0d1",
      "username": "joao_silva",
      "email": "joao@example.com",
      "full_name": "Joao da Silva",
      "plan_id": "plan-basic",
      "plan_name": "Plano Mensal Basico",
      "gateway": "asaas",
      "payment_method": "credit_card",
      "payment_failures": 3,
      "last_payment_at": "2026-02-15T00:00:00+00:00",
      "next_billing_date": "2026-03-15T00:00:00+00:00",
      "days_overdue": 12,
      "subscription_status": "suspended",
      "amount": 1990
    }
  ]
}

Campos do customer inadimplente

Campo Tipo Descricao
customer_id string ID do customer (MongoDB ObjectId)
username string Username
email string Email
full_name string Nome completo
plan_id string Slug do plano
plan_name string Nome do plano
gateway string Gateway (stripe/asaas)
payment_method string Metodo (credit_card/pix/boleto)
payment_failures int Falhas consecutivas de pagamento
last_payment_at string Ultimo pagamento (ISO 8601)
next_billing_date string Proxima cobranca (ISO 8601)
days_overdue int Dias em atraso
subscription_status string Status da assinatura
amount int Valor do plano (centavos)

Uso no frontend (tabela)

// Tabela com colunas:
// | Cliente | Email | Plano | Gateway | Falhas | Dias Atraso | Valor | Status |
//
// Ordenar por payment_failures DESC (mais criticos primeiro)
// Badge vermelho se days_overdue > 7
// Badge amarelo se payment_failures >= 3

4. GET /admin/finance/churn

Analise de churn mensal com breakdown por motivo.

GET /api/v1/admin/finance/churn?months=6
Authorization: Bearer <admin_token>

Query Parameters

Parametro Tipo Default Descricao
months int 6 Meses de historico (1-24)

Response (200 OK)

{
  "monthly": [
    {
      "month": "2026-01",
      "active_start": 33,
      "new": 7,
      "cancelled": 0,
      "active_end": 40,
      "churn_rate": 0.0
    },
    {
      "month": "2026-02",
      "active_start": 39,
      "new": 85,
      "cancelled": 3,
      "active_end": 121,
      "churn_rate": 7.7
    },
    {
      "month": "2026-03",
      "active_start": 110,
      "new": 122,
      "cancelled": 8,
      "active_end": 224,
      "churn_rate": 7.3
    }
  ],
  "by_reason": {
    "payment_failure": 0,
    "customer_cancelled": 11,
    "admin_cancelled": 0,
    "chargeback": 0,
    "expired": 2
  }
}

Uso no frontend (graficos)

// Grafico de area: Evolucao de assinantes
// X: monthly[].month
// Y: monthly[].active_end

// Grafico de barras: New vs Cancelled por mes
// X: monthly[].month
// Barra verde: monthly[].new
// Barra vermelha: monthly[].cancelled

// Grafico de pizza: Motivos de cancelamento
// Fatias: by_reason (payment_failure, customer_cancelled, admin_cancelled, chargeback, expired)

5. GET /admin/finance/export

Exporta dados financeiros consolidados em xlsx (default), csv (zip multi-aba) ou json. Padrão visual definido em ADR-059 (título + metadados + freeze + autofilter + zebra + auto-width + formatos numéricos nativos).

Duas formas de autenticacao (para compatibilidade com download no browser):

# Opcao 1: Header (padrao, via fetch/http)
GET /api/v1/admin/finance/export?start=2026-01-01&end=2026-03-27
Authorization: Bearer <admin_token>

# Opcao 2: Query param (para window.open / <a href> no browser)
GET /api/v1/admin/finance/export?token=<jwt>&start=2026-01-01&end=2026-03-27&format=xlsx

Query Parameters

Parametro Tipo Default Descricao
format string xlsx xlsx (multi-aba), csv (zip), json (aninhado)
start string 90 dias atras Data inicio (YYYY-MM-DD)
end string hoje Data fim (YYYY-MM-DD)
token string - JWT token (alternativa ao header, para download no browser)

Response

format Content-Type Filename
xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet fdplay_financeiro_<start>_<end>.xlsx
csv application/zip (multi-aba) fdplay_financeiro_<start>_<end>.zip
json application/json; charset=utf-8 fdplay_financeiro_<start>_<end>.json

Abas do Excel

Aba Conteudo Colunas
Resumo KPIs do periodo Metrica, Valor
Assinaturas Todas as subscriptions no periodo ID, Cliente, Email, Plano, Gateway, Metodo, Status, Valor, Inicio, Expiracao, Ultimo Pagamento, Falhas, Reembolsado
Inadimplentes Customers com payment_failures > 0 Cliente, Email, Plano, Gateway, Metodo, Falhas, Ultimo Pagamento, Prox. Cobranca, Dias Atraso, Valor, Status
Cancelamentos Subscriptions canceladas no periodo Cliente, Email, Plano, Gateway, Data Cancelamento, Valor
Reembolsos Eventos de refund/chargeback no periodo Evento, Tipo, Subscription, Admin, Motivo, Data

Uso no frontend

// Botao "Exportar Excel" que faz download direto
Future<void> exportFinance(String start, String end) async {
  // Token via query param — funciona com window.open no browser
  final url =
    '$baseUrl/api/v1/admin/finance/export?token=$token&start=$start&end=$end';

  // Web: window.open dispara download nativo do browser
  if (kIsWeb) {
    html.window.open(url, '_blank');
    return;
  }

  // Mobile: salvar via dio + path_provider
  final response = await dio.get(
    url,
    options: Options(responseType: ResponseType.bytes),
  );

  final dir = await getApplicationDocumentsDirectory();
  final file = File('${dir.path}/fdplay_financeiro.xlsx');
  await file.writeAsBytes(response.data);

  // Abrir com app nativo
  OpenFile.open(file.path);
}

Integracao Flutter/Dart

Service completo

import 'dart:convert';
import 'package:http/http.dart' as http;

class FinanceService {
  final String baseUrl;
  final String token;

  FinanceService({required this.baseUrl, required this.token});

  Map<String, String> get _headers => {
    'Authorization': 'Bearer $token',
    'Content-Type': 'application/json',
  };

  /// KPIs consolidados
  Future<Map<String, dynamic>> getOverview() async {
    final r = await http.get(
      Uri.parse('$baseUrl/api/v1/admin/finance/overview'),
      headers: _headers,
    );
    return jsonDecode(r.body);
  }

  /// Serie temporal de receita
  Future<Map<String, dynamic>> getRevenue({
    String period = 'monthly',
    String? start,
    String? end,
  }) async {
    final params = <String, String>{'period': period};
    if (start != null) params['start'] = start;
    if (end != null) params['end'] = end;

    final uri = Uri.parse('$baseUrl/api/v1/admin/finance/revenue')
        .replace(queryParameters: params);
    final r = await http.get(uri, headers: _headers);
    return jsonDecode(r.body);
  }

  /// Clientes inadimplentes
  Future<Map<String, dynamic>> getOverdue({int page = 0, int limit = 20}) async {
    final uri = Uri.parse(
      '$baseUrl/api/v1/admin/finance/overdue?page=$page&limit=$limit',
    );
    final r = await http.get(uri, headers: _headers);
    return jsonDecode(r.body);
  }

  /// Analise de churn
  Future<Map<String, dynamic>> getChurn({int months = 6}) async {
    final uri = Uri.parse(
      '$baseUrl/api/v1/admin/finance/churn?months=$months',
    );
    final r = await http.get(uri, headers: _headers);
    return jsonDecode(r.body);
  }

  /// URL para download do Excel (com token na query p/ browser)
  String getExportUrl({String? start, String? end}) {
    final params = <String, String>{'token': token};
    if (start != null) params['start'] = start;
    if (end != null) params['end'] = end;
    return Uri.parse('$baseUrl/api/v1/admin/finance/export')
        .replace(queryParameters: params)
        .toString();
  }
}

Sugestao de Layout do Dashboard

+---------------------------------------------+
|  MRR         |  ARR         |  Ticket Medio  |
|  R$ 3.840,70 |  R$ 46.088   |  R$ 19,90      |
+---------------------------------------------+
|  Ativos      |  Inadimpl.   |  Churn 30d     |
|  193         |  34 (!)      |  4.0%          |
+---------------------------------------------+

[Grafico Linha: Receita Mensal - Bruto vs Liquido]
[Grafico Barras: Stripe vs Asaas por mes]

+---------------------------------------------+
| [Grafico Pizza:        | [Grafico Barras:    |
|  Metodos Pagamento]    |  Novos vs Cancela]  |
+---------------------------------------------+

[Tabela: Inadimplentes - ordenado por falhas]
| Cliente | Email | Falhas | Dias Atraso | Valor |
|---------|-------|--------|-------------|-------|

[Botao: Exportar Excel]  [Filtro: Periodo]

Errors

HTTP Code Quando
401 UNAUTHORIZED Token JWT ausente ou invalido
403 FORBIDDEN Usuario nao e admin
422 VALIDATION_ERROR Parametros de query invalidos (datas, periodo)

Notas Tecnicas

  • Valores em centavos: Todos os campos monetarios (mrr, arr, amount, gross, net) sao em centavos. Frontend converte: cents / 100 para exibir em reais.
  • Churn rate: Calculado como (cancelled_no_mes / ativos_inicio_mes) * 100.
  • Overdue: Inclui subscriptions com payment_failures > 0 OU status = 'suspended'.
  • Export: Gera .xlsx com openpyxl. Headers estilizados (fundo escuro, fonte branca). Colunas auto-dimensionadas.
  • Performance: Overview faz ~5 queries MongoDB. Revenue itera subscriptions em memoria (ok para <10k subs). Para escala maior, migrar para aggregation pipeline.