fam_sdk 1.1.1
fam_sdk: ^1.1.1 copied to clipboard
Official Flutter/Dart SDK for FAM API - Type-safe payment and subscription integrations with zero third-party dependencies. Production-ready with automatic retries, comprehensive error handling, and w [...]
FAM Flutter SDK
Official Flutter/Dart SDK for the FAM API
A type-safe, developer-friendly wrapper for Mangopay payment services
Installation • Quick Start • API Reference • UI Components • Webhooks • Error Handling • Contributing
Highlights #
- Full Dart Type Safety — Strict types for all API requests and responses
- Zero Dependencies — Only
cryptofor HMAC, no other external dependencies - Multi-Platform — Works on Android, iOS, Web, macOS, Windows, and Linux
- Automatic Retries — Built-in retry logic with exponential backoff
- Comprehensive Errors — Typed exception classes for precise error handling
- Webhook Verification — Secure signature verification out of the box
- Pre-built UI — Ready-to-use payment widgets (PaymentSheet, CardForm)
Requirements #
- Dart SDK 3.0.0 or higher
- Flutter 3.16.0 or higher
Installation #
flutter pub add fam_sdk
Using pubspec.yaml directly
dependencies:
fam_sdk: ^1.0.0
Then run:
flutter pub get
Installing from Git
dependencies:
fam_sdk:
git:
url: https://github.com/globodai-group/fam-flutter-sdk.git
ref: main
Quick Start #
import 'package:fam_sdk/fam_sdk.dart';
// Initialize the client
final fam = Fam(
apiKey: 'your-auth-token',
options: FamOptions(
baseUrl: 'https://api.fam.com',
),
);
// Create a user
final user = await fam.users.createNatural(
CreateNaturalUserRequest(
email: 'john.doe@example.com',
firstName: 'John',
lastName: 'Doe',
birthday: DateTime(1990, 1, 15),
nationality: 'FR',
countryOfResidence: 'FR',
),
);
// Create a wallet
final wallet = await fam.wallets.create(
CreateWalletRequest(
owners: [user.id],
description: 'Main wallet',
currency: Currency.EUR,
),
);
print('Wallet created: ${wallet.id}');
Configuration #
import 'package:fam_sdk/fam_sdk.dart';
final fam = Fam(
apiKey: 'your-auth-token',
options: FamOptions(
baseUrl: 'https://api.fam.com',
timeout: Duration(seconds: 30), // Request timeout (default: 30s)
maxRetries: 3, // Retry attempts (default: 3)
),
);
API Reference #
Users #
Natural Users
// Create a natural user
final user = await fam.users.createNatural(
CreateNaturalUserRequest(
email: 'user@example.com',
firstName: 'John',
lastName: 'Doe',
birthday: DateTime(1990, 1, 15),
nationality: 'FR',
countryOfResidence: 'FR',
),
);
// Update a natural user
await fam.users.updateNatural(userId, UpdateNaturalUserRequest(
firstName: 'Jane',
));
// Get user details
final user = await fam.users.getUser(userId);
final naturalUser = await fam.users.getNaturalUser(userId);
Legal Users
// Create a legal user
final company = await fam.users.createLegal(
CreateLegalUserRequest(
email: 'contact@company.com',
name: 'ACME Corp',
legalPersonType: LegalPersonType.BUSINESS,
legalRepresentativeFirstName: 'John',
legalRepresentativeLastName: 'Doe',
legalRepresentativeBirthday: DateTime(1980, 5, 20),
legalRepresentativeNationality: 'FR',
legalRepresentativeCountryOfResidence: 'FR',
),
);
// Update and retrieve
await fam.users.updateLegal(userId, UpdateLegalUserRequest(name: 'ACME Corporation'));
final legalUser = await fam.users.getLegalUser(userId);
User Resources
// Get user's wallets, cards, bank accounts, and transactions
final wallets = await fam.users.getWallets(userId);
final cards = await fam.users.getCards(userId);
final bankAccounts = await fam.users.getBankAccounts(userId);
final transactions = await fam.users.getTransactions(userId);
Wallets #
// Create a wallet
final wallet = await fam.wallets.create(
CreateWalletRequest(
owners: [userId],
description: 'EUR Wallet',
currency: Currency.EUR,
),
);
// Get wallet details and transactions
final wallet = await fam.wallets.getWallet(walletId);
final transactions = await fam.wallets.getTransactions(walletId);
Payments #
Pay-ins
// Create a card direct payin
final payin = await fam.payins.create(
CreateCardDirectPayinRequest(
authorId: userId,
creditedWalletId: walletId,
debitedFunds: Money(amount: 1000, currency: Currency.EUR),
fees: Money(amount: 0, currency: Currency.EUR),
cardId: cardId,
secureModeReturnUrl: 'https://example.com/return',
),
);
// Get payin details
final payin = await fam.payins.getPayin(payinId);
// Refund a payin
final refund = await fam.payins.refund(payinId, CreateRefundRequest(
authorId: userId,
));
Recurring Payments
// Create recurring payment registration
final recurring = await fam.payins.createRecurringPayment(
CreateRecurringPaymentRequest(
authorId: userId,
cardId: cardId,
creditedWalletId: walletId,
firstTransactionDebitedFunds: Money(amount: 1000, currency: Currency.EUR),
firstTransactionFees: Money(amount: 0, currency: Currency.EUR),
),
);
// Create Customer-Initiated Transaction (CIT)
final cit = await fam.payins.createRecurringCit(
CreateRecurringCitPayinRequest(
recurringPayinRegistrationId: recurring.id,
debitedFunds: Money(amount: 1000, currency: Currency.EUR),
fees: Money(amount: 0, currency: Currency.EUR),
secureModeReturnUrl: 'https://example.com/return',
),
);
// Create Merchant-Initiated Transaction (MIT)
final mit = await fam.payins.createRecurringMit(
CreateRecurringMitPayinRequest(
recurringPayinRegistrationId: recurring.id,
debitedFunds: Money(amount: 1000, currency: Currency.EUR),
fees: Money(amount: 0, currency: Currency.EUR),
),
);
Pay-outs
// Create a payout to bank account
final payout = await fam.payouts.create(
CreatePayoutRequest(
authorId: userId,
debitedWalletId: walletId,
debitedFunds: Money(amount: 1000, currency: Currency.EUR),
fees: Money(amount: 0, currency: Currency.EUR),
bankAccountId: bankAccountId,
),
);
// Get payout details
final payout = await fam.payouts.getPayout(payoutId);
Transfers
// Create a wallet-to-wallet transfer
final transfer = await fam.transfers.create(
CreateTransferRequest(
authorId: userId,
debitedWalletId: sourceWalletId,
creditedWalletId: targetWalletId,
debitedFunds: Money(amount: 1000, currency: Currency.EUR),
fees: Money(amount: 0, currency: Currency.EUR),
),
);
// Get transfer details
final transfer = await fam.transfers.getTransfer(transferId);
// Refund a transfer
final refund = await fam.transfers.refund(transferId, CreateRefundRequest(
authorId: userId,
));
Cards #
Card Registration
// Create card registration
final registration = await fam.cardRegistrations.create(
CreateCardRegistrationRequest(
userId: userId,
currency: Currency.EUR,
cardType: CardType.CB_VISA_MASTERCARD,
),
);
// Update with tokenized card data
final updated = await fam.cardRegistrations.update(
registration.id,
UpdateCardRegistrationRequest(registrationData: tokenizedData),
);
// Get card from registration
final card = await fam.cards.getCard(updated.cardId!);
Card Operations
// Get card details
final card = await fam.cards.getCard(cardId);
// Deactivate a card
await fam.cards.deactivate(cardId);
// Validate a card
final validation = await fam.cardValidations.create(
CreateCardValidationRequest(
authorId: userId,
cardId: cardId,
secureModeReturnUrl: 'https://example.com/return',
ipAddress: '192.168.1.1',
browserInfo: browserInfo,
),
);
User-Scoped Modules #
Bank Accounts
final bankAccounts = fam.bankAccounts(userId);
// Create IBAN bank account
final iban = await bankAccounts.createIban(
CreateIbanBankAccountRequest(
ownerName: 'John Doe',
ownerAddress: Address(
addressLine1: '1 rue de la Paix',
city: 'Paris',
postalCode: '75001',
country: 'FR',
),
iban: 'FR7630004000031234567890143',
),
);
// List and manage
final accounts = await bankAccounts.list();
final account = await bankAccounts.getAccount(accountId);
await bankAccounts.deactivate(accountId);
KYC Documents
final kyc = fam.kyc(userId);
// Create and submit KYC document
final document = await kyc.create(
CreateKycDocumentRequest(type: KycDocumentType.IDENTITY_PROOF),
);
await kyc.createPage(document.id, fileBase64);
await kyc.submit(document.id);
// Check status
final status = await kyc.getDocument(document.id);
UBO Declarations
final ubo = fam.ubo(userId);
// Create UBO declaration
final declaration = await ubo.createDeclaration();
// Add Ultimate Beneficial Owner
final owner = await ubo.createUbo(
declaration.id,
CreateUboRequest(
firstName: 'John',
lastName: 'Doe',
birthday: DateTime(1980, 1, 15),
nationality: 'FR',
address: Address(
addressLine1: '1 rue de la Paix',
city: 'Paris',
postalCode: '75001',
country: 'FR',
),
birthplace: Birthplace(city: 'Paris', country: 'FR'),
),
);
// Submit declaration
await ubo.submit(declaration.id);
SCA Recipients
final recipients = fam.scaRecipients(userId);
// Get schema for recipient type
final schema = await recipients.getSchema(
payoutMethodType: 'IBAN',
recipientType: 'Individual',
currency: 'EUR',
country: 'FR',
);
// Create recipient
final recipient = await recipients.create(
CreateRecipientRequest(
displayName: 'John Doe - Main Account',
payoutMethodType: PayoutMethodType.IBAN,
recipientType: RecipientType.Individual,
currency: Currency.EUR,
// ... schema-specific fields
),
);
Subscriptions #
// Register a subscription
final subscription = await fam.subscriptions.register(
CreateSubscriptionRequest(
userId: userId,
walletId: walletId,
cardId: cardId,
amount: Money(amount: 999, currency: Currency.EUR),
frequency: SubscriptionFrequency.MONTHLY,
),
);
// Manage subscriptions
final subscriptions = await fam.subscriptions.list(userId: userId);
final subscription = await fam.subscriptions.getSubscription(subscriptionId);
// Lifecycle operations
await fam.subscriptions.enable(subscriptionId);
await fam.subscriptions.disable(subscriptionId);
await fam.subscriptions.cancel(subscriptionId);
Portal #
// Create a portal session for user self-service
final session = await fam.portal.createSession(
CreatePortalSessionRequest(
userId: userId,
returnUrl: 'https://example.com/account',
features: [PortalFeature.MANAGE_CARDS, PortalFeature.VIEW_TRANSACTIONS],
),
);
// Redirect user to session.url
UI Components #
The SDK includes pre-built Flutter widgets for payment collection:
import 'package:fam_sdk/ui.dart';
PaymentSheet
A ready-to-use modal for collecting card payments:
final result = await PaymentSheet.show(
context: context,
amount: Money(amount: 2500, currency: Currency.EUR),
onTokenized: (cardData) async {
// Process payment with cardData
return true; // Return true on success
},
theme: FamTheme(
primaryColor: Colors.blue,
borderRadius: 12,
),
);
if (result.success) {
print('Payment completed!');
}
CardForm
A complete card input form:
CardForm(
onCardChanged: (cardData) {
setState(() => _isValid = cardData.isComplete);
},
onSubmit: (cardData) async {
// Handle card submission
},
showPostalCode: true,
theme: FamTheme.light(),
)
CardField
Individual card input fields for custom layouts:
Column(
children: [
CardField(
type: CardFieldType.number,
onChanged: (value) => _cardNumber = value,
decoration: InputDecoration(labelText: 'Card Number'),
),
Row(
children: [
Expanded(
child: CardField(
type: CardFieldType.expiry,
onChanged: (value) => _expiry = value,
),
),
Expanded(
child: CardField(
type: CardFieldType.cvc,
onChanged: (value) => _cvc = value,
),
),
],
),
],
)
Webhooks #
Verify and process webhook events securely:
import 'package:fam_sdk/fam_sdk.dart';
final webhooks = Webhooks(
config: WebhookHandlerConfig(
secret: 'whsec_your_webhook_secret',
),
);
// In your server handler
void handleWebhook(String payload, String signature) {
try {
final event = webhooks.constructEvent(payload, signature);
if (event is MangopayWebhookEvent) {
switch (event.type) {
case MangopayEventType.PAYIN_NORMAL_SUCCEEDED:
handleSuccessfulPayin(event);
break;
case MangopayEventType.PAYIN_NORMAL_FAILED:
handleFailedPayin(event);
break;
case MangopayEventType.KYC_SUCCEEDED:
handleKycValidation(event);
break;
default:
print('Unhandled event: ${event.type}');
}
} else if (event is FamWebhookEvent) {
switch (event.type) {
case FamEventType.FAM_SUBSCRIPTION_PAYMENT_SUCCEEDED:
handleSubscriptionPayment(event);
break;
default:
print('Unhandled FAM event: ${event.type}');
}
}
} on WebhookSignatureException catch (e) {
print('Invalid webhook signature: $e');
// Return 400 Bad Request
}
}
Error Handling #
The SDK provides typed exception classes for precise error handling:
import 'package:fam_sdk/fam_sdk.dart';
try {
final user = await fam.users.getUser('invalid-id');
} on NotFoundException catch (e) {
// Resource not found (404)
print('User not found');
} on AuthenticationException catch (e) {
// Invalid or expired token (401)
print('Please re-authenticate');
} on ValidationException catch (e) {
// Invalid request data (400/422)
print('Validation errors:');
for (final error in e.fieldErrors) {
print(' ${error.field}: ${error.message}');
}
} on RateLimitException catch (e) {
// Too many requests (429)
print('Rate limited. Retry after ${e.retryAfter?.inSeconds}s');
} on NetworkException catch (e) {
// Connection/timeout errors
print('Network error: ${e.message}');
} on ApiException catch (e) {
// Other API errors
print('API error ${e.statusCode}: ${e.message}');
}
Dart Types #
Full type definitions are included for all API operations:
import 'package:fam_sdk/fam_sdk.dart';
// Users
NaturalUser user;
LegalUser company;
CreateNaturalUserRequest request;
CreateLegalUserRequest legalRequest;
// Payments
Wallet wallet;
Payin payin;
Payout payout;
Transfer transfer;
// Cards
Card card;
CardRegistration registration;
// KYC
KycDocument document;
UboDeclaration declaration;
// Subscriptions
Subscription subscription;
// Common
Money amount;
Currency currency;
Address address;
Development #
# Install dependencies
flutter pub get
# Run tests
flutter test
# Run tests with coverage
flutter test --coverage
# Analyze code
flutter analyze
# Format code
dart format .
Contributing #
We welcome contributions! Please see our contributing guidelines:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
flutter test) - Commit using Conventional Commits (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Security #
If you discover a security vulnerability, please send an email to security@globodai.com instead of using the issue tracker.
License #
This project is licensed under the MIT License - see the LICENSE file for details.
Made with care by the Globodai team