Flutter SDK for Veem Global Payments.
Wraps Veem's Web SDK in a WebView and exposes a native Flutter API. The
Web SDK runs inside the WebView; Flutter widgets and an imperative
present() method are the public surface. Plugin updates ship from Veem's
CDN, and PCI scope stays with Veem.
| Plugin | v1 | Notes |
|---|---|---|
| Card | ✅ | This release. |
| Bank | ⏳ | Undetermined. |
| Payee | ⏳ | Undetermined. |
| Beneficial Ownership Info | ⏳ | Undetermined. |
| Plaid | ⏳ | Undetermined. Bank OAuth redirects in WebView need attention. |
| Identity Check | ⏳ | Undetermined. Requires camera permissions plumbing. |
This package is distributed via Git, not pub.dev. Add it to your app's
pubspec.yaml and pin to a release tag:
dependencies:
veem_flutter:
git:
url: https://github.com/bushaHQ/veem_flutter.git
ref: v0.1.0Always pin ref: to a tag. Pointing it at a branch (ref: main) means
every flutter pub get can silently pull new code.
-
Bump
version:in this package'spubspec.yaml. -
Update
CHANGELOG.md. -
Commit, then tag and push:
git tag v0.1.0 git push origin dev --tags
-
Consuming apps bump their
ref:to the new tag and runflutter pub get.
WebView requires platform configuration. See the
webview_flutter docs for the
current minimum versions.
- iOS: minimum deployment target 12.0. No additional Info.plist entries needed for the Card plugin in v1 (camera permissions arrive with Identity Check).
- Android:
minSdkVersion 21. Internet permission is included by default.
import 'package:veem_flutter/veem_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Veem.initialize(const VeemConfig(
environment: VeemEnvironment.sandbox,
clientId: 'your-veem-client-id',
));
runApp(const MyApp());
}Your backend calls Veem's
search customer by email
endpoint using your partner OAuth token and returns the resulting
accountId and sessionSecret to your app. Never embed your partner
token, partner secret, or any long-lived credential in the mobile binary.
Modal (imperative):
final result = await Veem.card.present(
context,
config: CardPluginConfig(
accountId: accountId,
sessionSecret: sessionSecret,
referenceId: 'order_$orderId',
preset: const CardPreset(amount: 500, currencyCode: 'USD'),
headerText: 'Add your card',
),
);
switch (result) {
case CardPluginCompleted(:final userInputs):
final fundingId = userInputs.paymentMethod.fundingMethod.id;
// Send fundingId to your backend; call Create Payment API with it.
case CardPluginExited():
// User cancelled.
case CardPluginErrored(:final error):
// Surface error.message to the user.
}Embedded widget:
VeemCardPlugin(
config: CardPluginConfig(...),
onCompleted: (event) { /* ... */ },
onExited: () { /* ... */ },
onErrored: (error) { /* ... */ },
)Style the plugin with a typed VeemStyle. The fastest path is to derive
from your Material theme:
CardPluginConfig(
// ...
style: VeemStyle.fromTheme(Theme.of(context)),
)Or build one explicitly:
CardPluginConfig(
// ...
style: VeemStyle(
typography: VeemTypography(
fontFamily: 'Roboto',
color: Color(0xFF1A1A1A),
fontSize: 14,
),
button: VeemButtonStyle(
backgroundColor: Color(0xFF0076F7),
color: Colors.white,
borderRadius: 8,
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 12),
),
),
)Colors take Flutter Colors (serialized as #RRGGBB, alpha dropped),
font weights take Flutter FontWeights (mapped to numeric CSS weights),
and padding takes EdgeInsets. Anything not yet typed can be passed via
VeemStyle(extra: {...}) and will be merged into the output map.
Note on fonts: fontFamily must resolve in the WebView's runtime —
system fonts or web-loaded fonts work, but custom fonts you bundle in
your Flutter app are NOT automatically available since the WebView runs
an isolated rendering context. If you need a brand font, host it as a
web font and reference it by name.
The full Veem style schema is documented at https://developer.veem.com/docs/card-plugin.
┌─────────────────────────────────────────────────┐
│ Merchant Flutter app │
│ ───────────────── │
│ Veem.initialize(VeemConfig) │
│ Veem.card.present(context, config) │
│ VeemCardPlugin(config: ...) │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ Bridge layer (Dart) │
│ ───────────────── │
│ VeemWebView — loads assets/web/index.html │
│ BridgeMessage — JSON envelope, both directions │
│ JavaScriptChannel('VeemHost') │
└──────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ WebView │
│ ───────────────── │
│ index.html (bundled asset) │
│ • injected config (env, clientId, etc.) │
│ • loads veem-web-sdk from unpkg.com │
│ • `new Veem.WebSDK({...})` mounts plugin │
│ • onComplete/onExit/onError → VeemHost │
└─────────────────────────────────────────────────┘
VeemConfig.webSdkVersion defaults to '0', which resolves to the latest
0.x release on unpkg. For production, pin to an exact version you've
tested:
const VeemConfig(
// ...
webSdkVersion: '0.x.y', // replace with the version you tested
)Otherwise a breaking change in the Web SDK can ship into your app silently the next time a user opens the plugin.
- Card plugin only available. Bank, Payee, BOI, Plaid, Identity Check coming in subsequent releases.
- No offline detection. The Web SDK loads from a CDN; the plugin won't
work without network, and the error surface for that case is generic
(
VeemErrorCode.networkError). - Web SDK exact init signature. This SDK assumes the Web SDK exposes
itself as
window.Veem.WebSDKand accepts the config shape documented on Veem's Card Plugin page. If Veem changes that shape, the bridge inassets/web/index.htmlis the place to adjust.
MIT