enterprise

Your provider account. Your compliance agreement. Our layer.

Most platforms make you connect through their aggregator relationship, which means their agreement, their invoice and their risk appetite govern your product. FeelConnect is built the other way around: bring your own Plaid, Teller or Enable Banking account and keep the relationship, while we handle Link, normalization, enrichment, webhooks and the SDKs.

bring your own provider account

The integration stops being the thing you renegotiate.

Institutions carry an ordered routing chain, and the registry uses the first provider whose credentials are present. Swapping, adding or removing a provider is a configuration change — endpoint paths, request bodies, response shapes, webhook payloads and cursors are all ours, not the upstream's.

Teller

US

US banks and credit unions, mutual-TLS authenticated. Free developer tier up to 100 live connections; paid above that

Free self-serve signup — you can hold this credential today.

Enable Banking

UK / EU

UK, EU and Nordic institutions under Enable Banking's own PSD2 licence. Free Restricted Production reads only accounts you whitelist; serving other people's accounts needs their full production activation

Free self-serve signup — you can hold this credential today.

Plaid

US / CA

Broad US and Canadian retail bank coverage. Sandbox is instant; production needs a company profile and use-case review

Requires an agreement signed by your legal entity.

Shipped

  • Per-org credential storage exists in the schema: ProviderCredential carries an orgId, and a null orgId means the platform's own credential.
  • Every connection records the credential set that authorised it (Item.credentialOrgId), so a connection keeps talking to the provider account it was made with even if credentials change later.
  • Credentials are encrypted at rest with AES-256-GCM and never returned in plaintext — the console only ever learns that a key is set and its last four characters.
  • A credential present in the environment always wins over a stored one and shows as read-only, so secrets managed by a file or a secrets manager cannot be overridden through a web UI.

In active rollout

  • Credential resolution is still deployment-wide: the registry reads the environment first, then the stored value, without yet narrowing by org.
  • Because of that, bringing your own provider account is an onboarding we run with you — we configure and verify your credentials against the provider's live API and confirm which institutions became connectable — rather than a self-serve toggle in the dashboard.

Onboarded customers are configured and verified by us against the provider's live API, and we confirm exactly which institutions became connectable before you build on it.

controls

Mechanisms, not badges.

Every line below describes something implemented in the source. None of it is a certification, because there isn't one — and a security page that blurs that distinction is the first thing worth distrusting.

  • AES-256-GCM at rest

    Upstream provider tokens, FeelConnect access tokens, webhook secrets and TOTP seeds are encrypted with a 32-byte key supplied as FC_ENCRYPTION_KEY. Without it the app derives a development key and says so loudly in the logs.

  • Keys stored as hashes

    Secret keys and access tokens are kept as SHA-256 lookup hashes with a display prefix and last four. A database read cannot reconstruct a working credential.

  • Signed, replay-windowed webhooks

    Every delivery carries FC-Timestamp and FC-Signature: v1=hex(hmacSHA256(secret, "${ts}.${rawBody}")). Deliveries more than 300 seconds old are rejected. The Node SDK ships the verifier.

  • Role-based access in the console

    Four roles — owner, admin, developer, viewer — gate ten distinct actions including key creation, key revocation, webhook management and audit reads.

  • Audit log

    Org-scoped, append-only rows recording actor, action, target, metadata and source IP, indexed by org and time.

  • Environment separation

    A key's environment is part of the key. Test keys always resolve to the sandbox regardless of which provider credentials exist, so nobody reaches production data from a development branch.

Webhooks are verifiable, not just delivered. Every event carries FC-Webhook-Id, FC-Timestamp and FC-Signature: v1=…, an HMAC-SHA256 over ${timestamp}.${rawBody}. Deliveries older than 300 seconds are rejected, so a captured payload cannot be replayed at you later.

Failed deliveries retry 5 times — immediately, then 1m, 5m, 30m, 2h — and every attempt is recorded against the endpoint so you can see what we sent and what your server said. The Node SDK ships the verifier so you are not re-implementing an HMAC comparison in a hurry.

  • link.session_finished
  • item.connected
  • item.error
  • item.removed
  • transactions.initial_update
  • transactions.sync_updates_available
  • recurring.updated
  • holdings.updated
  • usage.limit_approaching
