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.
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#
- The app sends an order id to your backend; the backend decides the amount and returns
checkout_url. - Open it with
url_launcher(LaunchMode.externalApplication). - Your backend set the payment's
return_urlto your app's deep link. Register it as an Android intent filter / App Link and an iOS URL scheme / Universal Link, and listen withapp_links. - When the link arrives, ask your backend for the order's status.
// 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),
]);
}