Skip to content

Flutter Quick Start - Pagamentos Recorrentes

Guia rápido de 5 minutos para integrar pagamentos recorrentes no Flutter.

Dois Gateways Disponíveis

O FDPlay suporta Asaas (gateway BR) e Stripe (internacional). Este guia cobre o Asaas. Para Stripe, veja a seção Stripe abaixo ou a documentação completa.


Asaas Quick Start

O Asaas é o gateway principal para clientes brasileiros. Os dados do cartão são enviados diretamente ao backend — não é necessária criptografia client-side.

1. Adicionar Dependência (30 segundos)

# pubspec.yaml
dependencies:
  http: ^1.1.0
flutter pub get

2. Criar Serviço (2 minutos)

// lib/services/subscription_service.dart
import 'dart:convert';
import 'package:http/http.dart' as http;

class SubscriptionService {
  final String baseUrl = 'https://sua-api.com'; // ← ALTERE AQUI
  final String Function() getToken;

  SubscriptionService({required this.getToken});

  Future<Map<String, dynamic>> subscribe({
    required String planId,
    required String cardNumber,
    required String cardHolder,
    required String cardCvv,
    required String cardExpMonth,
    required String cardExpYear,
    required String holderName,
    required String holderEmail,
    required String holderCpfCnpj,
    required String holderPostalCode,
    required String holderAddressNumber,
    required String holderPhone,
  }) async {
    // Criar assinatura via Asaas
    final response = await http.post(
      Uri.parse('$baseUrl/api/v1/asaas/subscribe'),
      headers: {
        'Authorization': 'Bearer ${getToken()}',
        'Content-Type': 'application/json',
      },
      body: json.encode({
        'plan_id': planId,
        'credit_card': {
          'holderName': cardHolder.toUpperCase(),
          'number': cardNumber.replaceAll(' ', ''),
          'expiryMonth': cardExpMonth.padLeft(2, '0'),
          'expiryYear': cardExpYear,
          'ccv': cardCvv,
        },
        'credit_card_holder_info': {
          'name': holderName,
          'email': holderEmail,
          'cpfCnpj': holderCpfCnpj,
          'postalCode': holderPostalCode,
          'addressNumber': holderAddressNumber,
          'phone': holderPhone,
        },
      }),
    );

    if (response.statusCode != 201) {
      throw Exception(json.decode(response.body)['detail']);
    }

    return json.decode(response.body);
  }
}

3. Usar no Checkout (1 minuto)

// No seu widget de checkout
Future<void> _onSubmitPayment() async {
  try {
    final service = SubscriptionService(
      getToken: () => yourUserToken, // ← JWT do usuário logado
    );

    final subscription = await service.subscribe(
      planId: 'plan-basic',
      cardNumber: _cardNumberController.text,
      cardHolder: _cardHolderController.text,
      cardCvv: _cvvController.text,
      cardExpMonth: _expMonthController.text,
      cardExpYear: _expYearController.text,
      holderName: 'Nome Completo',
      holderEmail: 'email@example.com',
      holderCpfCnpj: '24971563792',
      holderPostalCode: '89223005',
      holderAddressNumber: '277',
      holderPhone: '47998781877',
    );

    // Sucesso!
    Navigator.pushReplacementNamed(context, '/subscription-success');
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Erro: $e')),
    );
  }
}

Testar

Cartões de Teste (Sandbox)

Bandeira Número Status
Visa 4539620659922097 Aprovado
Mastercard 5555666677778884 Aprovado

Dados: - Titular: JOAO DA SILVA - Validade: 12/2030 - CVV: 123


Documentação Completa

Para exemplos completos, troubleshooting e detalhes:

Integração Asaas


Importante

  • Backend transmite dados do cartão ao Asaas via HTTPS (PCI compliant)
  • Asaas cobra automaticamente todo mês (modelo Netflix)
  • Nunca logue dados do cartão
  • Nunca armazene dados do cartão no app


Stripe Quick Start

1. Adicionar Dependência (30 segundos)

# pubspec.yaml
dependencies:
  flutter_stripe: ^11.0.0
  http: ^1.1.0
flutter pub get

2. Criar Serviço (2 minutos)

// lib/services/stripe_subscription_service.dart
import 'dart:convert';
import 'package:flutter_stripe/flutter_stripe.dart';
import 'package:http/http.dart' as http;

class StripeSubscriptionService {
  final String baseUrl = 'https://sua-api.com'; // ← ALTERE AQUI
  final String Function() getToken;

  StripeSubscriptionService({required this.getToken});

  /// Inicializar Stripe SDK (chamar uma vez no app)
  /// Busca a publishable key do backend — NUNCA hardcodar.
  Future<void> init() async {
    final resp = await http.get(Uri.parse('$baseUrl/api/v1/stripe/config'));
    if (resp.statusCode != 200) throw Exception('Stripe config unavailable');
    final data = json.decode(resp.body);
    Stripe.publishableKey = data['publishable_key'];
    await Stripe.instance.applySettings();
  }

  /// Criar assinatura Stripe
  Future<Map<String, dynamic>> subscribe({
    required String planId,
  }) async {
    // 1. Tokenizar cartão via Stripe SDK
    final pm = await Stripe.instance.createPaymentMethod(
      params: PaymentMethodParams.card(
        paymentMethodData: PaymentMethodData(),
      ),
    );

    // 2. Enviar para backend
    final resp = await http.post(
      Uri.parse('$baseUrl/api/v1/stripe/subscribe'),
      headers: {
        'Authorization': 'Bearer ${getToken()}',
        'Content-Type': 'application/json',
      },
      body: json.encode({
        'plan_id': planId,
        'payment_method_id': pm.id,
      }),
    );

    if (resp.statusCode != 201) {
      throw Exception(json.decode(resp.body)['detail']);
    }

    return json.decode(resp.body);
  }
}

3. Usar no Checkout (1 minuto)

Future<void> _onSubmitStripe() async {
  try {
    final service = StripeSubscriptionService(
      getToken: () => yourUserToken,
    );

    final result = await service.subscribe(planId: 'plan-basic');

    // Se 3D Secure necessário
    if (result['info']['client_secret'] != null) {
      await Stripe.instance.confirmPayment(
        paymentIntentClientSecret: result['info']['client_secret'],
      );
    }

    Navigator.pushReplacementNamed(context, '/success');
  } catch (e) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Erro: $e')),
    );
  }
}

Cartões de Teste Stripe

Número Cenário
4242 4242 4242 4242 Aprovado
4000 0025 0000 3155 Requer 3D Secure
4000 0000 0000 9995 Recusado

Dados: Validade futura, CVC qualquer (ex: 123)

Documentação completa: Integração Stripe


Pronto!

Com esses passos, você já pode processar pagamentos recorrentes via Asaas ou Stripe.