rootfi_softpos

Official RootFi SoftPOS SDK for Flutter — turn a merchant's Android phone into a contactless card terminal.

The merchant taps a customer's debit/credit card on the back of their device; RootFi captures the EMV cryptogram via the underlying terminal SDK, settles upstream, and credits the merchant's RootFi virtual account.

Security model

Unlike ad-hoc integrations that bake terminal credentials into the APK as const strings:

  • You only ever pass your RootFi API key. You never touch terminalId, uniqueId, or clientId. They are not in your APK, not in your repo, and not in your application code.
  • On initialize(), the SDK's native Kotlin layer attests the device with Google Play Integrity, then asks the RootFi backend for a short-lived (~10 min), device-bound bundle.
  • Credentials reach this SDK's Dart frame only to seed the underlying terminal SDK on the same call — they are never assigned to instance fields, getters, or any cache.
  • Every charge is pre-registered with POST /v1/softpos/charge so abuse of a leaked session is detectable, rate-limited, and revocable from the server side. Rotate the RootFi session-signing key and every live SDK session dies at its next charge.

Honest threat-model note

A determined attacker with a rooted device + Frida can inspect the SDK Dart frame that briefly holds the credentials. The mitigations for that are server-side: Play Integrity gates the session, the session token is short-lived and device-bound, and every tap is audited. To remove the brief Dart transit entirely would require a public Kotlin entry point on the underlying terminal SDK — closed-source today.

Quick start

dependencies:
  rootfi_softpos: ^0.1.0
import 'package:rootfi_softpos/rootfi_softpos.dart';

final pos = RootfiSoftPos(apiKey: 'rf_live_xxx')
  ..onStatus  = (s) => print('status: $s')
  ..onSuccess = (r) => print('paid ₦${r.amount} rrn=${r.rrn}')
  ..onFailure = (e) => print('failed: $e');

await pos.initialize();
final result = await pos.charge(amountNaira: 1500);

Use your live RootFi key (rf_live_…). SoftPOS is live-only — there is no sandbox terminal upstream, and the RootFi backend rejects rf_test_… keys at /v1/softpos/session with HTTP 403. Every tap is a real card transaction.

Settlement

When the tap settles upstream, RootFi book-transfers the funds from RootFi's master account to your virtual account and fires a softpos.settled webhook to your registered URL. See /docs for the webhook payload shape.

Android setup

Zero manual AndroidManifest.xml edits — the package merges the required NFC, INTERNET, and VIBRATE permissions into your host app automatically.

Your app needs compileSdk 34 (or higher) and minSdk 21 (or higher), and the device needs Google Play Services with a Play Integrity-licensed copy of your app.

Platforms

Android only. iOS does not support contactless card acceptance via the underlying terminal SDK; for iOS use the phone-to-phone rootfi_tap_to_pay flow.

Libraries

rootfi_softpos
RootFi SoftPOS SDK.