tsapp/api/webhooks/feelconnect/route.ts
import { verifyWebhook } from "@feelconnect/node"; export async function POST(req: Request) {  const raw = await req.text();   // Throws on a bad signature or a timestamp outside the tolerance window,  // so a replayed or forged delivery never reaches your handler.  const event = verifyWebhook({    rawBody: raw,    signatureHeader: req.headers.get("FC-Signature"),    timestampHeader: req.headers.get("FC-Timestamp"),    secret: process.env.FEELCONNECT_WEBHOOK_SECRET!,  });   switch (event.type) {    case "item.connected":      await onConnected(event.data);      break;    case "transactions.sync_updates_available":      await enqueueSync(event.data);      break;  }   return new Response(null, { status: 204 });}

private deployment

The same build, inside your perimeter.

There is no per-customer fork and no hidden control plane. Connectors activate from environment variables, so a private install differs from ours only in which variables are set.

bashdocker-compose
# The whole platform, on your infrastructure.# Postgres, FeelConnect and the reference consumer app.git clone <your-fork> && cd feelsmoneycp .env.example .env            # provider credentials, encryption keys, SMTP docker compose --profile full up -d --build # FeelConnect on :4101, the reference app on :4100, Postgres on :5460.# Two databases on one server: feelconnect and feelsmoney.

Compose brings up Postgres and both applications. The platform and the reference consumer app use two databases on one server, which keeps a restore of one from touching the other.

In your infrastructure it is your database, your encryption keys, and your provider credentials. Outbound traffic goes only to the providers you enabled — and if you enable none, manual CSV/OFX/QFX import and public-address crypto still work for real, with no third party involved at all.

Institution logos are served from your own origin rather than a third-party CDN, deliberately: a CDN would learn every user's IP address and which bank they were about to connect.

what we'd need from you

The actual list, with the actual variable names.

Nothing here is a discovery call in disguise. These are the credentials each provider issues, in the exact shape our configuration reads them — take the list to your vendor manager before you talk to us.

Start with the two you can sign up for yourself

Not every provider needs a sales cycle. These have free or no-credential tiers you can complete without talking to anyone, and the counts are how many catalogue institutions route to each — routing, not a live-coverage promise, since an institution becomes connectable when its provider's credentials exist.

Teller
336
Every US bank and credit union in the catalogue, Chase and Bank of America included
SimpleFIN
337
The same US institutions, behind Teller in every chain — no platform credential at all
Enable Banking
191
UK, EU and Nordic institutions, ahead of GoCardless in every chain
Akahu
5
New Zealand banks — nothing else in the catalogue reaches them

Teller and Enable Banking together put 526 institutions within reach on free tiers. GoCardless Bank Account Data has closed new registrations — existing secrets still work, which is one more reason bringing your own credentials matters.

  • Teller — US, self-serve

    • TELLER_APPLICATION_ID
    • TELLER_CERT
    • TELLER_KEY
    • TELLER_ENVIRONMENT

    Free developer tier: 100 live connections, no card, no sales call. Every API call is authenticated with mutual TLS, so the application id alone is not enough — send the certificate and private key whole, BEGIN and END lines included. Leave the environment blank for the free development tier, which is real bank data.

  • Enable Banking — UK/EU, self-serve

    • ENABLE_BANKING_APPLICATION_ID
    • ENABLE_BANKING_PRIVATE_KEY

    Free Restricted Production under their PSD2 licence, so you inherit their permission rather than needing your own AISP authorisation. Restricted Production reads only accounts you whitelist yourself; serving other people's accounts needs their full production activation, which is a contract. The credentials do not change when that lands.

  • SimpleFIN — US, no platform credential

    • SIMPLEFIN_ENABLED

    One flag is the entire platform-side setup. Each end user runs their own SimpleFIN Bridge (about $15 a year, paid by them) and pastes a one-time setup token into Link. Nothing to register, nothing to sign.

  • Akahu — NZ, self-serve

    • AKAHU_APP_TOKEN
    • AKAHU_APP_SECRET

    Free for personal use, and the only route to New Zealand banks in the catalogue. Akahu requires identity verification and 2FA before issuing app credentials, so allow more than ten minutes.

  • Coinbase — self-serve

    • COINBASE_CLIENT_ID
    • COINBASE_CLIENT_SECRET

    An OAuth application you register in about five minutes, with the wallet:accounts:read and wallet:transactions:read scopes.

  • PayPal — self-serve

    • PAYPAL_CONNECT_ENABLED

    Reading a PayPal balance is a different product grant from taking PayPal payments: the app needs Log In with PayPal and Transaction Search enabled. The connector stays hidden until the flag is set, so nobody is offered a button that dead-ends.

  • Plaid — US/CA, business agreement

    • PLAID_CLIENT_ID
    • PLAID_SECRET
    • PLAID_ENV

    Sandbox keys are instant. Production needs a company profile and a use-case review, days to weeks, and is billed to you per connected item.

  • Akoya — US, business agreement

    • AKOYA_CLIENT_ID
    • AKOYA_SECRET

    Sales-led, token-based, no credential sharing — the cleanest model for the largest US banks. Chase, Bank of America and Wells Fargo route to Akoya first in our catalogue.

  • Finicity (Mastercard) — US, business agreement

    • FINICITY_PARTNER_ID
    • FINICITY_APP_KEY
    • FINICITY_PARTNER_SECRET

    Sales-led. Strong for income and asset verification if you are underwriting.

  • MX — US, business agreement

    • MX_CLIENT_ID
    • MX_API_KEY

    Sales-led, enterprise pricing. US banks and credit unions.

  • Stripe Financial Connections — US, business agreement

    • STRIPE_FC_SECRET_KEY

    The fastest of the sales-led US options if you already run Stripe — enable Financial Connections on your existing account.

  • Wise — business agreement

    • WISE_CLIENT_ID
    • WISE_CLIENT_SECRET

    API access on a Wise business account.

  • GoCardless — existing holders only

    • GOCARDLESS_SECRET_ID
    • GOCARDLESS_SECRET_KEY

    Bank Account Data has closed new registrations. Existing secrets still work and still cover UK and EU banks, so bring yours if you have one — but if you do not, use Enable Banking instead. UK and EU institutions list GoCardless behind it as a fallback.

Deployment values

  • Encryption keys

    • FC_ENCRYPTION_KEY
    • FM_ENCRYPTION_KEY

    Real 32-byte values (openssl rand -base64 32). Rotating them later means re-encrypting stored provider tokens, so set them before the first real connection.

  • Background work

    • CRON_SECRET

    Point a scheduler at GET /api/internal/cron every 5–15 minutes. It drives webhook retries and stale-item refresh, and fails closed when the secret is unset.

  • Outbound email

    • SMTP_HOST
    • SMTP_PORT
    • SMTP_USER
    • SMTP_PASS
    • EMAIL_FROM

    Any transactional provider with SPF and DKIM on your sending domain.

  • OAuth redirect URIs

    • https://<your-host>/link/callback/<connector>

    Register this exact shape with each provider. Bank consent pages cannot render in a frame, so Link hands off to a popup and resumes when the bank returns the user.

how onboarding runs

Four steps, and you can start step one today.

Build against the sandbox
01

Free plan, no card, no approval. The whole integration is written and reviewed before any agreement exists.

Scope providers with us
02

Which institutions and countries you need decides which providers you pursue. Two of them — Teller for the US, Enable Banking for the UK and EU — are free self-serve signups you can complete this afternoon.

We configure and verify
03

Credentials are stored encrypted and checked against each provider's live API — you are told in the provider's own words whether it worked, and POST /v1/institutions/coverage reports how much of the catalogue live keys now reach.

Switch keys to live
04

Enable live access on the application, create a live key, point the integration at it. Same endpoints, same shapes.

due diligence

The questions that decide it.

Tell us which institutions you need. We'll tell you what it takes.

Including when the answer is that a free self-serve provider already covers you and you do not need an Enterprise agreement at all.

You can also read the published plans first — most teams never need to talk to us.