expo-finance-kit
Version:
Native Expo module for Apple FinanceKit - Access financial data from Apple Card and other accounts
303 lines (234 loc) • 9.14 kB
Markdown
# expo-finance-kit
Native Expo module for Apple FinanceKit - Access financial data from Apple Card and other accounts on iOS 17.4+.
A comprehensive, type-safe library providing modular access to Apple's FinanceKit API with React hooks, formatters, analytics, and more.
## Features
- 🔐 **Authorization Management** - Handle FinanceKit permissions with ease
- 💳 **Account Access** - Fetch and manage financial accounts
- 📊 **Transaction History** - Query and analyze transaction data
- 💰 **Balance Tracking** - Monitor account balances in real-time
- 📈 **Analytics & Insights** - Generate spending insights and detect trends
- ⚛️ **React Hooks** - Ready-to-use hooks for React Native apps
- 🎨 **Formatters** - Currency, date, and number formatting utilities
- 🛡️ **Type Safety** - Full TypeScript support with strict typing
- 🚀 **Performance** - Built-in caching and optimization
## Installation
```bash
npm install expo-finance-kit
```
## Configuration
### iOS Setup
1. **Request FinanceKit Entitlement from Apple** - You must request access to the FinanceKit entitlement from Apple before you can use this API. Visit the [Apple Developer Portal](https://developer.apple.com) to request access.
2. Add the FinanceKit entitlement to your app's entitlements file (after Apple approves your request):
```xml
<key>com.apple.developer.financekit</key>
<true/>
```
3. Add the privacy description to your `Info.plist`:
```xml
<key>NSFinancialDataDescription</key>
<string>This app needs access to your financial data to display transaction history and account information.</string>
```
4. FinanceKit requires iOS 17.4 or later.
## Quick Start
### Basic Usage
```typescript
import {
isFinanceKitAvailable,
requestAuthorization,
getAccounts,
getTransactions,
formatCurrency
} from 'expo-finance-kit';
// Check if FinanceKit is available
if (!isFinanceKitAvailable()) {
console.log('FinanceKit not available on this device');
return;
}
// Request authorization
const { granted } = await requestAuthorization();
if (granted) {
// Fetch accounts
const accounts = await getAccounts();
console.log(`Found ${accounts.length} accounts`);
// Get recent transactions
const transactions = await getTransactions({
accountId: accounts[0].id,
startDate: new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), // 30 days ago
limit: 50
});
// Format currency for display
transactions.forEach(transaction => {
console.log(`${transaction.merchantName}: ${formatCurrency(transaction.amount, transaction.currencyCode)}`);
});
}
```
### Using React Hooks
```typescript
import React from 'react';
import { View, Text, Button } from 'react-native';
import {
useAuthorizationStatus,
useAccounts,
useTransactions,
formatCurrency,
formatRelativeDate
} from 'expo-finance-kit';
function MyFinanceApp() {
const { isAuthorized, requestAuthorization } = useAuthorizationStatus();
const { accounts, loading: accountsLoading } = useAccounts();
const { transactions, refetch } = useTransactions({ limit: 20 });
if (!isAuthorized) {
return (
<View>
<Text>Please authorize access to your financial data</Text>
<Button title="Authorize" onPress={requestAuthorization} />
</View>
);
}
return (
<View>
<Text>Accounts ({accounts.length})</Text>
{accounts.map(account => (
<Text key={account.id}>{account.displayName} - {account.institutionName}</Text>
))}
<Text>Recent Transactions</Text>
{transactions.map(transaction => (
<View key={transaction.id}>
<Text>{transaction.merchantName || transaction.transactionDescription}</Text>
<Text>{formatCurrency(transaction.amount, transaction.currencyCode)}</Text>
<Text>{formatRelativeDate(transaction.transactionDate)}</Text>
</View>
))}
<Button title="Refresh" onPress={refetch} />
</View>
);
}
```
### Advanced Analytics
```typescript
import {
generateSpendingInsights,
calculateTransactionStats,
findUnusualTransactions,
calculateSavingsRate
} from 'expo-finance-kit';
// Generate spending insights for the last 30 days
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
const insights = generateSpendingInsights(transactions, startDate, endDate);
console.log(`Total spent: ${formatCurrency(insights.totalSpent, 'USD')}`);
console.log(`Total income: ${formatCurrency(insights.totalIncome, 'USD')}`);
// Calculate statistics
const stats = calculateTransactionStats(transactions);
console.log(`Average transaction: ${formatCurrency(stats.averageTransaction, 'USD')}`);
console.log(`Savings rate: ${calculateSavingsRate(stats.totalIncome, stats.totalExpenses)}%`);
// Find unusual transactions
const unusual = findUnusualTransactions(transactions);
console.log(`Found ${unusual.length} unusual transactions`);
// Category breakdown
insights.categoriesBreakdown.forEach(category => {
console.log(`${category.category}: ${category.percentage.toFixed(1)}% (${formatCurrency(category.amount, 'USD')})`);
});
```
## API Reference
### Core Functions
#### Authorization
- `requestAuthorization()` - Request access to financial data
- `getAuthorizationStatus()` - Get current authorization status
- `isFinanceKitAvailable()` - Check if FinanceKit is available
- `ensureAuthorized()` - Helper to ensure authorization before data access
#### Accounts
- `getAccounts()` - Fetch all accounts
- `getAccountById(id)` - Get a specific account
- `getAccountsByInstitution()` - Group accounts by institution
- `getPrimaryAccount()` - Get the primary (first asset) account
#### Transactions
- `getTransactions(options)` - Fetch transactions with filtering
- `getRecentTransactions(limit)` - Get recent transactions
- `getTransactionsByAccount(accountId, options)` - Get account-specific transactions
- `getIncomeTransactions()` - Get only income (credit) transactions
- `getExpenseTransactions()` - Get only expense (debit) transactions
#### Balances
- `getBalances()` - Fetch all account balances
- `getBalanceByAccount(accountId)` - Get balance for specific account
- `getTotalBalance()` - Calculate total balance across all accounts
- `getBalanceSummary()` - Get comprehensive balance summary
### React Hooks
- `useAuthorizationStatus()` - Manage authorization state
- `useAccounts(options?)` - Fetch and monitor accounts
- `useTransactions(options?)` - Fetch and monitor transactions
- `useAccountBalance(accountId?)` - Track account balance
- `useTotalBalance()` - Monitor total balance
- `useTransactionStream(accountId?, interval?)` - Real-time transaction updates
### Utilities
#### Formatters
- `formatCurrency(amount, currencyCode)` - Format currency values
- `formatDate(date, format)` - Format dates
- `formatRelativeDate(date)` - Format relative dates (e.g., "2 days ago")
- `formatAccountName(account)` - Format account display name
- `formatPercentage(value)` - Format percentages
#### Analytics
- `generateSpendingInsights(transactions, startDate, endDate)` - Generate comprehensive insights
- `calculateTransactionStats(transactions)` - Calculate transaction statistics
- `findUnusualTransactions(transactions)` - Detect unusual spending
- `calculateSavingsRate(income, expenses)` - Calculate savings percentage
- `predictFutureBalance(transactions, currentBalance, days)` - Predict future balance
### Types
```typescript
interface Account {
id: string;
institutionName: string;
displayName: string;
accountDescription?: string;
currencyCode: string;
accountType: 'asset' | 'liability';
}
interface Transaction {
id: string;
accountId: string;
amount: number;
currencyCode: string;
transactionDate: number;
merchantName?: string;
transactionDescription: string;
merchantCategoryCode?: number;
status: TransactionStatus;
transactionType: TransactionType;
creditDebitIndicator: 'credit' | 'debit';
}
interface AccountBalance {
id: string;
accountId: string;
amount: number;
currencyCode: string;
}
interface SpendingInsights {
periodStart: number;
periodEnd: number;
totalSpent: number;
totalIncome: number;
netCashFlow: number;
categoriesBreakdown: CategoryBreakdown[];
merchantsBreakdown: MerchantBreakdown[];
}
```
## Platform Support
- ✅ iOS 17.4+
- ❌ Android (returns "unavailable" for all methods)
- ❌ Web (returns "unavailable" for all methods)
## Examples
Check out the [example app](./example) for a complete implementation showcasing all features including:
- Authorization flow
- Account listing and selection
- Transaction history with grouping
- Balance display
- Spending statistics and insights
- Unusual transaction detection
- Pull-to-refresh functionality
## Contributing
Contributions are welcome! Please read our [contributing guidelines](CONTRIBUTING.md) before submitting PRs.
## License
MIT
## Acknowledgments
This module provides a comprehensive wrapper around Apple's FinanceKit API, making it easy to integrate financial data into your Expo/React Native applications.