Connection Flow Fundamentals
Concepts

Connection flow fundamentals

How BillerAPI links your users to their biller accounts.

A BillerAPI integration has two components. The first is end-user biller account linking, which your users complete through the hosted Elements flow. The second is data retrieval — reading bills and insights on the accounts your users have linked.

The lifecycle below walks a single connection from the moment your user taps Connect a biller to the moment bills and webhook events start arriving. Each stage names the actor responsible for it: your client, your server, or BillerAPI.

Client

Your web or mobile app. Initiates linking and opens the hosted Elements flow. Never handles biller credentials.

Stages 2 · 3
Your server

Holds your API key. Creates link tokens, exchanges the public token, and stores the resulting access token.

Stages 1 · 4 · 5
BillerAPI

Hosts the connect flow, authenticates the user with their biller, retrieves bills, and delivers webhook events.

Stages 1 · 3 · 4 · 5

Connection lifecycle

Five stages, in order. Stages 1 and 4 run on your server with your API key; stages 2 and 3 run in the browser; stage 5 is ongoing.

Stage 01 · Server-side

Create a link token

Your server

Your user initiates biller linking on your client. Your client calls your backend, and your backend creates a link token with POST /v1/link-tokens, passing client_user_id, an optional biller_id, and the consents your use case requires. Return the resulting link_token to your client.

POST /v1/link-tokens
JavaScript
const response = await fetch('https://sandbox.api.billerapi.com/v1/link-tokens', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer $BILLERAPI_API_KEY',
  },
  body: JSON.stringify({
    client_user_id: 'user_123',
    biller_id: 'sb_utility',
    consents: ['bills:read'],
  }),
});
const { link_token } = await response.json();

Link tokens expire after 30 minutes

Create one per link attempt, hand it straight to the client, and never cache or reuse it. An expired or reused token fails the flow.
Stage 02 · Client-side

Open Elements

Client

Initiate the hosted flow with elements.connect({ linkToken, onSuccess, onExit }) from billerapi-js. Elements renders in an overlay on your page — your app keeps the surrounding experience, BillerAPI owns everything inside the frame.

Initialize and open Elements
JavaScript
import { BillerApiElements } from 'billerapi-js';

const elements = new BillerApiElements({
  clientId: 'your_client_id',
  environment: 'sandbox',
});

const handler = elements.connect({
  linkToken,
  onSuccess: async (publicToken, metadata) => {
    // send publicToken to your server for exchange
  },
  onExit: (error) => { if (error) console.error(error.code); },
});
handler.open();
Stage 03 · Hosted by BillerAPI

Your user completes the hosted flow

BillerAPI

Inside the frame, the user selects their biller, reviews and grants the consent scopes, picks a service region if that biller is region-gated, authenticates with the biller, clears MFA if required, and confirms which discovered accounts to link. When the flow finishes, onSuccess fires with a public_token.

Connect a biller

Find your biller

Search supported billers

spring
SUSpringfield UtilityELECTRIC · IL
SWSpringfield WaterWATER · IL
SBSpring BroadbandINTERNET · US
Continue
01 · Select biller
Connect a biller

Share your bill data

Springfield Utility → Acme App

BillsAmounts, due dates, statementsbills:read
Account detailsBiller name, masked account, status
Agree and continue
02 · Consent
Connect a biller

Log in to Springfield Utility

Entered here only — never sent to Acme App

Username
jordan@example.com
Password
••••••••••••
Verify (MFA) — if your biller asks, we'll prompt for a one-time code next.
Log in
03 · Credentials
Connect a biller

Choose accounts to link

2 accounts found at Springfield Utility

Electric••••4242
Gas••••8811
Link account
04 · Select accounts
Connect a biller
Account linked
Springfield Utility
Account••••4242
Done
05 · Success

The most common path. Region selection appears between consent and credentials for region-gated billers, and an MFA or security-question step appears after login when the biller requires one.

The full sequence, including every conditional step, is listed in Inside the hosted flow.

Sandbox test credentials

Account number 4242424242 with any username and password always succeeds — that is the happy path, with no challenge screens. To exercise MFA, use 4000000003 and enter code 123456 when the flow prompts. The full set of magic account numbers, including the error and multi-account scenarios, is in the Getting Started sandbox reference.

