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

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

paypal_checkout_flutter #

pub package License: BSD-3

A complete Flutter package for PayPal payments using the native PayPal Mobile SDK (Android v2.3.0 / iOS v2.0.1). Type-safe Dart ↔ Kotlin/Swift communication via Pigeon.

No WebView. Opens the system browser or processes cards directly with the native SDK.

Features #

Native SDK (Pigeon) #

Feature Method Backend required
PayPal Checkout pay() Yes
PayPal Checkout (no backend) payDirect() No
Pay Later (financing) pay() + payLater Yes
Card payment payWithCard() Yes
Card payment (no backend) payWithCardDirect() No
Vault PayPal account vaultPaypal() Yes
Vault card vaultCard() Yes
Vault PayPal (no backend) vaultPaypalDirect() No
Vault card (no backend) vaultCardDirect() No

REST API — Orders & Payments #

Endpoint Method
Create order createOrder()*
Get order details getOrderDetails()
Update order (PATCH) updateOrder()
Capture order captureOrder()*
Authorize order authorizeOrder()
Capture authorization captureAuthorization()
Void authorization voidAuthorization()
Refund capture refund()

REST API — Catalog Products (4/4 endpoints) #

Endpoint Method
Create product createProduct()
List products listProducts()
Show product details getProductDetails()
Update product updateProduct()

REST API — Billing Plans (7/7 endpoints) #

Endpoint Method
Create plan createPlan()
List plans listPlans()
Show plan details getPlanDetails()
Update plan updatePlan()**
Activate plan activatePlan()**
Deactivate plan deactivatePlan()**
Update pricing schemes updatePlanPricing()

REST API — Subscriptions (10/10 endpoints) #

Endpoint Method
Create subscription createSubscription()
Show subscription details getSubscriptionDetails()
List subscriptions listSubscriptions()
Update subscription updateSubscription()
Revise subscription reviseSubscription()
Activate subscription activateSubscription()
Suspend subscription suspendSubscription()
Cancel subscription cancelSubscription()
Capture payment captureSubscriptionPayment()
List transactions listSubscriptionTransactions()

* Available via PaypalOrderService and internally used by payDirect()/payWithCardDirect(). ** Available via PaypalSubscriptionService directly.

  • Full 3D Secure support for card payments
  • Clean architecture: entities, repositories, mappers
  • Either<Failure, Success> with dartz for error handling
  • 177 unit tests with full coverage

Requirements #

  • Android: minSdk 23, compileSdk 34, Java 17
  • iOS: iOS 16.0+
  • Flutter: >=1.17.0
  • A PayPal app (developer.paypal.com)

Installation #

dependencies:
  paypal_checkout_flutter: ^0.0.3

Android Setup #

Add the deep link intent filter in your AndroidManifest.xml:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="com.example.myapp" android:host="paypalpay" />
    </intent-filter>
</activity>

Quick Start #

Initialize (once at app startup) #

import 'package:paypal_checkout_flutter/paypal_checkout_flutter.dart';

final paypal = FlutterPaypalPayment();

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await paypal.init(PaypalConfig(
    clientId: 'YOUR_CLIENT_ID',
    environment: PaypalEnvironment.sandbox,
    returnUrl: 'com.example.myapp://paypalpay',
  ));

  runApp(MyApp());
}

Usage Examples #

1. PayPal Checkout (with backend) #

Your server creates the order via PayPal Orders API and returns the orderId.

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

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

2. PayPal Checkout (no backend) #

Creates the order, opens checkout, and captures — all from Flutter.

Note: Requires your clientSecret. Not recommended for production.

final result = await paypal.payDirect(
  clientSecret: 'YOUR_SECRET',
  params: PaymentParams(
    amount: '25.00',
    currencyCode: 'USD',
    description: 'Product X purchase',
  ),
);

3. Card Payment #

Charge a card directly without PayPal login. Supports 3D Secure automatically.

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

3b. PaypalCardForm Widget #

Drop-in PayPal-styled card form. Shows animated 3D card preview, auto-detects card network (Visa, Mastercard, Amex, Discover), and validates all fields client-side before calling onSubmit.

import 'package:paypal_checkout_flutter/paypal_checkout_flutter.dart';

showModalBottomSheet(
  context: context,
  isScrollControlled: true,
  backgroundColor: Colors.transparent,
  builder: (ctx) => Padding(
    padding: EdgeInsets.only(
      bottom: MediaQuery.of(ctx).viewInsets.bottom,
    ),
    child: SingleChildScrollView(
      child: PaypalCardForm(
        amount: '35.20',
        currency: 'USD',
        submitButtonText: 'Pay \$35.20',
        requireCardholderName: false,   // optional name field
        requireBillingPostalCode: false, // optional ZIP field
        onSubmit: (card) async {
          Navigator.of(ctx).pop();
          final result = await paypal.payWithCard(
            CardPaymentRequest(orderId: 'ORDER_ID', card: card),
          );
          result.fold(
            (err) => showError(err.message),
            (ok)  => showSuccess(ok.orderId),
          );
        },
        onError: (message) => showError(message),
      ),
    ),
  ),
);

