Figo Snap & Pay SDK: Integration Guide#
Figo Snap & Pay opens a camera screen, reads an invoice, receipt or account details, and returns the payment details as JSON:{
"bankCode": "058",
"accountNumber": "0123456789",
"amount": "12900.00",
"narration": "Website redesign",
"bankName": "GUARANTY TRUST BANK PLC",
"source": "local",
"confidence": 1.0,
"rawText": "…",
"error": null,
"modelUsed": true
}
Images are read on the device first. If the device can't read them confidently, Figo reads them instead (source: "remote").| Platform | Package |
|---|
| Android | ai.figolabs:figo-snap-and-pay |
| iOS | FigoSnapAndPay (CocoaPods) |
| React Native (0.77+, new architecture) | @figolabs/figo-snap-and-pay |
| Flutter | figo_snap_and_pay |
1. What you need#
License key (snp-…), issued by Figo.
Figo key (figoApiKey) from the Figo dashboard, for the same company as the license.
Devices: Android 8.0+, iOS 15+.
Optional: a hosted on-device model file (see section 7).
2. Install#
Camera and internet permissions are added for you.Add NSCameraUsageDescription to Info.plist.With Expo (development build, not Expo Go), add the plugin to app.json:{ "expo": { "plugins": [["@figolabs/figo-snap-and-pay", { "cameraPermission": "Scan invoices to pay them." }]] } }
Add NSCameraUsageDescription to ios/Runner/Info.plist, set platform :ios, '15.0' in the Podfile, and set minSdkVersion 26 on Android.
3. Initialize#
Call initialize once, for example after sign-in. It checks the license and returns who it is licensed to. If it fails, don't continue: show the error message.const license = await FigoSnapAndPay.initialize({ licenseKey, figoApiKey });
license is { companyName, expiryDate }, with expiryDate like 14-Nov-2026.| Option | Default | Description |
|---|
licenseKey | required | Your Snap & Pay license key. |
figoApiKey | required | Your Figo key. |
mode | auto | auto: device first, then Figo. localOnly: device only. remoteOnly: Figo only. |
minConfidence | 0.7 | Device results below this are sent to Figo (auto mode). |
modelUrl | – | URL of the on-device model file (section 7). |
modelSha256 | – | Checksum of the model file. |
wifiOnlyDownload | true | Download the model only on Wi-Fi. |
4. Scan#
scan() opens the camera screen and returns the result.Java: use initializeAsync(...) and scanAsync(...), which take a callback.SwiftUI: FigoSnapCameraScreen { result in … } in a .fullScreenCover.try {
const result = await FigoSnapAndPay.scan({ primaryColor: '#FF6B00' });
} catch (e) {
if (e instanceof FigoSnapError && e.code === 'CANCELLED') return;
}
| Scan option | Default | Description |
|---|
title | Scan to pay | Screen title. |
primaryColor | blue | Brand color, #RRGGBB. |
allowGallery | true | Allow picking a photo from the gallery. |
confirmBeforeExtract | true | Show Retake / Use photo before reading. |
autoCapture | true | Take the photo once an account number is in view. |
Embedded camera#
To place the camera inside your own screen:| Platform | Component |
|---|
| Android | FigoSnapCameraView(context, options) |
| iOS | FigoSnapCameraView(options:) |
| React Native | <FigoSnapCamera style={{ flex: 1 }} onResult={…} onError={…} /> |
| Flutter | FigoSnapCamera(onResult: …, onError: …) |
5. Read an existing image#
| Platform | Base64 | URL |
|---|
| Kotlin | extractBankAccount(base64) | extractBankAccountFromUrl(url) |
| Swift | extractBankAccount(base64:) | extractBankAccount(url:) |
| React Native | extractFromBase64(base64) | extractFromUrl(url) |
| Flutter | extractFromBase64(base64) / extractFromBytes(bytes) | extractFromUrl(url) |
Supported: JPEG, PNG, GIF and WebP, up to 10 MB.
6. Result#
| Field | Description |
|---|
bankCode | Bank code, or null. |
bankName | Bank name for bankCode. |
accountNumber | 10-digit account number, or null. |
amount | Amount to pay, digits only (e.g. "12900.00"), or null. |
narration | Short payment description, or null. |
source | local (read on the device) or remote (read by Figo). |
confidence | 0–1. |
modelUsed | true if the on-device model's answer was used. |
rawText | Text read on the device. |
error | Set only when Figo couldn't be reached and the device result is returned instead. |
Always let the user confirm the details before paying.
7. On-device model (optional)#
The on-device model improves on-device reading and enables prompt(). Without it, the SDK still works, but more images are read by Figo.1.
Host a Gemma 3 1B (instruction-tuned, int4) MediaPipe .task file with a 4096-token context, about 550 MB.
2.
Pass its URL as modelUrl, and optionally its SHA-256 as modelSha256.
3.
Download it once, for example from a settings screen:
const status = await FigoSnapAndPay.modelStatus(); // notConfigured | notDownloaded | downloading | ready | unsupported
await FigoSnapAndPay.prepareModel((p) => setProgress(p)); // 0..1
The model needs about 4 GB of RAM. On smaller devices, modelStatus() is unsupported.Prompt#
const { text } = await FigoSnapAndPay.prompt('Summarise this invoice in one line: …', { system: 'Be brief.' });
prompt() runs only on the device. It fails with MODEL_UNAVAILABLE if no model is ready.
8. Licensing#
When it's checked: at initialize. A valid result is kept in memory for 24 hours.
Expired or invalid: every call fails, and the camera screen shows the message.
Offline: if the license hasn't been checked in the last 24 hours, calls fail until the device is back online.
Footer: the camera screen shows "Licensed to {companyName}".
9. Errors#
| Code | Meaning |
|---|
LICENSE_INVALID | Unknown or disabled license, or a license for a different company from the Figo key. |
LICENSE_EXPIRED | The license has expired. |
CONFIG | Missing or invalid initialize options. |
NOT_INITIALIZED | initialize was not called. |
CANCELLED | The user closed the camera. |
CAMERA_PERMISSION_DENIED | Camera access was denied. |
INVALID_IMAGE / IMAGE_TOO_LARGE | Unsupported image, or over 10 MB. |
NO_DATA | No payment details found. |
MODEL_UNAVAILABLE | The on-device model can't run. |
AUTH | Invalid or expired Figo key, or not enough credits. |
PLAN_LIMIT | The Figo plan doesn't include this feature. |
RATE_LIMITED | Too many requests. Retry later. |
NETWORK | No connection. |
SERVER | Unexpected error. Retry. |
Security: both keys ship inside your app. Use keys made for this SDK, and rotate them if they leak.
Modified at 2026-11-14 19:52:08