paypal_checkout_flutter 0.0.4 copy "paypal_checkout_flutter: ^0.0.4" to clipboard
paypal_checkout_flutter: ^0.0.4 copied to clipboard

Flutter PayPal integration — native SDK checkout, cards, vault, subscriptions, plans, products, orders & refunds. No WebView.

example/example.dart

// Example: How to use paypal_checkout_flutter

import 'package:flutter/foundation.dart';
import 'package:paypal_checkout_flutter/paypal_checkout_flutter.dart';

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// Shared: Initialize once
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

final paypal = FlutterPaypalPayment();

Future<void> initialize() async {
  final result = await paypal.init(
    PaypalConfig(
      clientId: 'YOUR_PAYPAL_CLIENT_ID',
      environment: PaypalEnvironment.sandbox,
      returnUrl: 'com.example.myapp://paypalpay',
    ),
  );
  result.fold(
    (f) => debugPrint('Init error: ${f.message}'),
    (_) => debugPrint('PayPal ready'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 1: PayPal checkout with backend
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> payWithBackend() async {
  final orderId = await _createOrderOnYourServer();

  final result = await paypal.pay(
    PaymentRequest(orderId: orderId),
  );

  result.fold(
    (failure) => debugPrint('Error: ${failure.message} (${failure.code})'),
    (success) {
      debugPrint('Paid! Order: ${success.orderId}, Payer: ${success.payerId}');
    },
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 2: PayPal checkout without backend
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> payWithoutBackend() async {
  final result = await paypal.payDirect(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    params: PaymentParams(
      amount: '25.00',
      currencyCode: 'USD',
      description: 'Compra de producto X',
    ),
  );

  result.fold(
    (failure) => debugPrint('Error: ${failure.message} (${failure.code})'),
    (success) => debugPrint('Paid & captured! Order: ${success.orderId}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 3: Card payment (no PayPal login)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> payWithCard() async {
  final orderId = await _createOrderOnYourServer();

  final result = await paypal.payWithCard(
    CardPaymentRequest(
      orderId: orderId,
      card: PaymentCard(
        number: '4111111111111111',
        expirationMonth: '12',
        expirationYear: '2028',
        securityCode: '123',
      ),
    ),
  );

  result.fold(
    (failure) => debugPrint('Card error: ${failure.message} (${failure.code})'),
    (success) => debugPrint('Card paid! Order: ${success.orderId}, '
        'Status: ${success.status}, 3DS: ${success.didAttemptThreeDSecureAuthentication}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 4: Card payment without backend
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> payWithCardDirect() async {
  final result = await paypal.payWithCardDirect(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    params: PaymentParams(
      amount: '50.00',
      currencyCode: 'USD',
      description: 'Card purchase',
    ),
    buildRequest: (orderId) => CardPaymentRequest(
      orderId: orderId,
      card: PaymentCard(
        number: '4111111111111111',
        expirationMonth: '12',
        expirationYear: '2028',
        securityCode: '123',
      ),
    ),
  );

  result.fold(
    (failure) => debugPrint('Error: ${failure.message}'),
    (success) => debugPrint('Card paid & captured! Order: ${success.orderId}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 5: Vault a PayPal account (save for future)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> vaultPaypalAccount() async {
  final setupTokenId = await _createSetupTokenOnYourServer();

  final result = await paypal.vaultPaypal(
    VaultPaypalRequest(setupTokenId: setupTokenId),
  );

  result.fold(
    (failure) => debugPrint('Vault error: ${failure.message}'),
    (success) => debugPrint('PayPal vaulted! Token: ${success.setupTokenId}, '
        'Status: ${success.status}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 6: Vault a card (save for future)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> vaultCreditCard() async {
  final setupTokenId = await _createSetupTokenOnYourServer();

  final result = await paypal.vaultCard(
    VaultCardRequest(
      setupTokenId: setupTokenId,
      card: PaymentCard(
        number: '4111111111111111',
        expirationMonth: '12',
        expirationYear: '2028',
        securityCode: '123',
      ),
    ),
  );

  result.fold(
    (failure) => debugPrint('Card vault error: ${failure.message}'),
    (success) => debugPrint ('Card vaulted! Token: ${success.setupTokenId}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 7: Pay Later (PayPal financing)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> payLater() async {
  final orderId = await _createOrderOnYourServer();

  final result = await paypal.pay(
    PaymentRequest(
      orderId: orderId,
      fundingSource: PaypalFundingSource.payLater,
    ),
  );

  result.fold(
    (failure) => debugPrint('Pay Later error: ${failure.message}'),
    (success) => debugPrint('Pay Later done! Order: ${success.orderId}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 8: Vault PayPal without backend
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> vaultPaypalDirect() async {
  final result = await paypal.vaultPaypalDirect(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    customer: {'id': 'CUSTOMER_123'},
  );

  result.fold(
    (failure) => debugPrint('Vault error: ${failure.message}'),
    (success) => debugPrint('PayPal vaulted! Payment Token: $success'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 9: Vault card without backend
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> vaultCardDirect() async {
  final result = await paypal.vaultCardDirect(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    card: PaymentCard(
      number: '4111111111111111',
      expirationMonth: '12',
      expirationYear: '2028',
      securityCode: '123',
    ),
    customer: {'id': 'CUSTOMER_123'},
  );

  result.fold(
    (failure) => debugPrint('Card vault error: ${failure.message}'),
    (success) => debugPrint('Card vaulted! Payment Token: $success'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 10: Get order details
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> checkOrderDetails() async {
  final result = await paypal.getOrderDetails(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    orderId: 'ORDER_ID',
  );

  result.fold(
    (failure) => debugPrint('Error: ${failure.message}'),
    (order) => debugPrint('Order status: ${order['status']}, '
        'Amount: ${order['purchase_units']?[0]?['amount']}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 11: Refund a captured payment
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> refundPayment() async {
  // Full refund
  final result = await paypal.refund(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    captureId: 'CAPTURE_ID',
  );

  result.fold(
    (failure) => debugPrint('Refund error: ${failure.message}'),
    (refund) => debugPrint('Refunded! ID: ${refund['id']}, '
        'Status: ${refund['status']}'),
  );
}

Future<void> partialRefund() async {
  // Partial refund: refund only $5.00 of a larger capture
  final result = await paypal.refund(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    captureId: 'CAPTURE_ID',
    amount: '5.00',
    currencyCode: 'USD',
  );

  result.fold(
    (failure) => debugPrint('Partial refund error: ${failure.message}'),
    (refund) => debugPrint('Partial refund done! ID: ${refund['id']}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<String> _createOrderOnYourServer() async {
  // POST to your server -> PayPal Orders API v2 -> return order ID
  return 'MOCK_ORDER_ID';
}

Future<String> _createSetupTokenOnYourServer() async {
  // POST to your server -> PayPal Setup Tokens API -> return setup token ID
  return 'MOCK_SETUP_TOKEN_ID';
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 12: Authorize & Capture (two-step payments)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> authorizeAndCapture() async {
  // Step 1: Authorize order (hold funds)
  final authResult = await paypal.authorizeOrder(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    orderId: 'ORDER_ID',
  );

  authResult.fold(
    (failure) => debugPrint('Auth error: ${failure.message}'),
    (auth) async {
      final authId = auth['purchase_units']?[0]?['payments']?['authorizations']
          ?[0]?['id'] as String?;
      debugPrint('Authorized! ID: $authId');

      // Step 2: Capture the authorization later
      if (authId != null) {
        final captureResult = await paypal.captureAuthorization(
          clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
          authorizationId: authId,
        );
        captureResult.fold(
          (f) => debugPrint('Capture error: ${f.message}'),
          (c) => debugPrint('Captured! ID: ${c['id']}'),
        );
      }
    },
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 13: Update order (shipping/tracking)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> updateOrderTracking() async {
  final result = await paypal.updateOrder(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    orderId: 'ORDER_ID',
    patchOperations: [
      {
        'op': 'add',
        'path':
            '/purchase_units/@reference_id==\'default\'/shipping/trackers',
        'value': [
          {
            'carrier': 'FEDEX',
            'tracking_number': '1234567890',
            'status': 'SHIPPED',
          }
        ],
      }
    ],
  );

  result.fold(
    (failure) => debugPrint('Update error: ${failure.message}'),
    (_) => debugPrint('Order updated with tracking!'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 14: Create product + plan + subscription (full)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> createFullSubscription() async {
  const secret = 'YOUR_PAYPAL_CLIENT_SECRET';

  // Step 1: Create a product
  final productResult = await paypal.createProduct(
    clientSecret: secret,
    product: {
      'name': 'Premium Plan',
      'description': 'Access to all premium features',
      'type': 'SERVICE',
      'category': 'SOFTWARE',
    },
  );

  final productId = productResult.fold(
    (f) {
      debugPrint('Product error: ${f.message}');
      return null;
    },
    (product) {
      debugPrint('Product created: ${product['id']}');
      return product['id'] as String;
    },
  );
  if (productId == null) return;

  // Step 2: Create a billing plan
  final planResult = await paypal.createPlan(
    clientSecret: secret,
    plan: {
      'product_id': productId,
      'name': 'Monthly Premium',
      'billing_cycles': [
        {
          'frequency': {'interval_unit': 'MONTH', 'interval_count': 1},
          'tenure_type': 'REGULAR',
          'sequence': 1,
          'total_cycles': 0,
          'pricing_scheme': {
            'fixed_price': {'value': '9.99', 'currency_code': 'USD'},
          },
        }
      ],
      'payment_preferences': {
        'auto_bill_outstanding': true,
        'payment_failure_threshold': 3,
      },
    },
  );

  final planId = planResult.fold(
    (f) {
      debugPrint('Plan error: ${f.message}');
      return null;
    },
    (plan) {
      debugPrint('Plan created: ${plan['id']}');
      return plan['id'] as String;
    },
  );
  if (planId == null) return;

  // Step 3: Create a subscription
  final subResult = await paypal.createSubscription(
    clientSecret: secret,
    subscription: {
      'plan_id': planId,
      'subscriber': {
        'name': {'given_name': 'John', 'surname': 'Doe'},
        'email_address': 'john@example.com',
      },
      'application_context': {
        'return_url': 'https://example.com/return',
        'cancel_url': 'https://example.com/cancel',
      },
    },
  );

  subResult.fold(
    (f) => debugPrint('Subscription error: ${f.message}'),
    (sub) => debugPrint(
        'Subscription created: ${sub['id']}, Status: ${sub['status']}'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 15: List & manage products
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> manageProducts() async {
  const secret = 'YOUR_PAYPAL_CLIENT_SECRET';

  // List all products
  final listResult = await paypal.listProducts(
    clientSecret: secret,
    pageSize: 10,
    totalRequired: true,
  );

  listResult.fold(
    (f) => debugPrint('List error: ${f.message}'),
    (data) {
      final products = data['products'] as List;
      debugPrint('Total products: ${data['total_items']}');
      for (final p in products) {
        debugPrint('  ${p['id']}: ${p['name']}');
      }
    },
  );

  // Get product details
  final detailResult = await paypal.getProductDetails(
    clientSecret: secret,
    productId: 'PROD-XXXX',
  );

  detailResult.fold(
    (f) => debugPrint('Detail error: ${f.message}'),
    (product) => debugPrint('Product: ${product['name']} (${product['type']})'),
  );

  // Update product description
  final updateResult = await paypal.updateProduct(
    clientSecret: secret,
    productId: 'PROD-XXXX',
    patchOperations: [
      {'op': 'replace', 'path': '/description', 'value': 'Updated desc'},
    ],
  );

  updateResult.fold(
    (f) => debugPrint('Update error: ${f.message}'),
    (_) => debugPrint('Product updated!'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 16: List & manage plans
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> managePlans() async {
  const secret = 'YOUR_PAYPAL_CLIENT_SECRET';

  // List plans for a product
  final listResult = await paypal.listPlans(
    clientSecret: secret,
    productId: 'PROD-XXXX',
    pageSize: 10,
  );

  listResult.fold(
    (f) => debugPrint('List error: ${f.message}'),
    (data) {
      final plans = data['plans'] as List;
      for (final p in plans) {
        debugPrint('  ${p['id']}: ${p['name']} (${p['status']})');
      }
    },
  );

  // Update plan pricing
  final priceResult = await paypal.updatePlanPricing(
    clientSecret: secret,
    planId: 'P-XXXX',
    pricingSchemes: [
      {
        'billing_cycle_sequence': 1,
        'pricing_scheme': {
          'fixed_price': {'value': '14.99', 'currency_code': 'USD'},
        },
      }
    ],
  );

  priceResult.fold(
    (f) => debugPrint('Price update error: ${f.message}'),
    (_) => debugPrint('Plan pricing updated!'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 17: Subscription lifecycle
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> manageSubscription() async {
  const secret = 'YOUR_PAYPAL_CLIENT_SECRET';
  const subId = 'I-XXXX';

  // List active subscriptions
  final listResult = await paypal.listSubscriptions(
    clientSecret: secret,
    statuses: 'ACTIVE',
    pageSize: 20,
  );

  listResult.fold(
    (f) => debugPrint('List error: ${f.message}'),
    (data) {
      final subs = data['subscriptions'] as List;
      debugPrint('Active subscriptions: ${subs.length}');
    },
  );

  // Suspend a subscription
  final suspendResult = await paypal.suspendSubscription(
    clientSecret: secret,
    subscriptionId: subId,
    reason: 'Customer requested pause',
  );

  suspendResult.fold(
    (f) => debugPrint('Suspend error: ${f.message}'),
    (_) => debugPrint('Subscription suspended!'),
  );

  // Reactivate
  final activateResult = await paypal.activateSubscription(
    clientSecret: secret,
    subscriptionId: subId,
    reason: 'Customer wants to resume',
  );

  activateResult.fold(
    (f) => debugPrint('Activate error: ${f.message}'),
    (_) => debugPrint('Subscription reactivated!'),
  );

  // Revise subscription (change plan)
  final reviseResult = await paypal.reviseSubscription(
    clientSecret: secret,
    subscriptionId: subId,
    revisionDetails: {'plan_id': 'P-NEW-PLAN'},
  );

  reviseResult.fold(
    (f) => debugPrint('Revise error: ${f.message}'),
    (data) => debugPrint('Revision link: ${data['links']}'),
  );

  // Cancel
  final cancelResult = await paypal.cancelSubscription(
    clientSecret: secret,
    subscriptionId: subId,
    reason: 'Customer requested cancellation',
  );

  cancelResult.fold(
    (f) => debugPrint('Cancel error: ${f.message}'),
    (_) => debugPrint('Subscription cancelled.'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 18: Capture outstanding payment
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> captureOutstandingPayment() async {
  final result = await paypal.captureSubscriptionPayment(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    subscriptionId: 'I-XXXX',
    captureRequest: {
      'note': 'Charging outstanding balance',
      'capture_type': 'OUTSTANDING_BALANCE',
      'amount': {'currency_code': 'USD', 'value': '10.00'},
    },
  );

  result.fold(
    (f) => debugPrint('Capture error: ${f.message}'),
    (data) => debugPrint('Payment captured! $data'),
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 19: List subscription transactions
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> listTransactions() async {
  final result = await paypal.listSubscriptionTransactions(
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
    subscriptionId: 'I-XXXX',
    startTime: '2026-01-01T00:00:00Z',
    endTime: '2026-04-18T23:59:59Z',
  );

  result.fold(
    (f) => debugPrint('Error: ${f.message}'),
    (data) {
      final txns = data['transactions'] as List;
      debugPrint('Transactions: ${txns.length}');
      for (final txn in txns) {
        debugPrint('  ${txn['id']}: ${txn['status']} — '
            '${txn['amount_with_breakdown']?['gross_amount']}');
      }
    },
  );
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// FLOW 20: Use PaypalSubscriptionService directly
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Future<void> useServiceDirectly() async {
  final service = PaypalSubscriptionService(
    config: PaypalConfig(
      clientId: 'YOUR_PAYPAL_CLIENT_ID',
      environment: PaypalEnvironment.sandbox,
      returnUrl: 'com.example.myapp://paypalpay',
    ),
    clientSecret: 'YOUR_PAYPAL_CLIENT_SECRET',
  );

  try {
    // These plan lifecycle methods are only available via the service
    await service.updatePlan(
      'P-XXXX',
      patchOperations: [
        {'op': 'replace', 'path': '/description', 'value': 'Updated plan'},
      ],
    );

    await service.activatePlan('P-XXXX');
    debugPrint('Plan activated!');

    await service.deactivatePlan('P-XXXX');
    debugPrint('Plan deactivated!');
  } finally {
    service.dispose();
  }
}
0
likes
0
points
116
downloads

Publisher

verified publisherignacio-manchu.com

Weekly Downloads

Flutter PayPal integration — native SDK checkout, cards, vault, subscriptions, plans, products, orders & refunds. No WebView.

Repository (GitHub)
View/report issues

Topics

#paypal #payments #checkout #subscriptions #in-app-purchase

License

unknown (license)

Dependencies

dartz, flutter, http

More

Packages that depend on paypal_checkout_flutter

Packages that implement paypal_checkout_flutter