Skip to content

The hosted connect flow

The hosted flow is how your users connect their bank: you create a connect session on your backend, send the user to the returned hostedUrl, and we take it from there — bank picker, consent, the bank's own OAuth, progress, and the redirect back to you. Your API key never touches the user's device, and the bank sees a real browser (banks block embedded WebViews).

Connect flow sequence

  1. Your backend creates a session: POST /v1/connect-sessions with the returnUrl this user should land on.
  2. You open hostedUrl — as a web redirect, or via the iOS / Android Link SDKs.
  3. The user picks a bank (skipped if you set providerId), sees the consent info, and is redirected to the bank's OAuth.
  4. Back from the bank, a progress screen tracks the data download; if account selection is enabled for you, the user can deselect accounts here.
  5. The user is redirected to your returnUrl with the result, and your backend receives the authoritative events as webhooks.

Connect sessions

sh
curl -X POST https://partner.bbapi.io/v1/connect-sessions \
  -H "X-Api-Key: {{BB_API_KEY}}" \
  -H "X-Client-Id: <clientId>" \
  -H "Content-Type: application/json" \
  -d '{ "returnUrl": "https://app.example.com/bb-callback" }'
json
{
  "sessionId": "cs_9c1e…",
  "hostedUrl": "https://aisp-connect.bbapi.io/s/<one-time-token>",
  "expiresAt": "2026-07-15T10:35:00Z"
}
  • The hostedUrl token is one-time — the first load consumes it. Hand it to the user immediately and never reuse it.
  • expiresAt is the single expiry to honor. An expired session ends in the Expired state with a friendly screen; just create a new session.
  • POST /v1/connect-sessions accepts an Idempotency-Key header — a retry with the same key replays the original response instead of minting a second session.
  • Optional fields: locale (UI language), country (preselects the bank picker's country), providerId (skips the picker entirely).

Track the session from your backend:

sh
curl https://partner.bbapi.io/v1/connect-sessions/<sessionId> \
  -H "X-Api-Key: {{BB_API_KEY}}" \
  -H "X-Client-Id: <clientId>"
Session stateMeaning
AwaitingBankSelectionuser is in the bank picker
RedirectedToBankhanded off to the bank's OAuth
Authenticatinguser is authenticating at the bank
Fetchingaccounts and transactions are downloading
AwaitingAccountSelectionuser is choosing which accounts to keep
Completedterminal — connectionId is set
Failedterminal — see the failure webhook for the reason
Cancelledterminal — user cancelled
Expiredterminal — session outlived expiresAt

The return redirect

The final redirect to your returnUrl appends connectionId, resultCode (Ok | Error | Cancelled), sessionId, and error on failure.

Two rules keep integrations robust:

  • returnUrl is allowlisted. The portal (Apps → return URLs) holds your registered patterns — web URLs, iOS universal links, Android app links, custom schemes. Each session passes the concrete URL for this user; it must match a registered pattern or the create fails with validation_error.
  • The redirect is a UX signal, not the result. Users close tabs and switch apps mid-flow; the redirect may never arrive. The authoritative outcome is the session state and the webhooks (ConnectionCreateSuccess / ConnectionCreateFailed).

Account selection

If account selection is enabled for your integration, users see the accounts covered by their bank consent all pre-selected and can only deselect — the selection can never exceed what the bank authorized. Deselected accounts end unsubscribed: they exist on the connection but are excluded from your subscribed view. You can flip subscriptions later via PATCH /v1/accounts/{id}/subscribe and DELETE /v1/accounts/{id}/subscribe.

Connection lifecycle

A successful flow produces a connection — the durable link to one bank consent. It moves through four states:

StateMeaningRecovery
Pendingtransient during creation — never a resting state
Activeauthorized, consent valid
Inactiveconsent expired or revoked, or refreshes kept failingreconnectActive
Disabledthe flow never completed (consent never obtained)none — create a new connection
  • Consent expiry and revocation arrive as ConnectionConsentExpired / ConnectionConsentRevoked webhooks and flip the connection to Inactive.
  • Reconnect (POST /v1/connections/{id}/reconnect) repeats the bank authorization for an Inactive connection and keeps the same connectionId — your account and transaction history stay attached.
  • Reconnecting a Disabled connection is rejected; start a new connect session instead.

Refresh never redirects

POST /v1/connections/{id}/refresh fetches new transactions in the background and returns 202 Accepted — there is nothing to show the user. If the bank demands re-authentication, the refresh fails, the connection goes Inactive, and reconnect is the recovery path. Refreshes are also guarded by a cooldown and per-day quotas — handle refresh_cooldown, refresh_in_progress, and refresh_quota_exceeded per the error reference.