Connect an Account

Open Sail's Connect Account Widget with a hosted session, so your end user can connect a store, card, or HSA/FSA account.

Your end user connects an account through Sail's Connect Account Widget, a single-use URL that opens a Sail-rendered login screen. A hosted session is the API object behind both of Sail's widgets. Its flow value tells Sail which one to open. The connect_account and reconnect flows open the Connect Account Widget. The upload_receipt flow opens the Upload Receipt Widget. This guide shows how to open the widget, know when the connection is ready, and reconnect it when the user's credentials stop working.

Your end user enters their login only inside Sail's iframe, so their credentials never touch your servers. Sail stores them, and your backend keeps using your partner API key for every other call.

Requirements

Before you start, make sure you have:

  • A Sail user created for your end user.
  • An API key with the scope that matches the connection type: expenses for a store or card connection, or benefit_account for an HSA/FSA connection.
  • A webhook endpoint configured to receive events.

Step 1: Choose the connection type

The connection_type you send decides which login screen your end user sees. See Account Connections for what each type produces.

connection_typeYour end user logs intoUsed by
storeA store account, such as Amazon or WalgreensThe Itemize Transaction API
benefit_accountAn HSA/FSA administrator, such as HealthEquityThe Connect HSA/FSA API
cardA bank account or credit or debit cardThe Connect HSA/FSA API, to bring in the card purchases a reimbursement pays back

To skip the selection screen and open one login directly, you also pass an ID in options. Use merchant_id with store, from List Merchants, or administrator_id with benefit_account, from List HSA/FSA Administrators. If your end user already has a connection for that store or administrator, the request returns 409 conflict.

Step 2: Create the session

Call Create Hosted Session from your backend with the user's id, flow set to connect_account, and the connection_type from Step 1. The example below opens Walgreens directly.

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": "store",
      "merchant_id": "mer_walgreens"
    }
  }'

Save the url and expires_at. The URL works once, and it stops working at expires_at.

Step 3: Open the widget for your end user

Open the url in an iframe inside your app, or redirect your end user to it. To show the widget as an overlay instead of a full page, set modal to true in options when you create the session.

When modal is false, you style the window around the widget yourself, and your app receives two postMessage events from it:

EventSail sends it whenPayload
sail:completeThe flow finishes or is closedtype, entryPoint, userId, timestamp
sail:errorSetup fails before the flow appears, with errorCode set to connection_failedtype, entryPoint, timestamp, errorCode, message

sail:complete doesn't say whether the connection worked, because its payload has no result field. Close the window and wait for the webhook in Step 4.

If the session expires before your end user finishes, create a new session and open the new url.

Step 4: Wait for the connection to be ready

After your end user logs in, Sail connects to the account and syncs its data. This can take minutes for a store, because Sail retrieves the order history. Results arrive by webhook, so there's nothing to poll.

Fetch the data once you receive connection.synced. Its flags (balances_updated, activity_updated, expenses_updated) tell you which kinds of data moved.

📘

Check the Sail-Signature header before you process any event. Delivery is at-least-once, so deduplicate on the event id. See Receiving New Data for both.

What you fetch depends on the connection type. For a store or card connection, you read expenses. For an HSA/FSA connection, you read accounts and balances. Each product's quickstart shows that call:

Step 5: Reconnect when the login stops working

A connection stops syncing when your end user's credentials go stale, for example after a password change. To find out, check the connection's status with Get Connection. A status of user_input_required or error means your end user needs to log in again.

To let your end user log in again, create a session with flow set to reconnect and the existing connection_id in options. Sail keeps the same connection, so you don't create a new one.

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": "reconnect",
    "options": {
      "connection_id": "conn_8e3a"
    }
  }'

Two cases return an error instead of a URL. An external connection has no login to refresh, so it returns 409 connection_not_reconnectable. A connection that is still syncing returns 409 conflict, so wait for the sync to finish and try again.

Next steps


Did this page help you?