4. Pay Later (Financing) #

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

5. Vault: Save PayPal Account #

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

6. Vault: Save Card #

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

7. Refund (Total or Partial) #

// Full refund
final result = await paypal.refund(
  clientSecret: 'YOUR_SECRET',
  captureId: 'CAPTURE_ID',
);

// Partial refund ($5.00)
final partial = await paypal.refund(
  clientSecret: 'YOUR_SECRET',
  captureId: 'CAPTURE_ID',
  amount: '5.00',
  currencyCode: 'USD',
);

8. Order Authorization Flow #

// Authorize (hold funds)
final auth = await paypal.authorizeOrder(
  clientSecret: 'YOUR_SECRET',
  orderId: 'ORDER_ID',
);

// Capture later
final capture = await paypal.captureAuthorization(
  clientSecret: 'YOUR_SECRET',
  authorizationId: 'AUTH_ID',
);

// Or void
final voided = await paypal.voidAuthorization(
  clientSecret: 'YOUR_SECRET',
  authorizationId: 'AUTH_ID',
);

9. Update Order (Shipping/Tracking) #

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

Subscriptions API #

10. Create a Product #

final result = await paypal.createProduct(
  clientSecret: 'YOUR_SECRET',
  product: {
    'name': 'Premium Plan',
    'description': 'Access to all features',
    'type': 'SERVICE',
    'category': 'SOFTWARE',
  },
);

result.fold(
  (failure) => print('Error: ${failure.message}'),
  (product) => print('Product created: ${product['id']}'),
);

11. List Products #

final result = await paypal.listProducts(
  clientSecret: 'YOUR_SECRET',
  pageSize: 10,
  page: 1,
  totalRequired: true,
);

result.fold(
  (failure) => print('Error: ${failure.message}'),
  (data) {
    final products = data['products'] as List;
    print('Total: ${data['total_items']}, Found: ${products.length}');
  },
);

12. Get Product Details #

final result = await paypal.getProductDetails(
  clientSecret: 'YOUR_SECRET',
  productId: 'PROD-XXXX',
);

13. Update Product #

final result = await paypal.updateProduct(
  clientSecret: 'YOUR_SECRET',
  productId: 'PROD-XXXX',
  patchOperations: [
    {'op': 'replace', 'path': '/description', 'value': 'New description'},
  ],
);

14. Create a Billing Plan #

final result = await paypal.createPlan(
  clientSecret: 'YOUR_SECRET',
  plan: {
    'product_id': 'PROD-XXXX',
    'name': 'Monthly Plan',
    '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,
    },
  },
);

15. List Plans #

final result = await paypal.listPlans(
  clientSecret: 'YOUR_SECRET',
  productId: 'PROD-XXXX', // optional filter
  pageSize: 10,
);

16. Update Plan Pricing #

final result = await paypal.updatePlanPricing(
  clientSecret: 'YOUR_SECRET',
  planId: 'P-XXXX',
  pricingSchemes: [
    {
      'billing_cycle_sequence': 1,
      'pricing_scheme': {
        'fixed_price': {'value': '14.99', 'currency_code': 'USD'},
      },
    }
  ],
);

17. Create a Subscription #

final result = await paypal.createSubscription(
  clientSecret: 'YOUR_SECRET',
  subscription: {
    'plan_id': 'P-XXXX',
    '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',
    },
  },
);

18. List Subscriptions #

final result = await paypal.listSubscriptions(
  clientSecret: 'YOUR_SECRET',
  planIds: 'P-XXXX',
  statuses: 'ACTIVE',
  pageSize: 20,
);

19. Manage Subscription Lifecycle #

// Activate
await paypal.activateSubscription(
  clientSecret: 'YOUR_SECRET',
  subscriptionId: 'I-XXXX',
  reason: 'Reactivating after pause',
);

// Suspend
await paypal.suspendSubscription(
  clientSecret: 'YOUR_SECRET',
  subscriptionId: 'I-XXXX',
  reason: 'Customer requested pause',
);

// Cancel
await paypal.cancelSubscription(
  clientSecret: 'YOUR_SECRET',
  subscriptionId: 'I-XXXX',
  reason: 'Customer requested cancellation',
);

// Revise (change plan)
final revised = await paypal.reviseSubscription(
  clientSecret: 'YOUR_SECRET',
  subscriptionId: 'I-XXXX',
  revisionDetails: {'plan_id': 'P-NEW-PLAN'},
);

20. Capture Outstanding Payment #

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

21. List Subscription Transactions #

final result = await paypal.listSubscriptionTransactions(
  clientSecret: 'YOUR_SECRET',
  subscriptionId: 'I-XXXX',
  startTime: '2026-01-01T00:00:00Z',
  endTime: '2026-04-18T23:59:59Z',
);

result.fold(
  (failure) => print('Error: ${failure.message}'),
  (data) {
    final txns = data['transactions'] as List;
    for (final txn in txns) {
      print('${txn['id']}: ${txn['status']} — ${txn['amount_with_breakdown']}');
    }
  },
);

Using the Service Directly #

For advanced usage, you can use PaypalSubscriptionService or PaypalOrderService directly:

