Connect a User's HSA/FSA

Learn how to connect a user's HSA or FSA and retrieve their balance, activity, and deposit information.

Your application can use Sail to retrieve HSA and FSA account data, including balances, contributions, account activity, and deposit credentials. Sail connects to the user's HSA or FSA administrator and securely retrieves this information on your behalf.

In this guide, you'll connect a user to their HSA or FSA administrator through Sail's Connect widget, retrieve their account data, and optionally access their full account and routing numbers for deposits.

Requirements

Before you start, make sure you have:

  • A Sail user created for your end user
  • An API key with the benefit_account scope and the account_numbers scope (if you need deposit credentials)
  • A separate API key with the token_admin scope (needed to mint user tokens for PII access and full account number reveals)
📘

A token_admin key cannot hold other scopes, so you'll need at least two API keys: one for data access and one for minting tokens. See Scoped API Keys to understand why and how to set them up.

Step 1: Connect an HSA/FSA administrator

To pull account data, your end user needs to log into their HSA/FSA administrator. Create a Connect Widget session with connection_type set to benefit_account. Sail returns a single-use URL that you embed in your app as an iframe or redirect. The user enters their administrator credentials securely within Sail's Connect Account Widget.

curl -X POST https://live.savewithsail.com/api/v1/hosted-sessions \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "usr_abc123",
    "flow": "connect_account",
    "options": {
      "connection_type": "benefit_account"
    }
  }'

Open the url in an iframe or redirect your end user to it. The session is single-use and the expires_at field tells you when it stops working. You can check which administrators Sail supports through the List Administrators endpoint.

Step 2: Listen for webhooks

After your end user completes the login, Sail connects to the administrator and discovers the user's benefit accounts. Listen for these webhook events:

EventWhat it means
connection.createdYour end user finished the connect widget and the connection exists.
connection.status_changedThe connection moved to a new status (for example, syncing to active).
connection.syncedSync completed. The connection's data is ready to fetch.
connection.synced.initialInitial basic account info is available.
connection.synced.profileAccount profile data has been updated.
connection.synced.activityAccount activity has been updated.

When you receive connection.synced, the account data is ready to fetch. A single administrator login can hold multiple accounts (for example, an HSA and an LPFSA).

Step 3: Confirm accounts

Once the connection is active and accounts are discovered, you can read balances, contribution progress, account activity, and deposit credentials.

Fetch all benefit accounts for the user. Each account includes the account type, balance, and sync status.

curl https://live.savewithsail.com/api/v1/users/usr_abc123/accounts \
  -H "Authorization: Bearer sk_live_..."

Amounts are decimal numbers in USD (for example, 1050.50 means $1,050.50). The connection is now active and you can start reading account data.

Step 4: Read deposit credentials (optional)

Moving money into a user's account requires its account and routing numbers. Those are personally identifiable information, so Sail asks for a second credential on top of your API key. Skip this step if you only need balances and activity.

Mint an ephemeral user token with your token_admin key through Mint Ephemeral User Token, then send it alongside your data key. Tokens are short-lived, so mint one per workload and discard it rather than storing it.

curl -X POST https://live.savewithsail.com/api/v1/users/usr_abc123/tokens \
  -H "Authorization: Bearer sk_live_token_admin_..." \
  -H "Content-Type: application/json" \
  -d '{
    "ttl_seconds": 900,
    "scopes": ["numbers"]
  }'

With the token in hand, call Get Account & Routing Numbers for the masked version, which is safe to display and to poll.

curl https://live.savewithsail.com/api/v1/users/usr_abc123/accounts/acct_77b1/numbers \
  -H "Authorization: Bearer sk_live_..." \
  -H "x-sail-user-token: ut_test_p2m88xnq1"

To initiate an actual deposit you need the unmasked number, which comes from Reveal Full Account Number. That call needs a token minted with the numbers:reveal scope, every reveal is audit-logged and rate-limited per user, and the response is a one-time read. Don't store it unencrypted.

Next steps


Did this page help you?