waffy_sdk_flutter 0.6.0
waffy_sdk_flutter: ^0.6.0 copied to clipboard
Official Waffy payments SDK for Flutter. Embed the Waffy checkout in your app and get success or failure callbacks.
waffy_sdk_flutter #
waffy_sdk_flutter is a small Flutter SDK that embeds the Waffy checkout flow in a WebView.
You pass in a Waffy payment URL and one way to authenticate the customer (a payment ticket, a login hint or a user token), and the SDK:
- Appends the authentication value to the URL as a query parameter.
- Loads the checkout in a
WebView. - Listens for redirects that indicate payment success or failure.
- Exposes simple callbacks so your app can react to the result.
Features #
- ✅ Simple
WaffyPaymentWebViewwidget to start a payment flow. - ✅ Supports payment tickets (recommended), login hints and the legacy user token.
- ✅ Notifies you when:
- The payment succeeds or fails.
- The payment flow completes with a
statusand optionalmessage. - The underlying
WebViewURL changes.
- ✅ Uses
webview_flutterunder the hood.
Getting started #
1. Add dependency #
flutter pub add waffy_sdk_flutter
Or add it manually to your app's pubspec.yaml:
dependencies:
waffy_sdk_flutter: ^0.6.0
2. Platform setup #
This package uses webview_flutter.
Follow the platform-specific setup in its documentation if you have not already configured WebView for your Flutter app (e.g. iOS minimum version, Android WebView requirements).
Usage #
Basic example #
The main entry point is the WaffyPaymentWebView widget.
paymentUrl: The Waffy checkout URL you receive from your backend.ticket: A payment ticket your backend requested right before opening the checkout. See Authentication for the other options.onPaymentComplete: Called once when the flow finishes (success or failure).onPaymentSuccess: Convenience callback when the result is successful.onPaymentFailure: Convenience callback when the result is failed, with a message.onUrlChange: Called for every URL change inside theWebView.
import 'package:flutter/material.dart';
import 'package:waffy_sdk_flutter/waffy_sdk_flutter.dart';
class WaffyCheckoutPage extends StatelessWidget {
const WaffyCheckoutPage({
super.key,
required this.paymentUrl,
required this.ticket,
});
final String paymentUrl;
final String ticket;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Waffy Checkout'),
),
body: WaffyPaymentWebView.ticket(
paymentUrl: paymentUrl,
ticket: ticket,
onPaymentComplete: (status, message) {
switch (status) {
case WaffyPaymentStatus.success:
// Handle success (e.g. navigate, show success UI).
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment success: $message')),
);
break;
case WaffyPaymentStatus.failed:
// Handle failure (e.g. show error, allow retry).
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Payment failed: $message')),
);
break;
}
},
onUrlChange: (url) {
// Optional: inspect URL changes for analytics or debugging.
debugPrint('Waffy WebView URL changed: $url');
},
),
);
}
}
Authentication #
Pass exactly one of ticket, hint or userToken. The SDK appends it to the payment URL for you.
| Parameter | Appended to the payment URL as | Use it when |
|---|---|---|
ticket |
ticket |
Recommended. You have a payment ticket for this customer and payment. |
hint |
login_hint |
You want the customer to sign in on the payment page, and you know their phone number. |
userToken |
userTokenUrl |
You already integrated with the legacy customer token. It keeps working unchanged. |
Use the named constructor for your option. Each one accepts only its own value, so passing more than one is a compile-time error:
// Payment ticket (recommended)
WaffyPaymentWebView.ticket(paymentUrl: paymentUrl, ticket: ticket);
// Login hint: the customer's phone number, e.g. '+9665XXXXXXXX'
WaffyPaymentWebView.hint(paymentUrl: paymentUrl, hint: customerPhone);
// Legacy user token
WaffyPaymentWebView.userToken(paymentUrl: paymentUrl, userToken: userToken);
The default WaffyPaymentWebView(...) constructor also accepts all three, for existing integrations.
Getting a payment ticket #
Request the ticket from your backend, never from the app, because the request uses your client_secret. Then send the ticket to the app and pass it to the ticket parameter.
curl -X POST "$WAFFY_ID_URL/realms/waffy/protocol/openid-connect/token" \
-u "$CLIENT_ID:$CLIENT_SECRET" \
--data-urlencode "grant_type=urn:waffy:params:oauth:grant-type:customer-token-exchange" \
--data-urlencode "login_hint=$CUSTOMER_PHONE" \
--data-urlencode "scope=payment:$PAYMENT_REF"
# => { "ticket": "a1b2c3...", "expiresIn": 300 }
PAYMENT_REFis the contract's short ID: the last part of the payment URL path (.../external/6VzpzZlR?...gives6VzpzZlR).- A ticket expires after 5 minutes and works only once. Request a new one each time you open the payment page.
- If the customer hasn't approved your organization yet, the payment page asks them to sign in instead.
See the Waffy authentication guide for the full flow.
Invalid authentication #
With the default constructor, passing none of the three parameters, or more than one:
- fails an
assertwhere the widget is created, in debug mode (and is an analyzer error forconstwidgets); - throws a
WaffyAuthErrorwhen the widget is first built, in every build mode. Empty strings count as not provided here.
Upgrading from 0.1.x #
No code changes are needed. Apps that pass userToken get exactly the same payment URL as before. To move to tickets, replace userToken: ... with ticket: ....
How the payment result is detected #
Internally, WaffyPaymentWebView:
- Takes your
paymentUrland appends the authentication query parameter (ticket,login_hintoruserTokenUrl). - Loads that URL in a
WebView. - Listens to URL changes:
- If the URL contains
status=SUCCESS, it:- Calls
onPaymentComplete(WaffyPaymentStatus.success, message). - Calls
onPaymentSuccess()if provided.
- Calls
- If the URL contains
status=FAILED, it:- Calls
onPaymentComplete(WaffyPaymentStatus.failed, message). - Calls
onPaymentFailure(message)if provided.
- Calls
messageis taken from themessagequery parameter of the URL, if present.
- If the URL contains
Your backend / Waffy checkout implementation is responsible for redirecting
to a URL with status=SUCCESS or status=FAILED (and optional message).
API reference #
WaffyPaymentWebView #
Constructor parameters:
paymentUrl(required): Base payment/checkout URL from your backend/Waffy.ticket,hintoruserToken(exactly one required): How the customer is authenticated on the payment page. See Authentication.ticket:String?– one-time payment ticket; added asticket.hint:String?– the customer's phone number; added aslogin_hint.userToken:String?– legacy customer token; added asuserTokenUrl.
onPaymentSuccess:void Function()?– called when the payment succeeds.onPaymentFailure:void Function(String message)?– called when the payment fails.onPaymentComplete:void Function(WaffyPaymentStatus status, String message)?– called once when the payment flow completes.onUrlChange:void Function(String? url)?– called on any URL change inside theWebView.webViewController: OptionalWebViewControllerif you want to provide your own.
WaffyPaymentStatus #
enum WaffyPaymentStatus {
success,
failed,
}
WaffyAuthError #
Thrown when none, or more than one, of ticket, hint and userToken is provided. message describes the problem.
Support #
For integration help or to report an issue, contact the Waffy team via waffyapp.com.