comparison

A Plaid alternative that tells you exactly what it is.

FeelConnect is a meta-aggregation layer: one Link flow, one /v1 API, nine AI enrichment endpoints, eleven SDKs, and pricing you can read without a sales call. It routes to bank aggregators — Plaid among them — rather than pretending the agreements they require do not exist.

Read this before the comparison

FeelConnect does not hold bank connections of its own. Every institution in the catalog carries an ordered chain of connectors, and live traffic goes to the first one whose credentials are present in the deployment you are calling.

Some connectors an operator can switch on alone in minutes — GoCardless Bank Account Data (UK and EU banks, free self-signup under their PSD2 licence), Coinbase, Kraken, PayPal, public-address crypto wallets, and CSV / OFX / QFX import. Others need a signed business relationship before they will serve production data, including Plaid, MX, Finicity, Akoya, and Stripe Financial Connections. Where an institution has no enabled connector, a live call returns provider_error rather than pretending.

The sandbox is the exception and it is always on: test keys resolve to the simulated network regardless of credentials, so the full integration is buildable on day one. See going live for the provider-by-provider breakdown.

the difference

Five things that are genuinely different.

Each of these is a property of the platform you can check in the docs or in a sandbox key, not a positioning statement.

  • Published pricing, enforced by one file. Free, $99, $499, and a quoted Enterprise tier. Every quota on the pricing page — requests, AI requests, connected users, rate limit, webhook endpoints, team seats — is read from the same entitlements the API enforces, so the page cannot drift from the meter.
  • AI enrichment is an endpoint, not an add-on. 9 products live under /v1/ai/* on the same key and the same meter. They are rules-first: 526 deterministic descriptor rules and a 14-category / 89-subcategory taxonomy run always, and a model enhances the result when it is reachable. Every response says which engine produced it.
  • A routing layer, not a single upstream. 17 connectors, and each institution carries an ordered preference chain. Add a provider and the institutions that list it start using it — no data migration, no code change, no redeploy of logic.
  • 11 client libraries with one contract. TypeScript / Node, Link JS (browser), Python, Go, Rust, Java, Swift, Kotlin, Dart / Flutter, PHP, .NET — identical method groups, identical error envelope, identical webhook verification helper. See the SDK reference.
  • A sandbox with no approval queue. Sign up, copy an fc_sk_test_ key, and the whole flow works immediately: institution search, OAuth and MFA simulation, account selection, consent, and 24 months of deterministic history across all 9 products. Test keys always resolve to the sandbox, so you can keep building against stable data after you go live.

pricing, in numbers

The whole price list, on the comparison page.

Quoting our own limits here is the point: a comparison you cannot verify is marketing.

Source: src/lib/billing/plans.ts — the same entitlements the rate limiter and the monthly meter read.
PlanFree$0/moStartup$99/moGrowth$499/moEnterpriseCustom
API requests / mo10,000500,0005,000,000Unlimited
AI requests / mo1,00050,000500,000Unlimited
Connected users1005,00050,000Unlimited
Rate limit10 rps50 rps200 rps1000 rps
Live accessSandbox onlyYesYesYes

Rate limits burst to 3× for short spikes, quotas reset on the first of the month, and there is no overage billing — at the limit, requests return 429 rate_limit_error until the month rolls over or you upgrade. A usage.limit_approaching webhook fires before you get there. The full breakdown is on /pricing.

enrichment

You can use the enrichment without moving your aggregation.

Four AI products accept a raw transactions payload instead of an access token — which means you can evaluate them against your existing data before changing anything.

# Enrichment on data you already have. No item, no Link, no connection.
curl https://connect.feels.money/v1/ai/categorize \
-H "Authorization: Bearer $FEELCONNECT_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"transactions": [
{ "id": "t1", "description": "SQ *BLUE BOTTLE COFFEE OAK", "amount": 6.75 },
{ "id": "t2", "description": "COMCAST CABLE COMM", "amount": 89.99 }
]
}'

The response carries enginerules, ai, or ai+rules — so you always know whether a model was involved. If the model layer is unreachable the endpoints degrade to the deterministic engines instead of failing, and a rules-only response is metered identically. Details on the enrichment API page and in the AI reference.

meta-aggregation

One institution, an ordered chain of providers.

This is the architectural difference, and it is also the reason the coverage caveat above exists.

Chase, for example, carries the chain ["akoya", "finicity", "plaid", "sandbox"]. At connect time the registry walks that list and hands the session to the first connector whose credentials are present. With none configured it falls to the sandbox and behaves like a demo. Configure Akoya and every institution listing Akoya starts using it — the item ids, the access tokens, the cursors, and the response shapes are unchanged, because they belong to FeelConnect rather than to the upstream.

Test-environment keys always resolve to the sandbox regardless of what is configured, so your customers can develop against stable fake data while your live keys reach real banks.

institutions
938
with real logos
903
countries
61
connectors
17

Counted from the live catalog. Browse it at /institutions — every institution has a page showing its routing chain and which products each connector in that chain can serve.

about plaid, factually

Three things we will say about Plaid, and nothing else.

Only what is publicly documented and uncontroversial. We route to Plaid; disparaging it would be both dishonest and self-defeating.

  • Plaid’s sandbox is instant; production access is reviewed. Signing up gives you sandbox credentials immediately, while Production access requires a company profile and a use-case review. Our own going-live guide tells operators to budget days to weeks for it.
  • Plaid has the broadest US and Canadian coverage of the providers FeelConnect routes to. That is why the Plaid connector exists and why it appears in the preference chain of most US institutions in the catalog.
  • Enabling the Plaid connector makes you a Plaid customer. It calls Plaid’s own API with your credentials, under your agreement with them. FeelConnect is not a reseller of Plaid and is not affiliated with, endorsed by, or sponsored by Plaid. Plaid is a trademark of Plaid Inc.

migration

The shapes will look familiar.

FeelConnect deliberately speaks the idiom the ecosystem already learned: POST with a JSON body, cursor-based transaction sync, and positive amounts for money leaving the account.

Node
// The sync loop has the shape you already wrote once.
let cursor: string | undefined = await loadCursor(itemId);
for (;;) {
const page = await fc.transactions.sync({
access_token: accessToken,
cursor,
count: 500,
});
await applyChanges(page.added, page.modified, page.removed);
cursor = page.next_cursor;
await saveCursor(itemId, cursor); // persist after applying the page
if (!page.has_more) break;
}
What you are movingWhat it becomes
Client credentialsOne bearer secret key per application and environment: fc_sk_test_… or fc_sk_live_…. Keys are stored as SHA-256 hashes with a display prefix and last four.
Link initializationPOST /v1/link/token/create returns a 30-minute link_token; FeelConnect.open({ linkToken }) from @feelconnect/link renders the modal.
Token exchangePOST /v1/link/token/exchange turns the public_token into a persistent access_token plus an item_id.
Incremental transactionsPOST /v1/transactions/sync returns added, modified, removed, next_cursor, and has_more. Cursors are opaque and item-scoped; persist one per item.
Amount conventionPositive is money out, negative is money in, in major units with an iso_currency_code beside it. Dates are YYYY-MM-DD strings.
Error handlingNon-2xx responses carry { error: { type, code, message, request_id } }. See errors and rate limits.
Change notificationsSigned webhooks with FC-Signature: v1=hex(hmacSHA256(secret, "ts.body")), a five-minute timestamp window, and retries at 0s, 1m, 5m, 30m, and 2h.

faq

Questions developers actually ask.