The zbd_ramp package provides a native Flutter widget for integrating ZBD Ramp into your iOS, Android, and Web applications.
Features
Flutter Optimized Built specifically for Flutter with native WebView integration
Cross-Platform Works seamlessly on iOS, Android, and Web
Type Safe Full Dart type safety with comprehensive type definitions
Real-Time Events PostMessage communication for error handling, logging, and step tracking
Installation
Add the package to your pubspec.yaml:
dependencies :
zbd_ramp : ^1.0.0
http : ^1.1.0
Then run:
Quick Start
1. Create Session Token
First, initialize a ramp session from your backend or directly in your Flutter app:
import 'package:zbd_ramp/zbd_ramp.dart' ;
final response = await initRampSession ( InitRampSessionConfig (
apikey : 'your-zbd-api-key' ,
email : 'user@example.com' ,
destination : 'lightning-address@zbd.gg' ,
quoteCurrency : QuoteCurrency . USD ,
baseCurrency : BaseCurrency . BTC ,
webhookUrl : 'https://your-webhook-url.com' ,
referenceId : 'order-123' ,
metadata : { 'userId' : '456' , 'plan' : 'premium' },
));
if (response.success) {
final sessionToken = response.data.sessionToken;
// Use sessionToken with ZBDRampWidget
} else {
print ( 'Failed to create session: ${ response . error } ' );
}
import 'package:zbd_ramp/zbd_ramp.dart' ;
final response = await initRampSession ( InitRampSessionConfig (
apikey : 'your-zbd-api-key' ,
accessToken : 'user-access-token' ,
destination : 'lightning-address@zbd.gg' ,
quoteCurrency : QuoteCurrency . USD ,
baseCurrency : BaseCurrency . BTC ,
webhookUrl : 'https://your-webhook-url.com' ,
));
if (response.success) {
final sessionToken = response.data.sessionToken;
// Use sessionToken with ZBDRampWidget
}
Add the widget to your Flutter app:
import 'package:flutter/material.dart' ;
import 'package:zbd_ramp/zbd_ramp.dart' ;
class PaymentScreen extends StatelessWidget {
final String sessionToken;
const PaymentScreen ({ Key ? key, required this .sessionToken}) : super (key : key);
@override
Widget build ( BuildContext context) {
return Scaffold (
appBar : AppBar (title : Text ( 'Buy Bitcoin' )),
body : ZBDRampWidget (
config : RampConfig (sessionToken : sessionToken),
callbacks : RampCallbacks (
onSuccess : (data) {
print ( 'Payment successful: $ data ' );
// Handle successful payment
},
onError : (error) {
print ( 'Payment error: ${ error . message } ' );
// Handle error
},
onStepChange : (step) {
print ( 'Current step: $ step ' );
// Track user progress
},
),
height : 600 ,
),
);
}
}
API Reference
initRampSession()
Creates a new session token for the ZBD Ramp widget.
Parameters
class InitRampSessionConfig {
final String apikey; // Required: Your ZBD API key
final String ? email; // Email authentication
final String ? accessToken; // Access token authentication
final String destination; // Required: Lightning address or username
final QuoteCurrency quoteCurrency; // Required: Quote currency (USD)
final BaseCurrency baseCurrency; // Required: Base currency (BTC)
final String ? webhookUrl; // Optional: Webhook URL
final String ? referenceId; // Optional: Your reference ID
final Map < String , dynamic > ? metadata; // Optional: Additional metadata
}
Either email OR accessToken must be provided for authentication.
Returns
class InitRampSessionResponse {
final InitRampSessionData data;
final String ? error;
final bool success;
final String message;
}
class InitRampSessionData {
final String sessionToken; // Session token for widget
final String expiresAt; // Token expiration time
final String widgetUrl; // Direct widget URL
}
refreshAccessToken()
Refreshes an expired access token using a refresh token.
Token Lifecycle:
Access tokens expire after 30 days
Refresh tokens expire after 90 days
Both tokens are received via webhook after user completes OTP login with email
Parameters
class RefreshAccessTokenConfig {
final String apikey; // Required: Your ZBD API key
final String accessTokenId; // Required: ID of access token to refresh
final String refreshToken; // Required: Refresh token
}
Returns
class RefreshAccessTokenResponse {
final RefreshAccessTokenData data;
final String ? error;
final bool success;
final String message;
}
class RefreshAccessTokenData {
final String accessTokenId;
final String accessToken; // New access token
final String refreshToken; // New refresh token
final String accessTokenExpiresAt;
final String refreshTokenExpiresAt;
}
Example
try {
final response = await refreshAccessToken ( RefreshAccessTokenConfig (
apikey : 'your-zbd-api-key' ,
accessTokenId : '7b585ffa-9473-43ca-ba1d-56e9e7e2263b' ,
refreshToken : 'user-refresh-token' ,
));
if (response.success) {
final newAccessToken = response.data.accessToken;
final newRefreshToken = response.data.refreshToken;
// Store the new tokens securely
}
} catch (error) {
print ( 'Token refresh error: $ error ' );
}
Main Flutter widget that renders the ZBD Ramp interface.
Constructor
ZBDRampWidget ({
Key ? key,
required RampConfig config,
required RampCallbacks callbacks,
double ? width,
double ? height,
})
RampConfig
Configuration for the widget:
class RampConfig {
final String sessionToken; // Required: Session token
final String ? secret; // Optional: Widget secret
}
RampCallbacks
Event handlers for widget lifecycle:
class RampCallbacks {
final OnSuccessCallback ? onSuccess; // Payment successful
final OnErrorCallback ? onError; // Error occurred
final OnStepChangeCallback ? onStepChange; // User navigated to new step
final OnLogCallback ? onLog; // Debug/info logging
final OnReadyCallback ? onReady; // Widget fully loaded
final OnCloseCallback ? onClose; // User closed widget
}
Complete Example
Hereβs a full implementation with all callbacks:
import 'package:flutter/material.dart' ;
import 'package:zbd_ramp/zbd_ramp.dart' ;
class BuyBitcoinScreen extends StatefulWidget {
@override
_BuyBitcoinScreenState createState () => _BuyBitcoinScreenState ();
}
class _BuyBitcoinScreenState extends State < BuyBitcoinScreen > {
String ? sessionToken;
bool isLoading = true ;
String ? error;
@override
void initState () {
super . initState ();
_createSession ();
}
Future < void > _createSession () async {
try {
final response = await initRampSession ( InitRampSessionConfig (
apikey : 'your-zbd-api-key' ,
email : 'user@example.com' ,
destination : 'lightning@zbd.gg' ,
quoteCurrency : QuoteCurrency . USD ,
baseCurrency : BaseCurrency . BTC ,
webhookUrl : 'https://your-webhook.com' ,
referenceId : 'user_123' ,
));
if (response.success) {
setState (() {
sessionToken = response.data.sessionToken;
isLoading = false ;
});
} else {
setState (() {
error = response.error;
isLoading = false ;
});
}
} catch (e) {
setState (() {
error = e. toString ();
isLoading = false ;
});
}
}
@override
Widget build ( BuildContext context) {
return Scaffold (
appBar : AppBar (title : Text ( 'Buy Bitcoin' )),
body : isLoading
? Center (child : CircularProgressIndicator ())
: error != null
? Center (child : Text ( 'Error: $ error ' ))
: ZBDRampWidget (
config : RampConfig (sessionToken : sessionToken ! ),
callbacks : RampCallbacks (
onSuccess : (data) {
print ( 'β
Payment successful: $ data ' );
Navigator . of (context). pop ();
ScaffoldMessenger . of (context). showSnackBar (
SnackBar (content : Text ( 'Payment successful!' )),
);
},
onError : (error) {
print ( 'β Error: ${ error . message } ' );
ScaffoldMessenger . of (context). showSnackBar (
SnackBar (
content : Text ( 'Error: ${ error . message } ' ),
backgroundColor : Colors .red,
),
);
},
onStepChange : (step) {
print ( 'π Step changed: $ step ' );
},
onReady : () {
print ( 'β
Widget ready' );
},
onClose : () {
print ( 'π Widget closed' );
Navigator . of (context). pop ();
},
onLog : (log) {
print ( 'π Log: $ log ' );
},
),
height : 600 ,
),
);
}
}
Error Handling
Handle errors gracefully in your application:
void _handleError ( RampError error) {
// Error structure: { code: string, message: string, details?: any }
print ( 'Error Code: ${ error . code } ' );
print ( 'Error Message: ${ error . message } ' );
if (error.details != null ) {
print ( 'Error Details: ${ error . details } ' );
}
// Show user-friendly message
showDialog (
context : context,
builder : (context) => AlertDialog (
title : Text ( 'Payment Error' ),
content : Text (error.message),
actions : [
TextButton (
onPressed : () => Navigator . pop (context),
child : Text ( 'OK' ),
),
],
),
);
}
iOS Configuration
Add the following to your ios/Runner/Info.plist:
< key > NSAppTransportSecurity </ key >
< dict >
< key > NSAllowsArbitraryLoads </ key >
< true />
</ dict >
< key > NSCameraUsageDescription </ key >
< string > Camera access is required for KYC verification </ string >
Android Configuration
Add permissions to your android/app/src/main/AndroidManifest.xml:
< uses-permission android:name = "android.permission.INTERNET" />
< uses-permission android:name = "android.permission.CAMERA" />
< uses-permission android:name = "android.permission.RECORD_AUDIO" />
< uses-permission android:name = "android.permission.MODIFY_AUDIO_SETTINGS" />
< uses-permission android:name = "android.permission.VIDEO_CAPTURE" />
< uses-permission android:name = "android.permission.AUDIO_CAPTURE" />
< uses-permission android:name = "android.permission.ACCESS_NETWORK_STATE" />
Try the Example App
The quickest way to see the SDK in action:
Clone the Repository
git clone https://github.com/zbdpay/ramp-flutter.git
cd ramp-flutter/example
Test with Your Credentials
Enter your ZBD API Key
Fill in email and Lightning destination
Tap βCreate Session & Load Rampβ
Resources
Package on pub.dev View the official Flutter package
GitHub Repository View source code and example app
API Reference Complete API documentation
Webhook Events Handle webhook notifications
Other SDKs
TypeScript
React
React Native
Support
Need help? Create an issue on GitHub or reach out to our support team .