Pagar.me — Especificação para os apps Flutter (cliente e painel admin)¶
Data: 2026-10-21 | Status: Especificação — não implementada nos apps | Contrato da API: Pagar.me — Integração
A API já aceita o Pagar.me; os apps não. Esta página lista, arquivo por arquivo, o que muda em
fdplay-front-end (cliente) e fdplay-front-end-admin (painel). Os caminhos foram lidos em
21/10/2026; confirme-os antes de editar.
Ordem importa: o cliente primeiro, o seletor depois
O app do cliente que não conhece um gateway cai em Stripe. Por isso a API recusa
pagarme como padrão (409) até allow_as_default = true no credentials.toml. Ligue essa
trava só depois de a nova versão do app do cliente estar publicada e a versão mínima
(GET /config/client-version) atualizada.
1. App do cliente (fdplay-front-end)¶
1.1 Reconhecer o gateway — lib/config/payment_config.dart¶
enum PaymentGateway { stripe, asaas }→ acrescentarpagarme.fetchActiveGateway(): oswitchtemdefault:→ Stripe. Mapear'pagarme'e tratar valor desconhecido como o último gateway válido (ou Asaas, o padrão da plataforma), nunca como Stripe.- Novo getter
isPagarmeActive.isPixAvailablehoje éisAsaasActive: passa a incluir o Pagar.me (PIX avulso), sem Pix Automático. - PIX do Pagar.me não é recorrente (ver 1.4): a tela não pode prometer "débito automático".
1.2 Serviço — novo lib/services/pagarme_service.dart (par de asaas_service.dart)¶
| Função | Rota |
|---|---|
getConfig() |
GET /pagarme/config → public_key |
tokenizeCard(card) |
POST https://api.pagar.me/core/v5/tokens?appId={public_key} → token_xxx (uso único) |
subscribe(planId, cardToken, billingAddress, promo?) |
POST /pagarme/subscribe |
subscribePix(planId, promo?) |
POST /pagarme/subscribe/pix |
updateCard(cardToken, billingAddress) |
PUT /pagarme/subscription/credit-card |
cancel() |
DELETE /pagarme/subscription (ou o genérico DELETE /customers/me/subscription) |
renew(cardToken + billingAddress ou payment_method:'pix') |
PUT /customers/me/subscription/renew |
O número do cartão nunca vai para a API. Token usado não se reaproveita: erro → tokenizar de novo.
1.3 Telas de pagamento — ui/widgets/pages/sign_up/widgets/sign_up_payment.dart, ui/widgets/credit_card/payment.dart, ui/widgets/dialogs/account_dialog.dart¶
- Escolher o fluxo por
activePaymentGateway: no Pagar.me, tokenizar →subscribe; sem criptografia RSA, semcredit_card_holder_info. - Endereço de cobrança (CEP, rua, número, bairro, cidade, UF) no formulário do cartão, enviado em
billing_address(ADR-0192). Sem ele o Pagar.me recusa todo cartão.422comfield: billing_address= pedir o endereço. - Assinatura nasce
pending: repolarGET /customers/me/subscription(já existe, a cada ~4 s) e mostrar "processando". Sair da espera quando o status deixar de serpending:activeentra;cancelled= cartão recusado ("Cartão recusado, tente outro"). Não escrever "Seu cartão foi aceito" enquantopending. - Erros:
400(falta CPF no perfil — pedir),402 PAYMENT_DECLINED(recusado na hora: tokenizar de novo e oferecer outro cartão),504(não repetir: pode ter cobrado; aguardar e repolar),502(gateway indisponível). - Trocar cartão:
updateCard(in-place), igual ao Asaas/Stripe.
1.4 PIX — ui/widgets/common/pix_expiration_timer.dart e telas de PIX¶
- Resposta:
info.pix.{qr_code, qr_code_image_url, expiration_date, charge_id}— a imagem vem como URL, não base64. expiration_dateé a janela de 10 min; reabrir o QR do mesmo pedido:GET /customers/me/pix-qr(410 = cobrança já não está aberta → gerar outro).- Vencido o período, o cliente renova (
renewcompayment_method:'pix') e recebe um QR novo. Texto da tela: "PIX do período", não "recorrente".
1.5 Ingresso — services/ticket_store_service.dart, ui/widgets/pages/ticket_store_page.dart, ui/widgets/dialogs/ticket_store_dialog.dart¶
POST /store/purchase/pagarme/card(card_token,billing_address,subscribe?) e…/pix; sem cadastro:/store/purchase/checkout/pagarme/{card,pix}+buyer.- PIX do ingresso:
pix.payload/pix.image_url/pix.expiration_date; semsubscribeno PIX. 504na compra no cartão: o pedido fica reservado; mostrar "em processamento" e consultarGET /me/ticket-orders(não comprar de novo).
2. Painel admin (fdplay-front-end-admin)¶
2.1 Seletor de gateway — lib/presentation/views/finance/platform_config_view.dart¶
_gatewayOptions = ['stripe', 'asaas'](linha ~30) e o rótulogw == 'stripe' ? 'Stripe' : 'Asaas'(~119) → acrescentarpagarme/ "Pagar.me (Stone)".- Tratar o 409 do
PUT(sem chaves, ou travaallow_as_defaultdesligada) mostrandodetail; não "voltar" o seletor em silêncio. - Aviso na tela ao escolher Pagar.me: "apps antigos usam Stripe".
2.2 Menu e listagem — lib/config/router/routes_provider.dart, presentation/cubits/api_cubits_presentation.dart, views/asaas_subscriptions/*¶
- Novo menu Pagar.me (par de
asaasSubscriptions) e rotaadmin/pagarme/subscriptions; clonarasaas_subscriptions_view.darte o modeloasaas_subscription_model_domain.dart(campos extras:pagarme_subscription_id,pagarme_customer_id,pagarme_order_id,pagarme_contract_*). - Ações da linha: cancelar (
POST …/{id}/cancel), pagamentos (GET …/{id}/payments;valueem reais,id=ch_xxx), estorno (POST …/{id}/refund,valueopcional em reais) e histórico (GET …/{id}/refunds). Mesmo contratodocs+infodo Asaas. - Estatísticas:
GET /admin/pagarme/subscriptions/stats(MRR em centavos; PIX não entra).
2.3 Planos — views/plans/add_plan_view.dart¶
publishTosó ligaasaas(estripe). Aceitarpagarmeno toggle; a API não cria nada no gateway (assinatura avulsa), só registra a preferência.- Listagem pública de planos para o app:
GET /plans?gateway=pagarmedevolve todo plano ativo.
2.4 Financeiro — views/finance/finance_view.dart (~1018), widgets/finance_report_pdf.dart (~505, ~879)¶
- KPIs: acrescentar "MRR Pagar.me" (
overview.mrr_pagarme); o PDF hoje imprime sómrr_asaas/mrr_stripe. - Receita por período: o item traz
pagarmeao lado deasaas/stripe(centavos). - Filtro
gateway: aceitapagarme. Dashboard de assinaturas:by_gateway.pagarmeegateway_distribution.pagarme_share.
2.5 Cliente 360 e estorno¶
domain/models/customer_360_model_domain.dart: lerpagarme_charges(mesmoCharge360),isPagarme,pagarme_customer_id,pagarme_subscription_id; somar no resumo.widgets/customer_payments_tab.dartecustomer_subscriptions_tab.dart: listar o novo grupo e o rótuloPAGARME.views/finance/refund_by_charge_view.dart:['stripe', 'asaas'](~155) → incluirpagarme(charge_id=ch_xxx). 404 = a cobrança não é de nenhuma assinatura/pedido nosso (a conta é compartilhada) — mostrar a mensagem.- Cancelar assinatura pela aba do cliente já usa a rota genérica, que detecta o gateway.
3. Critérios de aceite¶
- Com padrão
asaas, nada muda em nenhum app. - App novo + padrão
pagarme(trava ligada): cartão com token,pending→activepelo polling; PIX com QR por URL; renovar PIX gera novo QR. - App antigo nunca chega a ver
pagarme(trava desligada até a versão mínima subir). - Painel: menu Pagar.me lista, cancela e estorna; MRR e receita mostram o gateway; estorno por
charge_idrecusa cobrança alheia com 404. - Nenhum log ou erro do app contém número de cartão.
Sem verificação local
Esta máquina não tem Flutter SDK: nenhuma dessas mudanças foi compilada nem testada. Validar no sandbox do Pagar.me com chaves de teste (DEBT-154) antes de ligar a trava.