본문으로 건너뛰기
cccskills
무료GitHub에 공개

payment-integration

Payment processing integration with Stripe and PayPal for Flutter

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

연동 도구Stripe
설치 방법 보기

포함된 파일(1)

  • SKILL.md8.6 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Skill 17: Payment Integration

Overview

This skill provides comprehensive payment processing capabilities for Flutter applications using Stripe and PayPal. Supports one-time payments, subscriptions, and PCI-compliant payment flows.

Features

  • Stripe integration with Payment Intents
  • PayPal checkout integration
  • PCI DSS compliance (sensitive data never touches your server)
  • Subscription management
  • Apple Pay and Google Pay support
  • Payment method storage
  • Webhook handling

Installation

Dependencies

dependencies:
  flutter_stripe: ^10.0.0
  paypal_sdk: ^1.0.0
  pay: ^1.1.2  # For Apple Pay / Google Pay

Stripe Integration

1. Setup

import 'package:flutter_stripe/flutter_stripe.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize Stripe
  Stripe.publishableKey = 'pk_test_your_key_here';
  await Stripe.instance.applySettings();

  runApp(MyApp());
}

2. Payment Service

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

class PaymentService {
  final String backendUrl;

  PaymentService({required this.backendUrl});

  /// Create a payment intent on your backend
  Future<Map<String, dynamic>> createPaymentIntent(
    double amount,
    String currency,
  ) async {
    final response = await http.post(
      Uri.parse('$backendUrl/create-payment-intent'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'amount': (amount * 100).toInt(), // Stripe uses cents
        'currency': currency,
      }),
    );

    if (response.statusCode == 200) {
      return jsonDecode(response.body);
    } else {
      throw Exception('Failed to create payment intent');
    }
  }

  /// Present payment sheet
  Future<bool> presentPaymentSheet(String clientSecret) async {
    try {
      // Initialize payment sheet
      await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
          paymentIntentClientSecret: clientSecret,
          merchantDisplayName: '{{PROJECT_NAME}}',
          style: ThemeMode.system,
        ),
      );

      // Display payment sheet
      await Stripe.instance.presentPaymentSheet();

      return true;
    } on StripeException catch (e) {
      if (e.error.code == FailureCode.Canceled) {
        return false; // User canceled
      }
      rethrow;
    }
  }

  /// Create and confirm payment
  Future<bool> makePayment(double amount, String currency) async {
    try {
      // 1. Create payment intent
      final paymentIntent = await createPaymentIntent(amount, currency);

      // 2. Present payment sheet
      final success = await presentPaymentSheet(paymentIntent['clientSecret']);

      return success;
    } catch (e) {
      print('Payment error: $e');
      return false;
    }
  }
}

3. Payment Provider

import 'package:flutter_riverpod/flutter_riverpod.dart';

class PaymentState {
  final bool isProcessing;
  final bool paymentSuccess;
  final String? error;

  PaymentState({
    this.isProcessing = false,
    this.paymentSuccess = false,
    this.error,
  });

  PaymentState copyWith({
    bool? isProcessing,
    bool? paymentSuccess,
    String? error,
  }) {
    return PaymentState(
      isProcessing: isProcessing ?? this.isProcessing,
      paymentSuccess: paymentSuccess ?? this.paymentSuccess,
      error: error,
    );
  }
}

class PaymentNotifier extends StateNotifier<PaymentState> {
  final PaymentService _paymentService;

  PaymentNotifier(this._paymentService) : super(PaymentState());

  Future<void> processPayment(double amount, String currency) async {
    state = state.copyWith(isProcessing: true, error: null);

    try {
      final success = await _paymentService.makePayment(amount, currency);

      state = state.copyWith(
        isProcessing: false,
        paymentSuccess: success,
        error: success ? null : 'Payment was cancelled or failed',
      );
    } catch (e) {
      state = state.copyWith(
        isProcessing: false,
        paymentSuccess: false,
        error: e.toString(),
      );
    }
  }
}

final paymentProvider = StateNotifierProvider<PaymentNotifier, PaymentState>(
  (ref) => PaymentNotifier(PaymentService(backendUrl: 'https://your-api.com')),
);

4. Payment UI