Credentials never reach your servers

Biller usernames, passwords, one-time codes, and security-question answers are entered inside the hosted flow only. Your application never sees, transmits, or stores them.
Stage 04 · Server-side

Exchange the public token

Your server

Send the public_token to your backend and exchange it with POST /v1/link-tokens/:public_token/exchange. You get back an access_token, the biller_id, and an account_link_id — store the last two against your user.

POST /v1/link-tokens/:public_token/exchange
JavaScript
const exchange = await fetch(
  `https://sandbox.api.billerapi.com/v1/link-tokens/${encodeURIComponent(publicToken)}/exchange`,
  { method: 'POST', headers: { Authorization: 'Bearer $BILLERAPI_API_KEY' } },
);
const { access_token, biller_id, account_link_id } = await exchange.json();

The link session that produced the token is readable for auditing and support:

The link_session object
JSON
{
  "id": "ls_9f2c41d8a7b3",
  "object": "link_session",
  "client_user_id": "user_123",
  "biller_id": "sb_utility",
  "consents": ["bills:read"],
  "status": "succeeded",
  "account_link_id": "al_5e8d02c9f1a4",
  "expires_at": "2026-08-23T18:30:00Z"
}
Stage 05 · Ongoing

Read bills and receive webhooks

BillerAPI

With an account_link_id you can fetch bills for the linked account at any time.

HTTP
GET /v1/bills?account_link_id=al_5e8d02c9f1a4
Authorization: Bearer $BILLERAPI_API_KEY

Linking is only half synchronous. Everything that happens after the flow closes — the connection settling, new statements arriving, a link going stale — is delivered asynchronously by webhooks. Subscribe to the events your integration needs:

link.connectedbill.createdlink.disconnected

Don't poll for the first bill

Bills are retrieved after the flow closes, so an immediate GET /v1/bills can return an empty list. Wait for bill.created. See Webhook Delivery for signature verification and retry semantics.

Inside the hosted flow

These are the steps your user moves through inside the Elements modal, in order. Steps adapt to the biller and to the session — only region-gated billers show the region step, a biller without MFA skips verification, a single-account biller skips account selection, and update or repair sessions skip consent.

StepDescription
1Select billerUser searches or picks their biller from supported billers.
2Provide consentUser agrees to share the requested data (consent scopes shown). Skipped in update/repair mode.
3Select regionShown only for region-gated billers (for example Eversource CT/MA/NH). It sits between consent and credentials, because the region decides which login the biller presents.
4Log in to billerUser authenticates with their biller credentials.
5Verify (MFA)Only if the biller requires it: one-time code or security question.
6Select accountsUser picks which discovered accounts to link — this is the confirm-link step.
7SuccessConfirmation screen; the flow returns control to your app.

Data permissions

Consent scopes decide what BillerAPI may read on a linked account. They are requested on the link token and shown to the user on the consent step.

DataScopeDescription
Billsbills:readBill amounts, due dates, statement PDFs on linked accounts.
Account detailsgranted on linkBiller name, masked account identifier, link status.
Insightsderived from linked dataUsage and payment insights computed from linked accounts, where enabled. No separate scope is requested.

Request only the scopes your use case needs. Users see the requested scopes on the consent step and must re-link to expand them.

How BillerAPI authenticates

Credentials are entered in the hosted flow only. Biller usernames and passwords are collected inside the Elements frame and never touch your servers — you never receive, proxy, or store them.

Region selection precedes the login, not the biller choice. A small number of billers serve several regions under one brand (Eversource CT/MA/NH, for example). For those, the hosted flow inserts a region step after consent and before credentials, because the region determines which login form the biller presents. Every other biller goes straight from consent to credentials.

MFA and security questions are handled inline. When a biller challenges the login with a one-time code or a security question, the hosted flow prompts the user in place and continues the session once it clears. No callback into your application is required.

Sandbox has a deterministic credential. Account number 4242424242 with any username and password always succeeds, so you can build and test the entire lifecycle before you have a real biller account.

Was this page helpful?