How it works
SimpleFIN uses a setup token system to establish secure access to your bank accounts:- Obtain a setup token from SimpleFIN
- Sure claims the setup token to get an access URL with embedded credentials
- The access URL is used to fetch account data, balances, and transactions
- Data syncs automatically to keep your information current
Setting up SimpleFIN
To connect your US bank accounts:- Sign up for a SimpleFIN account at simplefin.org
- Generate a setup token from your SimpleFIN dashboard
- In Sure, provide the setup token
- Sure will claim the token and establish access to your accounts
Setup token claiming
The setup token is a base64-encoded claim URL. When you provide it to Sure:- Sure decodes the token to get the claim URL
- Validates the URL’s target address before sending any request
- Makes a POST request to claim the access URL
- Receives an access URL with HTTP Basic Auth credentials embedded
- Uses this access URL for all subsequent API requests
Features
Account syncing
- Account listing: View all connected accounts with current balances
- Transaction history: Import transactions with date range filtering
- Pending transactions: Included by default. Not all institutions return pending transactions even when requested — this is a limitation of the institution’s data feed.
- Multiple accounts: Connect multiple bank accounts from different institutions
- Localized status messages: Sync status summaries (such as “2 accounts synced” or “1 account needs setup”) display in your chosen language
Date range filtering
When syncing transactions, you can specify:- Start date: Fetch transactions from this date forward
- End date: Fetch transactions up to this date
Pending transaction inclusion
Pending transactions are included by default. Sure resolves whether to request them in this order:- An explicit argument passed internally by the sync flow
- The
SIMPLEFIN_INCLUDE_PENDINGenvironment variable (1= include,0= exclude) - The shared Include pending transactions setting under Settings → Self-Hosting
1 (on). To disable pending transactions globally, set:
pending=0 to the SimpleFIN API is not the same as omitting the parameter. The low-level client only adds pending=1 when inclusion is enabled and omits the parameter otherwise, because some bridges treat the parameter’s presence — regardless of value — as a request to include pending.
Error handling
Sure supports both the legacy SimpleFINerrors field and the structured errlist field introduced in protocol v2. When errlist is nonempty, it takes precedence over legacy errors.
Error responses are classified as either partial or fatal:
- Partial errors (
act.*error codes): affect one or more individual accounts but accounts data is still returned. Sure records these errors in sync stats for visibility and continues importing the remaining accounts. - Fatal errors: errors accompanied by no accounts, or a structured
gen.*error even when accounts are present. Sure stops the import and raises an error. The connection requires an update for structuredgen.auth,auth_failure,token_expired, orauthentication_errorerrors, or for legacy text mentioning authentication or reauthentication. An account-scopedact.authcode alone does not invalidate the entire connection.
gen.*-coded errors (general errors) always trigger the fatal path, even when some account data is present in the same response. The account data alongside a general error may be stale or incomplete and cannot be safely imported.
Reliability features
Sure’s SimpleFIN integration includes automatic retry logic:- Exponential backoff for transient network failures
- Up to 3 retry attempts for network errors
- Handles temporary connection issues gracefully
- Prevents sync failures from intermittent network problems
URL security checks
Sure validates every SimpleFIN URL — both the setup token’s claim URL and the stored access URL used on every sync — against a set of network address rules before making any request. This prevents a crafted token or bridge from directing the server to internal services.What is always blocked
The following addresses are blocked regardless of whether you self-host Sure or use the project-operated instance:- Non-http(s) URLs
- Link-local addresses (169.254.0.0/16), including the AWS instance metadata endpoint (169.254.169.254)
- Unspecified, multicast, and reserved IPv4 ranges
- The AWS IPv6 metadata address (fd00:ec2::254)
- The Alibaba Cloud metadata address (100.100.100.200)
- IPv6 addresses that carry an embedded IPv4 address (IPv4-mapped, NAT64, 6to4, IPv4-translated) are resolved to their underlying IPv4 address and checked against the same rules
Additional restrictions on managed instances
On the project-operated Sure instances (app.sure.am and demo.sure.am), the following addresses are also blocked to prevent access to private infrastructure:- http:// URLs (https is required)
- Loopback addresses (127.0.0.0/8, ::1)
- Private network ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Carrier-grade NAT range (100.64.0.0/10)
- IETF protocol assignment and benchmarking ranges (192.0.0.0/24, 198.18.0.0/15)
How checks are applied
Sure resolves the hostname to its IP addresses before each request and connects to the checked address directly. This prevents DNS rebinding attacks, where a hostname initially resolves to a public address but later resolves to an internal one mid-connection. Redirects are not followed, so a redirect to an internal address cannot bypass the check. When the stored access URL fails a check during a sync, Sure marks the connection as requiring reconnection and records a debug log entry under Settings → Debug. Providing a new setup token from your SimpleFIN dashboard resolves this.API structure
SimpleFIN uses a simple REST API with embedded authentication:- POST /claim: Exchange setup token for access URL
- GET /accounts: Fetch all accounts with balances and transactions
- GET /info: Get server information
API reference
For detailed protocol documentation, see the SimpleFIN Protocol.Pricing
SimpleFIN is a paid service, but typically more affordable than alternatives like Plaid. Check simplefin.org for current pricing.Investment holdings and lot aggregation
SimpleFIN reports one record per lot, so a single position can arrive as several records sharing the same security. A 401k that splits employee deferral from employer match is a common example. Sure combines these lots into a single position per security before storing the holding. Quantity and market value are summed across all lots. Cost basis is stored per share, so lots are combined into a share-weighted average — but only when every lot reported a basis. If any lot omits its cost basis, the entire position’s cost basis is left unknown rather than averaging over partial data, which would invent cost and produce incorrect gain/loss figures. If your investment account shows a total value that matches your institution’s balance but individual holdings appear at less than their full value, a manual sync from Settings → Providers → SimpleFIN will re-import the combined positions correctly.Holdings history
Holdings are stored by date: a sync on a new day creates that day’s row, while another sync on the same day updates it instead of overwriting the previous day’s record. This means Sure accumulates a daily history of your positions so you can see how your portfolio has changed over time.User corrections carried forward
When you remap a holding to a different security or lock a cost basis, Sure preserves that correction when a new day’s sync creates the next holding row. Sure uses the latest earlier row for the same account, provider, provider security, and currency, carrying its active security and cost-basis locks forward. If you have since undone a correction, the undone state is not revived — only the latest version is carried forward.Institution-specific cost basis corrections
The SimpleFIN specification says thecost_basis field is a per-share value, but some brokerages populate it with the total position cost instead. Sure detects these cases by institution name or domain and divides by quantity automatically, so the stored per-share figure stays correct.
Institutions where Sure applies this correction: Vanguard, Fidelity, Schwab, and E*Trade.
If your institution sends a total cost in cost_basis but is not in this list, the holding will show an inflated per-share basis. In that case, you can correct the value by setting a manual cost basis on the holding.
Limitations
- US-focused: Primarily supports US financial institutions
- Setup token security: Setup tokens can only be claimed once and may expire
- Pending transactions: Not all institutions return pending transactions, even when requested
- Rate limits: Subject to SimpleFIN API rate limits
- Access URL validity: Access URLs can be revoked or expire (returns 403 error)
Troubleshooting
Incorrect balance sign on credit cards or loans
SimpleFIN reports liability balances from the bank’s perspective (positive = you owe money). Sure converts these into the correct sign for net worth calculations — liabilities reduce net worth, so their balances are stored as negative values. For loans, Sure trusts the bank’s sign directly and stores the absolute value of the reported balance. Earlier versions incorrectly ran a transaction-history heuristic on loans, which could invert the balance and make the loan appear to add to your net worth instead of subtracting from it. This is now fixed. For credit cards, Sure uses recent transaction history to determine whether a positive balance represents debt (normal) or an overpayment credit (unusual). When there is not enough transaction history to decide, Sure falls back to sign-based normalization using both the posted and available balances reported by the institution. If a credit card balance still looks wrong after syncing, you can override the automatic sign detection. Open the account’s edit form (from Settings → Providers → SimpleFIN or the account detail page) and find the SimpleFIN balance meaning dropdown:- Automatic (default): Sure uses transaction history and provider balance to determine the correct sign.
- Debt (you owe the bank): Forces the balance to be treated as a positive debt amount.
- Credit (bank owes you): Forces the balance to be treated as a credit in your favor (for example, an overpayment).
- Re-sync the account from Settings → Providers → SimpleFIN.
- If the balance is still incorrect, check whether the account type is set to Credit Card or Loan in your account settings. An incorrect account type can cause the wrong normalization to be applied.
- For credit cards connected through SimpleFIN, set SimpleFIN balance meaning to Debt or Credit in the account’s edit form if the automatic detection is wrong for your institution.
Duplicate accounts with the same name
If you have two accounts at the same institution with identical display names (for example, two accounts both named “CHECKING (0001)”), Sure uses the upstream account ID to distinguish them during sync. Only accounts whose ID is genuinely absent from the upstream response are treated as stale and eligible for re-linking. Ambiguous cases where multiple local accounts share a name are skipped rather than resolved automatically, preventing one account from silently inheriting another’s transaction history. If you notice an account that appears to have lost its transaction history after a sync, check Settings → Debug for any skipped stale-linkage repair entries that may indicate an ambiguous name match.Setup token issues
If you receive a 403 error when claiming a setup token:- The token may have already been used
- The token may have expired
- The token may have been compromised
Invalid token or disallowed address error
If Sure shows an invalid token error immediately when you enter a setup token, the token’s embedded claim URL may point to a network address that Sure does not permit. This can happen with tokens generated by a bridge misconfigured to use a private or metadata address. Check that your SimpleFIN bridge is reachable at a public address. On the project-operated instance, https is required and private network addresses are blocked. On a self-hosted instance, http and local network addresses are allowed. If the connection was working and now requires reconnection after a sync, check Settings → Debug for aSimpleFIN access URL rejected entry. This indicates the stored access URL now resolves to a blocked address. Provide a new setup token from your SimpleFIN dashboard to reconnect.
Missing pending transactions
Pending transactions are requested by default. Some institutions don’t return them even whenpending=1 is sent. This is a limitation of the institution’s data feed, not a bug in SimpleFIN or Sure.
If you want to disable pending transactions entirely, set SIMPLEFIN_INCLUDE_PENDING=0 in your environment or turn off Include pending transactions under Settings → Self-Hosting.
Network errors
If you experience intermittent sync failures:- Sure automatically retries failed requests up to 3 times
- Network errors are logged for troubleshooting
- Manual sync attempts may succeed where automatic syncs fail