With Flexa SDK, you can quickly and easily add new layers of functionality to your wallet app.
In the current release, Flexa offers a privacy-focused payments experience for in-person and online spending anywhere Flexa is accepted (Flexa Spend), along with a simple scanner module for parsing QR code–formatted payment requests (Flexa Scan).
Module | Description |
---|---|
Flexa | Core functionality required by all other modules |
FlexaScan | Camera-based parsing of QR codes for payments and more |
FlexaSpend | Instant retail payments, powered by Flexa |
Flexa SDK is supported via CocoaPods and Swift Package Manager.
The simplest way to install Flexa is by adding the Swift package directly from https://github.com/flexa/flexa-ios.git
Alternatively, you can directly update Package.swift with this dependency:
dependencies: [
.package(url: "https://github.com/flexa/flexa-ios.git", from: "0.0.1")
]
And then add the Flexa
dependency to the relevant targets:
.target(
name: ...,
dependencies: [
.product(name: "Flexa", package: "flexa-ios"),
]
)
Add the following to your Podfile:
pod 'Flexa'
Flexa SDK for iOS requires Xcode 15 or later and is compatible with apps that target iOS 15 or above.
If you choose to enable Flexa Scan, you must also request permission to the Camera by providing Privacy - Camera Usage Description
in Info.plist
. We recommend using a simple, one-sentence description, such as:
“Allow camera access so that you can scan barcodes for payments.”
Flexa SDK requires your app to embed a valid publishable key, which will enable it to communicate with Flexa in order to request details of currently supported assets, the equivalent US dollar (or other local currency) balances for your user’s assets, and payment session details whenever a payment is initiated.
To obtain your publishable key, please contact a member of the Flexa team.
- Import the Flexa module in your main application file:
import Flexa
- Gather the current balances of all assets available in your user’s wallet accounts:
struct FXAvailableAsset {
let accentColor: UIColor?
let assetId: String
let balance: Decimal
let balanceAvailable: Decimal?
let displayName: String?
let icon: UIImage?
let logoImageUrl: URL?
let symbol: String?
}
struct FXAssetAccount {
let assetAccountHash: String
let displayName: String
let icon: UIImage?
let availableAssets: [FXAvailableAsset]
}
- Initialize Flexa, typically in your application initializer:
@main
struct YourApp: App {
init() {
Flexa.initialize(
FXClient(
publishableKey: "{YOUR_PUBLISHABLE_KEY}",
assetAccounts: [FXAssetAccount],
theme: .default
)
)
}
var body: some Scene {
...
}
- Import the Flexa module in your
UIApplicationDelegate
:
import Flexa
- Gather the current balances of all assets available in your user’s wallet accounts:
struct FXAvailableAsset {
let accentColor: UIColor?
let assetId: String
let balance: Decimal
let balanceAvailable: Decimal?
let displayName: String?
let icon: UIImage
let symbol: String?
}
struct FXAssetAccount {
let assetAccountHash: String
let displayName: String
let icon: UIImage?
let availableAssets: [FXAvailableAsset]
}
- Initialize Flexa, typically in your app's
application:didFinishLaunchingWithOptions
:
Flexa.initialize(FXClient(
publishableKey: "{YOUR_PUBLISHABLE_KEY}",
assetAccounts: [FXAssetAccount],
theme: .default)
)
Flexa works on many regions, but a few are unsupported. After the SDK is initialized developers can query the boolean Flexa.canSpend
, if it's false
it means the current region where the app is running is unsupported. In the case Flexa.canSpend
is false
the SDK won't open when calling the open()
method.
Currently Flexa allows to use universal links to speed up the sign in/sign up process
For Universal Link handling the SDK provides the processUniversalLink
method:
static func processUniversalLink(url: UR) -> Bool
The url
parameter should contain the universal link received, and the method will return true
if the SDK can handle the Universal Link and false
otherwise (and parent apps could choose if they process the link in a different way)
Configuration In order to allow Universal Links the parent app should be configured properly and should include the next associated domains:
applinks:{YOUR_APP_NAME}.flexa.link
On your AppDelegate
implement:
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard let url = userActivity.webpageURL else {
return false
}
return Flexa.processUniversalLink(url: url)
}
@main
struct SPMApp: App {
init() {
Flexa.initialize(
...
)
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { url in
Flexa.processUniversalLink(url: url)
}
}
}
}
// Open Flexa
Flexa.sections([.spend])
.assetAccounts(assetAccounts) // Optional
.selectedAsset(selectedAssetAccountHash, selectedAssetId) // Optional
.onTransactionRequest(onTransactionRequest)
.open()
// Callback handler
func onTransactionRequest(result: Result<FXTransaction, Error>) {
debugPrint(result)
switch result {
case .success(let transaction):
do {
// Sign and send the transaction
// Once the transaction is sent the parent application can pass the signature (String) to Flexa through Flexa.transactionSent
let signature = try ...
Flexa.transactionSent(commerceSessionId: transaction.commerceSessionId, signature: signature)
} catch let error {
// An error happened while singning/sending the transaction. Calling Flexa.transactionFailed instructs the SDK to cancel the ongoing commerce session.
Flexa.transactionFailed(commerceSessionId: transaction.commerceSessionId)
}
default:
break
}
}
The FXTransaction
struct:
/// Represents a Transaction to be made
///
/// Flexa will pass back a Transaction object to the parent application in order to be reviewed, signed and sent
public struct FXTransaction {
/// The Commerce Sessions identifier associated to the transaction
public let commerceSessionId: String
/// Amount of the transaction
public let amount: String
/// The assetAccountHash the funds will be taken from
public let assetAccountHash: String
/// The asset that must be used
public let assetId: String
/// Destination address of the transaction
public let destinationAddress: String
/// Calculated fee amount
public let feeAmount: String
/// The fee assetId, ETH for Ethereum, BTC for bitcoin network etc
public let feeAssetId: String
/// Fee price. Gas price on Ethereum, or the sats/vByte fee on Bitcoin
public let feePrice: String
/// Priority fee amount (Ethereum only)
public let feePriorityPrice: String?
/// Gas limit (Ethereum only)
public let size: String?
// Brand'fields
public let brandLogo, brandName, brandColor: String?
}
A builder pattern is used to configure and open Flexa:
sections
: allows you to specify the different Components to be displayed.assetAccounts
: sets the user's asset accountsselectedAsset
: selects a default app account's asset to be used on future transactionsonTransactionRequest
: is called when Flexa has all the information about a transaction and needs the parent application to send it. In this callback parent applications should do any validation and send the transaction. Once the transaction is sent the parent application can pass the transaction's signature to Flexa throughFlexa.transactionSent
.open
: opens Flexa's main screen
Flexa will never attempt to access your users’ private keys, wallet addresses, a history of any actions taken in-app, or other sensitive wallet details. There is no method that enables you to provide any of this information to Flexa SDK, and Flexa SDK does not automatically extract any of this information from your app.
In order to enable payments for your users, federal regulations require Flexa to collect some personal information. This information typically consists of a user’s full name and date of birth. For higher-value payments, it can also include a photo ID document and photograph. This information is used only for verification purposes, and Flexa will never share this information with you or with any of the business your users pay.
Please note that making any modifications to your app or any of Flexa’s code with the intent to gather, retain, or otherwise access this personal information is expressly prohibited by the Flexa Developer Agreement, and will result in a permanent ban from using Flexa software for your business and any related individuals.
We welcome and appreciate contributions to Flexa SDK from the open source community.
- For larger changes, please open an issue describing your objectives so that we can coordinate efforts.
- Or, if you would like to make a minor edit (such as a single-line modification or to fix a typo), please feel free to open a pull request with your changes and we will review it promptly.
Flexa SDK for iOS is available under the MIT License.