Skip to content
SDK preview. Packages are not publicly published yet — use REST / cURL, or the local development artifacts.

Flutter

Accept PayTaka payments in a Flutter app using your own backend, url_launcher and a deep link.

No Flutter plugin is published for PayTaka yet — but the integration is fully supported today. It uses the same secure pattern as Android and iOS, with standard packages, the checkout_url your backend creates, the system browser, and a deep link.

Text
Flutter app ──▶ your small backend ──(PayTaka secret key)──▶ PayTaka
     ▲                  │
     └─ checkout_url ───┘
launchUrl(checkout_url) ──▶ customer pays ──▶ myapp://payment-return?… ──▶ app
app ──▶ your backend ──▶ "is my order paid?"

The PayTaka secret key stays on your backend. Never put it in a Flutter or Dart bundle — a compiled app can be decompiled. No backend yet? See I only have an app.

The flow#

  1. The app sends an order id to your backend; the backend decides the amount and returns checkout_url.
  2. Open it with url_launcher (LaunchMode.externalApplication).
  3. Your backend set the payment's return_url to your app's deep link. Register it as an Android intent filter / App Link and an iOS URL scheme / Universal Link, and listen with app_links.
  4. When the link arrives, ask your backend for the order's status.
pay_button.dart · Dart
// Flutter: the app never holds a PayTaka secret key. It sends an ORDER ID to YOUR backend (the server
// decides the amount — see examples/mobile-backend), opens the checkout_url it returns with
// url_launcher, and asks YOUR backend for the order's real status when the customer returns through
// your deep link (app_links).
//
// pubspec.yaml: url_launcher, http, app_links
import 'dart:convert';

import 'package:app_links/app_links.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';

const backend = 'https://your-backend.example.com';
const orderId = 'order-1001'; // the order being paid

class PayButton extends StatefulWidget {
  const PayButton({super.key});

  @override
  State<PayButton> createState() => _PayButtonState();
}

class _PayButtonState extends State<PayButton> {
  String message = 'Ready';

  @override
  void initState() {
    super.initState();
    // Return link: myapp://payment-return?paytaka_payment_id=…&paytaka_status=PAID
    AppLinks().uriLinkStream.listen((uri) async {
      if (!uri.queryParameters.containsKey('paytaka_status')) return;
      // paytaka_status is only a HINT — never fulfil from it. Refresh the order from YOUR backend.
      setState(() => message = 'Checking your payment…');
      final response = await http.get(Uri.parse('$backend/orders/$orderId/status'));
      setState(() => message = 'Order status: ${jsonDecode(response.body)['status']}');
    });
  }

  Future<void> pay() async {
    final response = await http.post(Uri.parse('$backend/orders/$orderId/pay'));
    final checkoutUrl = jsonDecode(response.body)['checkout_url'] as String;
    await launchUrl(Uri.parse(checkoutUrl), mode: LaunchMode.externalApplication);
  }

  @override
  Widget build(BuildContext context) => Column(children: [
        ElevatedButton(onPressed: pay, child: const Text('Pay for $orderId')),
        Text(message),
      ]);
}