Loading...
Search the Quiltt documentation
Loading...
Once a user connects a bank, the first thing most apps show is their accounts and balances. This tutorial builds a React dashboard that queries a Profile's connected accounts, displays each balance, and computes a net total across every account.
Time: ~10 minutes
Framework: React (concepts apply to any client)
A dashboard that:
Every Account in Quiltt exposes a balance with three amounts:
| Field | Meaning |
|---|---|
current | The balance based on posted transactions |
available | The balance accounting for pending transactions |
limit | The overdraft or credit limit, when the provider reports one |
Quiltt normalizes the sign of these amounts across providers, so the same convention applies regardless of the upstream source:
Because the signs are consistent, summing every account's current balance produces a true net figure — assets add and liabilities subtract. You'll use this to compute a net total in step 4.
QuilttAuthProvider set up and at least one connected account. If you don't have this yet, complete the Authentication Tutorial first — it wires up the provider and launches the Connector.This tutorial continues from the Authentication Tutorial, reusing its QuilttAuthProvider and GraphQL client.
Before writing any code, test the query in the GraphQL Explorer (Dashboard → Profiles → select a Profile). The accounts query returns every account on the Profile:
query GetAccounts {
accounts {
id
name
mask
kind
currencyCode
institution {
name
}
balance {
current
available
limit
at
}
}
}
{
"data": {
"accounts": [
{
"id": "acct_12sf19AeKaWfukStXAL7nN",
"name": "Premium Checking",
"mask": "3141",
"kind": "DEPOSITORY",
"currencyCode": "USD",
"institution": { "name": "MX Bank" },
"balance": {
"current": 3141.59,
"available": 3000.0,
"limit": null,
"at": "2024-06-09T07:40:20Z"
}
},
{
"id": "acct_12vAFU1c4t514E40Nb9NTW",
"name": "Premium Credit Card",
"mask": "2134",
"kind": "CREDIT",
"currencyCode": "USD",
"institution": { "name": "MX Bank" },
"balance": {
"current": -2134.34,
"available": 12665.66,
"limit": -15000.0,
"at": "2024-06-01T18:55:35Z"
}
}
]
}
}
The credit card's current of -2134.34 means the user owes $2,134.34. See the Account Balances reference for the full sign convention.
Balances are plain numbers, so format them with the account's currencyCode. Create a helper that renders any amount in the account's currency:
// lib/formatCurrency.ts
export function formatCurrency(amount: number | null, currencyCode = 'USD') {
if (amount === null) return '—'
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: currencyCode,
}).format(amount)
}
A balance can be null when a Connection is still syncing, so this helper returns a placeholder rather than crashing.
Query the accounts with useQuery and render each one. This reuses the GraphQL client from the Authentication Tutorial:
// components/AccountList.tsx
'use client'
import { useQuilttClient, useQuery, gql } from '@quiltt/react'
import { formatCurrency } from '../lib/formatCurrency'
const ACCOUNTS_QUERY = gql`
query GetAccounts {
accounts {
id
name
mask
kind
currencyCode
institution {
name
}
balance {
current
available
at
}
}
}
`
export default function AccountList() {
const client = useQuilttClient()
const { data, loading, error } = useQuery(ACCOUNTS_QUERY, { client })
if (loading) return <div>Loading accounts...</div>
if (error) return <div>Couldn't load accounts. Try again.</div>
const accounts = data?.accounts ?? []
if (accounts.length === 0) {
return <div>No connected accounts yet. Launch the Connector to add one.</div>
}
return (
<ul className="flex flex-col gap-2">
{accounts.map((account) => (
<li key={account.id} className="flex justify-between border p-3">
<div>
<div className="font-medium">
{account.name}
{account.mask && <span className="text-gray-500"> ••{account.mask}</span>}
</div>
<div className="text-sm text-gray-500">
{account.institution.name} · {account.kind}
</div>
</div>
<div className="text-right font-mono">
{formatCurrency(account.balance?.current ?? null, account.currencyCode)}
</div>
</li>
))}
</ul>
)
}
Sum each account's current balance to show a net total. Because Quiltt normalizes the sign, liabilities subtract automatically:
// components/AccountList.tsx (add above the return)
const netTotal = accounts.reduce(
(total, account) => total + (account.balance?.current ?? 0),
0,
)
const currencyCode = accounts[0]?.currencyCode ?? 'USD'
Render it above the list:
<div className="mb-4 flex justify-between border-b pb-2 text-lg font-semibold">
<span>Net total</span>
<span className="font-mono">{formatCurrency(netTotal, currencyCode)}</span>
</div>
The net total is only meaningful when every account shares one currency. If a Profile holds accounts in multiple currencies, group by currencyCode and show a total per currency instead of one combined figure.
Drop the AccountList component into the page you built in the Authentication Tutorial:
// app/page.tsx
'use client'
import { QuilttButton } from '@quiltt/react'
import AccountList from './components/AccountList'
const CONNECTOR_ID = process.env.NEXT_PUBLIC_QUILTT_CONNECTOR_ID
export default function Home() {
return (
<main className="mx-auto flex max-w-xl flex-col gap-4 p-8">
<AccountList />
<QuilttButton connectorId={CONNECTOR_ID} className="border p-2">
Connect another account
</QuilttButton>
</main>
)
}
| Problem | Cause | Fix |
|---|---|---|
accounts is empty | The Profile has no connected accounts, or the token is for a different Profile | Connect an account, and confirm the Session token belongs to the right Profile. |
Balance shows — | The Connection is still syncing, so balance is null | Wait for the connection.synced.successful webhook, then re-query. |
All balances read $0.00 | Balances aren't formatted with the account's currency | Pass account.currencyCode to formatCurrency. |
| Net total looks wrong | Accounts span multiple currencies | Group by currencyCode and total each currency separately. |
You now display connected accounts and balances. To keep balances fresh for payment flows, trigger a real-time balance refresh and listen for the balance.created webhook.