Claude
Skills
Sign in
Back

financekit

Included with Lifetime
$97 forever

Access eligible Wallet financial data using FinanceKit and FinanceKitUI. Use when querying transactions or balances, reading Apple Card, Apple Cash, Savings, or U.K. connected-account data, requesting financial-data authorization, using TransactionPicker, enabling iOS 26 background delivery, or saving and checking Wallet orders.

Web3

What this skill does


# FinanceKit

Access eligible financial data from Apple Wallet, including U.S. Apple Card, Apple Cash, Savings, and U.K. connected-account data. FinanceKit provides on-device access to accounts, balances, and transactions with user-controlled authorization. Targets Swift 6.3 / current Apple platforms; query APIs are available from iOS/iPadOS 17.4, `TransactionPicker` from iOS/iPadOS 18, and background delivery from iOS/iPadOS 26.

Keep FinanceKit guidance focused on financial-data access, Wallet order storage/querying, TransactionPicker, and background delivery. Route Apple Pay checkout to PassKit, widget UI/timeline work to WidgetKit, and Wallet order-tracking email or Apple Business Connect optimization outside this skill.

## Contents

- [Setup and Entitlements](#setup-and-entitlements)
- [Data Availability](#data-availability)
- [Authorization](#authorization)
- [Querying Accounts](#querying-accounts)
- [Account Balances](#account-balances)
- [Querying Transactions](#querying-transactions)
- [Long-Running Queries and History](#long-running-queries-and-history)
- [Transaction Picker](#transaction-picker)
- [Wallet Orders](#wallet-orders)
- [Background Delivery](#background-delivery)
- [Common Mistakes](#common-mistakes)
- [Review Checklist](#review-checklist)
- [References](#references)

## Setup and Entitlements

### Requirements

1. **Managed entitlement** -- request `com.apple.developer.financekit` from Apple via the [FinanceKit entitlement request form](https://developer.apple.com/contact/request/financekit/). This is a managed capability; Apple reviews each application.
2. **Organization-level Apple Developer account** (individual accounts are not eligible).
3. **Account Holder role** required to request the entitlement.
4. **Eligible App Store app** -- the app must be in the Finance category, distributed through the App Store for iPhone in the United States or United Kingdom, and provide financial-management tools such as net-worth, spending, or budgeting features.
5. **Per-bundle-ID approval** -- Apple assigns the entitlement to the approved bundle ID; do not assume it applies to sibling apps or extensions automatically.
6. If the app offers financial products directly or through a regulated institution, it must allow customers to connect those accounts to Apple Wallet and share the data with FinanceKit.

### Project Configuration

1. Add the FinanceKit entitlement through Xcode managed capabilities after Apple approves the request.
2. Add `NSFinancialDataUsageDescription` to Info.plist -- this string is shown to the user during the authorization prompt.
3. For iOS 26 background delivery, add the FinanceKit entitlement to both the app and extension targets, then use App Groups for shared storage.

```xml
<key>NSFinancialDataUsageDescription</key>
<string>This app uses your financial data to track spending and provide budgeting insights.</string>
```

## Data Availability

U.S. FinanceKit financial data requires iOS/iPadOS 17.4+ and currently covers eligible Apple Card, Apple Cash, and Savings data; Apple Card Family participants and Apple Cash Family children are excluded. U.K. support requires iOS/iPadOS 18.4+ and uses open banking for supported institutions. Orders APIs are available separately from financial-data query APIs.

Check whether the device supports FinanceKit before making any API calls. This value is constant across launches and iOS versions.

```swift
import FinanceKit

guard FinanceStore.isDataAvailable(.financialData) else {
    // FinanceKit not available -- do not call any other financial data APIs.
    // The framework terminates the app if called when unavailable.
    return
}
```

For Wallet orders:

```swift
guard FinanceStore.isDataAvailable(.orders) else { return }
```

Data availability returning `true` does not guarantee data exists on the device. Data access can also become temporarily restricted (e.g., Wallet unavailable, MDM restrictions). Restricted access throws `FinanceError.dataRestricted` rather than terminating.

## Authorization

Request authorization to access user-selected financial accounts. The system presents an account picker where the user chooses which accounts to share and the earliest transaction date to expose.

```swift
let store = FinanceStore.shared

let status = try await store.requestAuthorization()
switch status {
case .authorized:    break  // Proceed with queries
case .denied:        break  // User declined
case .notDetermined: break  // No meaningful choice made
@unknown default:    break
}
```

### Checking Current Status

Query current authorization without prompting:

```swift
let currentStatus = try await store.authorizationStatus()
```

Once the user grants or denies access, `requestAuthorization()` returns the cached decision without showing the prompt again. Users can change access in Settings > Privacy & Security > Financial Data.

## Querying Accounts

Accounts are modeled as an enum with two cases: `.asset` (e.g., Apple Cash, Savings) and `.liability` (e.g., Apple Card credit). Both share common properties (`id`, `displayName`, `institutionName`, `currencyCode`) while liability accounts add credit-specific fields.

```swift
func fetchAccounts() async throws -> [Account] {
    let query = AccountQuery(
        sortDescriptors: [SortDescriptor(\Account.displayName)],
        predicate: nil,
        limit: nil,
        offset: nil
    )

    return try await store.accounts(query: query)
}
```

### Working with Account Types

```swift
switch account {
case .asset(let asset):
    print("Asset account, currency: \(asset.currencyCode)")
case .liability(let liability):
    if let limit = liability.creditInformation.creditLimit {
        print("Credit limit: \(limit.amount) \(limit.currencyCode)")
    }
}
```

## Account Balances

Balances represent the amount in an account at a point in time. A `CurrentBalance` is one of three cases: `.available` (includes pending), `.booked` (posted only), or `.availableAndBooked`.

```swift
func fetchBalances(for accountID: UUID) async throws -> [AccountBalance] {
    let predicate = #Predicate<AccountBalance> { balance in
        balance.accountID == accountID
    }

    let query = AccountBalanceQuery(
        sortDescriptors: [SortDescriptor(\AccountBalance.id)],
        predicate: predicate,
        limit: nil,
        offset: nil
    )

    return try await store.accountBalances(query: query)
}
```

### Reading Balance Amounts

Amounts are always positive decimals. Use `creditDebitIndicator` to determine the sign:

```swift
func formatBalance(_ balance: Balance) -> String {
    let sign = balance.creditDebitIndicator == .debit ? "-" : ""
    return "\(sign)\(balance.amount.amount) \(balance.amount.currencyCode)"
}

// Extract from CurrentBalance enum:
switch balance.currentBalance {
case .available(let bal):       formatBalance(bal)
case .booked(let bal):          formatBalance(bal)
case .availableAndBooked(let available, _): formatBalance(available)
@unknown default: "Unknown"
}
```

## Querying Transactions

Use `TransactionQuery` with Swift predicates, sort descriptors, limit, and offset.

```swift
let predicate = #Predicate<Transaction> { $0.accountID == accountID }

let query = TransactionQuery(
    sortDescriptors: [SortDescriptor(\Transaction.transactionDate, order: .reverse)],
    predicate: predicate,
    limit: 50,
    offset: nil
)

let transactions = try await store.transactions(query: query)
```

### Reading Transaction Data

```swift
let amount = transaction.transactionAmount
let direction = transaction.creditDebitIndicator == .debit ? "spent" : "received"
print("\(transaction.transactionDescription): \(direction) \(amount.amount) \(amount.currencyCode)")
// merchantName, merchantCategoryCode, foreignCurrencyAmount are optional
```

### Built-In Predicate Helpers

FinanceKit provides factory methods for common filters:

```swift
// Filter by transaction status
let bookedOnly = TransactionQuery.predicate(forStatuses: [.booked
Files: 3
Size: 48.9 KB
Complexity: 46/100
Category: Web3

Related in Web3