Search documentation
Fuzzy search across every docs page and section
Getting startedLink
Fuzzy search across every docs page and section
Getting startedLink
Getting started
Embed the FeelConnect Link modal: SDK options, lifecycle callbacks, postMessage protocol, and update mode for re-authentication.
Link is the user-facing connection flow: institution search, authentication (OAuth simulation, credentials, wallet address, or file upload), optional MFA, account selection, and consent. It renders as an iframe modal your page opens with a link_token.
npm install @feelconnect/link
Create a link_token server-side (reference), then open the modal. The vanilla API returns a handle; the React hook manages the handle's lifecycle for you.
import { useFeelConnectLink } from "@feelconnect/link";const { open, ready, exit } = useFeelConnectLink({linkToken,onSuccess: (publicToken, metadata) => exchangeOnServer(publicToken),onExit: (error) => error && report(error),onEvent: (name, data) => analytics.track("link_" + name, data),});// <button onClick={open} disabled={!ready}>Connect</button>
linkTokenstringrequiredPOST /v1/link/token/create. One token, one session.onSuccess(publicToken, metadata) => voidrequiredpublicToken server-side within 30 minutes. metadata carries the institution and selected accounts.onExit(error | null) => voiderror is null on a plain cancel, or { code, message } after a failure.onEvent(name, data?) => voidoriginstring{"institution": {"id": "inst_meridian_trust","name": "Meridian Trust"},"accounts": [{"id": "acct_9hK2mQxP7cW1nR4tYb8s","name": "Everyday Checking","mask": "4821","type": "depository"},{"id": "acct_5tGb2VnM8kQ4wZ1xLp0d","name": "Cashback Card","mask": "0093","type": "credit"}]}
{"code": "INSTITUTION_DOWN","message": "This institution is temporarily unavailable."}
A completed session walks these steps; onEvent fires at each transition:
user_mfa in sandbox) requires it.link_token are shown and granted.The SDK and iframe communicate with origin-checked postMessage events. You normally never touch these — the SDK maps them onto callbacks — but they matter if you build your own wrapper:
| Message | Direction | Payload |
|---|---|---|
fc:ready | iframe → parent | Link UI has loaded; the modal becomes visible. |
fc:event | iframe → parent | { name, … } telemetry, surfaced through onEvent. |
fc:success | iframe → parent | { public_token, metadata }, surfaced through onSuccess; the SDK closes the modal. |
fc:exit | iframe → parent | { error? }, surfaced through onExit. |
When an institution invalidates credentials, the item's status becomes login_required and you receive an item.error webhook. Reconnect the same item — keeping its item_id, accounts, and cursors — by creating a link token with update_item_id:
curl https://api.feelconnect.dev/v1/link/token/create \-H "Authorization: Bearer $FEELCONNECT_SECRET_KEY" \-H "Content-Type: application/json" \-d '{"user":{"client_user_id":"user-123"},"products":["transactions"],"update_item_id":"item_7dJ3nWqZ5xC9vK1mTf4g"}'
active and a transactions.sync_updates_available webhook follows. Your stored access_token keeps working — update mode needs no exchange, so you can ignore the public_token from onSuccess.access_token is rotated: the response carries rotated: true and the previous token stops working immediately, so replace every stored copy.update_item_id must belong to the same client_user_id, otherwise user_mismatch is returned./v1/sandbox/item/reset_login.