Building a financial dashboard with Stripe, Shopify, and Plaid without writing a reconciliation engine
March 6, 2026 · 8 min read
Your data lives in three places
If you run a business that sells through Shopify and processes payments with Stripe, your financial data is split across three systems. Stripe knows your payment volume and fees. Shopify knows your orders, refunds, and its own payouts. Your bank knows what actually landed in your account and what you spent.
Building a dashboard that combines all three means writing OAuth flows, managing API keys, syncing data on a schedule, normalizing amounts (Stripe uses cents, Plaid uses dollars with negative signs for deposits), and building matching logic to figure out which bank deposit corresponds to which payout. That is months of work before you display a single number.
FlowCheck handles all of that. You connect your accounts, and every endpoint returns unified data. Here is how to set it up from scratch.
Step 1: Get an API key
Register with your email. You will get 100 free credits and a sandbox key to test with.
curl -X POST https://developer.usepopup.com/api/v0/auth/register \
-H "Content-Type: application/json" \
-d '{"email": "you@example.com"}'Complete the checkout flow, then check your registration status to get your API key:
curl https://developer.usepopup.com/api/v0/auth/register/status?token=YOUR_TOKEN
Save the key. It starts with fc_live_ for production or fc_test_ for sandbox. You will not see it again.
Step 2: Connect Stripe
Create a restricted key in your Stripe dashboard with read access to Payouts and Balance. Then pass it to FlowCheck:
curl -X POST https://developer.usepopup.com/api/v0/connect/stripe \
-H "Authorization: Bearer fc_live_your_key" \
-H "Content-Type: application/json" \
-d '{"restricted_key": "rk_live_your_stripe_key"}'Or with the SDK:
import { FlowCheck } from "@flowcheck/sdk"
const fc = new FlowCheck("fc_live_your_key")
await fc.connectStripe({ restrictedKey: "rk_live_your_stripe_key" })FlowCheck encrypts your Stripe key with AES-256-GCM before storing it. Once connected, payout data syncs automatically.
Step 3: Connect Shopify
Create a custom app in your Shopify admin with read access to Orders and Payouts. Pass the shop domain and access token:
await fc.connectShopify({
shop: "my-store.myshopify.com",
accessToken: "shpat_your_token"
})Shopify orders and payouts now show up alongside Stripe data in every FlowCheck endpoint.
Step 4: Connect your bank account
Bank connections use Plaid Link, a two-step flow. First, get a Link token from FlowCheck:
const { data } = await fc.createPlaidLinkToken()
// data.link_token = "link-sandbox-abc123..."
// Use the Plaid Link SDK in your frontend to open the bank selector
// When the user finishes, Plaid gives you a public_token
await fc.exchangePlaidToken({ publicToken: "public-sandbox-xyz..." })After the exchange, bank transactions sync automatically. Deposits show as negative amounts in Plaid (yes, really), and FlowCheck normalizes everything so you do not have to think about it.
Step 5: Query everything from one endpoint
With all three sources connected, a single call gives you your complete financial picture:
const cashflow = await fc.cashflow("30d")
console.log(`Total inflow: $${cashflow.data.total_inflows / 100}`)
console.log(`Total outflow: $${cashflow.data.total_outflows / 100}`)
console.log(`Net: $${cashflow.data.net / 100}`)
// Daily breakdown
for (const day of cashflow.data.daily) {
console.log(`${day.date}: +$${day.inflows / 100} / -$${day.outflows / 100}`)
}The balance endpoint gives you a snapshot across all connected accounts:
curl https://developer.usepopup.com/api/v0/balance \
-H "Authorization: Bearer fc_live_your_key"
{
"data": {
"stripe": { "available": 234100, "pending": 89200 },
"bank": { "current": 1247800, "available": 1245300 },
"total_available": 1479400
}
}Step 6: Set up webhooks for real-time updates
Instead of polling the API, register a webhook to get notified when payouts match, when discrepancies are detected, or when a refund affects your reconciliation:
await fc.createWebhook({
url: "https://your-app.com/webhooks/flowcheck",
events: [
"payout.matched",
"payout.discrepancy",
"payout.missing",
"refund.detected",
"balance.threshold"
]
})Every webhook delivery is signed with HMAC-SHA256. Verify the FlowCheck-Signature header before processing.
What you did not have to build
At this point you have a working financial data layer. Here is what FlowCheck handled so you did not have to:
- Stripe payout sync with automatic backfill and ongoing polling
- Shopify order and payout sync with the same pattern
- Plaid bank transaction sync with soft-delete for removed transactions
- Amount normalization across cents (Stripe), dollars-negative-for-income (Plaid), and Shopify order amounts
- Reconciliation matching using a 100-point scoring model across amount, date, description, and bank account
- Discrepancy detection for missing deposits, amount mismatches, and timing anomalies
- Webhook infrastructure with HMAC signing, retry logic, and automatic endpoint disabling after repeated failures
All of that is code you would have written yourself, debugged across edge cases, and maintained as APIs change. Instead, you made six API calls and you are done.
Get started
Get an API key and connect your first data source. The sandbox is free and comes with test data so you can see real responses without connecting production accounts. The full API reference has examples for every endpoint.