class PaymentPage extends ConsumerWidget {
  const PaymentPage({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final paymentState = ref.watch(paymentProvider);

    return Scaffold(
      appBar: AppBar(title: const Text('Payment')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          children: [
            Text(
              'Total: \$20.00',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 32),
            if (paymentState.isProcessing)
              const CircularProgressIndicator()
            else
              ElevatedButton(
                onPressed: () {
                  ref.read(paymentProvider.notifier)
                      .processPayment(20.00, 'USD');
                },
                child: const Text('Pay Now'),
              ),
            if (paymentState.error != null)
              Text(
                paymentState.error!,
                style: const TextStyle(color: Colors.red),
              ),
            if (paymentState.paymentSuccess)
              const Text(
                'Payment successful!',
                style: TextStyle(color: Colors.green),
              ),
          ],
        ),
      ),
    );
  }
}

Subscription Management

class SubscriptionService {
  final String backendUrl;

  SubscriptionService({required this.backendUrl});

  Future<Map<String, dynamic>> createSubscription(
    String customerId,
    String priceId,
  ) async {
    final response = await http.post(
      Uri.parse('$backendUrl/create-subscription'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({
        'customerId': customerId,
        'priceId': priceId,
      }),
    );

    return jsonDecode(response.body);
  }

  Future<void> cancelSubscription(String subscriptionId) async {
    await http.post(
      Uri.parse('$backendUrl/cancel-subscription'),
      headers: {'Content-Type': 'application/json'},
      body: jsonEncode({'subscriptionId': subscriptionId}),
    );
  }
}

Apple Pay / Google Pay

import 'package:pay/pay.dart';

class DigitalWalletPayment extends StatelessWidget {
  final double amount;
  final String currency;

  const DigitalWalletPayment({
    super.key,
    required this.amount,
    required this.currency,
  });

  @override
  Widget build(BuildContext context) {
    return GooglePayButton(
      paymentConfigurationAsset: 'google_pay_config.json',
      paymentItems: [
        PaymentItem(
          label: 'Total',
          amount: amount.toStringAsFixed(2),
          status: PaymentItemStatus.final_price,
        ),
      ],
      type: GooglePayButtonType.pay,
      onPaymentResult: (result) {
        // Handle payment result
        print('Payment result: $result');
      },
    );
  }
}

Security Best Practices

  1. Never store card data - Use Stripe tokens only
  2. Backend validation - Always verify payments on server
  3. HTTPS only - All API calls must use HTTPS
  4. PCI Compliance - Don't handle raw card numbers
  5. Webhook verification - Verify Stripe signatures

Backend Requirements

Your backend must implement:

// Node.js/Express example
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

app.post('/create-payment-intent', async (req, res) => {
  const { amount, currency } = req.body;

  const paymentIntent = await stripe.paymentIntents.create({
    amount,
    currency,
    automatic_payment_methods: { enabled: true },
  });

  res.json({ clientSecret: paymentIntent.client_secret });
});

app.post('/webhook', async (req, res) => {
  const sig = req.headers['stripe-signature'];
  const event = stripe.webhooks.constructEvent(
    req.body,
    sig,
    process.env.STRIPE_WEBHOOK_SECRET
  );

  // Handle the event
  switch (event.type) {
    case 'payment_intent.succeeded':
      // Fulfill the purchase
      break;
    case 'payment_intent.payment_failed':
      // Notify user
      break;
  }

  res.json({ received: true });
});

Testing

Use Stripe test cards:

  • 4242 4242 4242 4242 - Success
  • 4000 0000 0000 9995 - Declined
  • 4000 0000 0000 3220 - Requires 3D Secure

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Machine Learning integration for Flutter using TensorFlow Lite and Firebase ML

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Google Maps and Mapbox integration for Flutter applications

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Implement tasks from an OpenSpec change. Use when the user wants to start implementing, continue implementation, or work through tasks.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Enter explore mode - a thinking partner for exploring ideas, investigating problems, and clarifying requirements. Use when the user wants to think through something before or during a change.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

Propose a new change with all artifacts generated in one step. Use when the user wants to quickly describe what they want to build and get a complete proposal with design, specs, and tasks ready for implementation.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

HabitaNexus/monorepo32026년 10월 15일 업데이트

HabitaNexus의 스킬 모두 보기

이 스킬의 문제 신고