final service = PaypalSubscriptionService(
  config: PaypalConfig(
    clientId: 'YOUR_CLIENT_ID',
    environment: PaypalEnvironment.sandbox,
    returnUrl: 'com.example.myapp://paypalpay',
  ),
  clientSecret: 'YOUR_SECRET',
);

try {
  // Plan lifecycle methods only available via service
  await service.updatePlan('P-XXXX', patchOperations: [...]);
  await service.activatePlan('P-XXXX');
  await service.deactivatePlan('P-XXXX');
} finally {
  service.dispose();
}

Dependency Injection #

GetIt #

final getIt = GetIt.instance;

Future<void> configureDependencies() async {
  final paypal = FlutterPaypalPayment();
  await paypal.init(PaypalConfig(
    clientId: 'YOUR_CLIENT_ID',
    environment: PaypalEnvironment.sandbox,
    returnUrl: 'com.example.myapp://paypalpay',
  ));
  getIt.registerSingleton<FlutterPaypalPayment>(paypal);
}

Riverpod #

final paypalProvider = Provider<FlutterPaypalPayment>((ref) {
  throw UnimplementedError('Initialized in main');
});

// In main:
runApp(
  ProviderScope(
    overrides: [paypalProvider.overrideWithValue(paypal)],
    child: MyApp(),
  ),
);

Architecture #

lib/
├── paypal_checkout_flutter.dart       # Public exports
└── src/
    ├── flutter_paypal_payment_plugin.dart  # Public API (FlutterPaypalPayment)
    ├── domain/
    │   ├── entities/                 # PaypalConfig, PaymentRequest, PaymentCard, etc.
    │   └── repositories/            # Abstract contracts
    ├── data/
    │   ├── repositories/            # Implementation delegating to Pigeon
    │   ├── mappers/                 # Dart ↔ Pigeon message mappers
    │   └── services/                # PaypalOrderService, PaypalSubscriptionService
    └── generated/                   # Auto-generated Pigeon code

android/src/main/kotlin/
└── FlutterPaypalPaymentPlugin.kt    # Native implementation (PayPal Android SDK)

ios/Classes/
└── PaypalCheckoutFlutterPlugin.swift # Native implementation (PayPal iOS SDK)

Error Handling #

All methods return Either<Failure, Success>. Use .fold() to handle both cases:

result.fold(
  (failure) {
    // failure.code  — e.g. 'NOT_INITIALIZED', 'CAPTURE_ERROR'
    // failure.message — human-readable description
    print('${failure.code}: ${failure.message}');
  },
  (success) {
    // Handle success
  },
);

Error Code Reference #

Code When it occurs
NOT_INITIALIZED init() was not called before pay() or payWithCard()
AUTH_ERROR OAuth2 token request failed (bad credentials or network)
CREATE_ORDER_ERROR Order creation failed
CAPTURE_ERROR Order capture failed after buyer approval
GET_ORDER_ERROR getOrderDetails() failed
UPDATE_ORDER_ERROR updateOrder() PATCH failed
AUTHORIZE_ERROR authorizeOrder() failed (AUTHORIZE intent)
CAPTURE_AUTHORIZATION_ERROR captureAuthorization() failed
VOID_AUTHORIZATION_ERROR voidAuthorization() failed
REFUND_ERROR refundCapture() failed
SETUP_TOKEN_ERROR createSetupToken() failed (vaulting flow)
PAYMENT_TOKEN_ERROR createPaymentToken() failed (vaulting flow)
CREATE_PRODUCT_ERROR createProduct() failed (subscriptions)
CREATE_PLAN_ERROR createPlan() failed
GET_PLAN_ERROR getPlan() failed
UPDATE_PLAN_ERROR updatePlan() failed
LIST_PLANS_ERROR listPlans() failed
UPDATE_PRICING_ERROR updatePlanPricing() failed
CREATE_SUBSCRIPTION_ERROR createSubscription() failed
GET_SUBSCRIPTION_ERROR getSubscription() failed
SUBSCRIPTION_ACTION_ERROR suspendSubscription() / cancelSubscription() / activateSubscription() failed
CAPTURE_SUBSCRIPTION_ERROR captureSubscriptionPayment() failed
UPDATE_SUBSCRIPTION_ERROR updateSubscription() failed
LIST_SUBSCRIPTIONS_ERROR listSubscriptions() failed
LIST_TRANSACTIONS_ERROR listSubscriptionTransactions() failed
LIST_PRODUCTS_ERROR listProducts() failed
GET_PRODUCT_ERROR getProduct() failed
UPDATE_PRODUCT_ERROR updateProduct() failed
VALIDATION_ERROR Invalid input (e.g. malformed order ID)
UNKNOWN_ERROR Unexpected error not covered above

Support #

If this package helps you, consider supporting its development:

ko-fi

License #

BSD-3-Clause — See LICENSE for details.

0
likes
150
points
116
downloads

Documentation

API reference

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

BSD-3-Clause (license)

Dependencies

dartz, flutter, http

More

Packages that depend on paypal_checkout_flutter

Packages that implement paypal_checkout_flutter