Collecting PSD2 Banking Data

This guide explains how to collect PSD2 Account Information Service (AIS) data — checking accounts, savings accounts, credit cards, balances, and transactions — using the Insurely API.

You will learn:

  1. How users, sessions, consents, and collections work together for PSD2 data collection
  2. Two collection modes: one-time and consent-based (reusable)
  3. Step-by-step API call sequences with request/response examples

Prerequisites

All examples use the 2026-04-01 API version — include the Insurely-Version: 2026-04-01 header in every request.

Overview

PSD2 data collection involves four core concepts: Users, Sessions, Consents, and Collections.

  • User — Created once per individual. Maps your externalId to a userUuid in Insurely.
  • Session — Created per interaction window. Provides a JWT that scopes operations to a user.
  • Consent (consent-based only) — Created once per bank. Stores PSD2 authorization, reusable for multiple collections until expired or revoked. User authenticates with BankID once during consent creation.
  • Collection — A single data fetch returning accounts, balances, and transactions. In the one-time flow, the user authenticates with BankID during the collection itself.

Authentication model

MethodHeaderUsed For
API keyauthorization-tokenBackend-to-backend: creating users, sessions, querying collections/consents per user
JWT session tokenAuthorization: Bearer <JWT>User-scoped: creating consents, polling consent status, starting collections

Key distinction

Consent endpoints (/consents/*) require JWT authentication. Collection endpoints (/collections/*) accept both API key and JWT.

User management

The User API lets you create and manage users that map to individuals in your system. Each user is identified by an externalId (your own identifier) and receives a userUuid within Insurely.

Create a user — Call POST /users with an externalId that maps to your internal user identifier. You receive a UserResponse containing the userUuid.

Request
curl -X POST https://api.insurely.com/users \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01" \
  -H "Content-Type: application/json" \
  -d '{ "externalId": "your-internal-user-id" }'
Response
{
  "userUuid": "abc-123",
  "externalId": "your-internal-user-id",
  "anonymized": false,
  "createdAt": "2026-03-05T10:00:00Z",
  "updatedAt": "2026-03-05T10:00:00Z"
}

Create a session — Call POST /users/{userUuid}/sessions to obtain a JWT token. The SessionResponse includes the token and its expiresAt timestamp.

Request
curl -X POST https://api.insurely.com/users/abc-123/sessions \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01"
Response
{
  "token": "eyJhbG...",
  "userUuid": "abc-123",
  "expiresAt": "2026-03-05T12:00:00Z"
}

Use the JWT for user-scoped calls — Pass the JWT as Authorization: Bearer <JWT> when creating consents, starting collections, or polling statuses.

You can look up an existing user by their externalId using GET /users?externalId=..., or retrieve a user directly by userUuid using GET /users/{userUuid}. To delete a user, call DELETE /users/{userUuid} — this anonymizes the user by setting externalId to null.

A consent represents explicit PSD2 user authorization. It is created via POST /consents and its status is polled via GET /consents/{consentId}/status.

INITIATED → AWAITING_AUTHORIZATION → AUTHORIZED
                                   → FAILED
                                   → EXPIRED (after expiresAt)
                                   → REVOKED (via revoke endpoint)

The CreateConsentRequest specifies the company, loginMethod, and parameters including a Psd2AisConsentParameter defining the scope (accountIds, balances, transactions) plus PSD2-required fields (psuIpAddress, optional psuLocale, optional validUntil).

During AWAITING_AUTHORIZATION, the ConsentStatusResponse includes authInstructions — either a SwedishBankIdQr with qrCodeData (for QR code flow) or a SwedishBankIdAutostartToken with autoStartToken (for same-device flow). The pollingInterval field (milliseconds) indicates how often to poll.

Once AUTHORIZED, the consent can be used to start one or more collections until it expires or is revoked via DELETE /consents/{consentId}.


Two Ways to Collect PSD2 Data

Option A: One-Time Collection (Direct Authentication)

Use this when you need to fetch PSD2 data once and do not need to re-collect later without user interaction. The user authenticates directly during the collection flow — no separate consent is created or stored.

When to use:

  • Single data fetch (e.g., onboarding snapshot)
  • You don't need recurring access
  • You want the simplest integration path

Check company availability — Call GET /companies/availability to verify the target company supports PSD2 AIS and is currently available.

Request
curl https://api.insurely.com/companies/availability \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01"

Start collection — Call POST /collections with a SwedishBankIdParameter and a Psd2AisConsentParameter defining the scope.

Request
curl -X POST https://api.insurely.com/collections \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01" \
  -H "Content-Type: application/json" \
  -d '{
    "company": "se-demo-psd2",
    "loginMethod": "SWEDISH_MOBILE_BANKID_OTHER_DEVICE",
    "parameters": [
      {
        "type": "SWEDISH_BANKID",
        "personalNumber": "200001012384"
      },
      {
        "type": "PSD2_AIS_CONSENT",
        "accountIds": [],
        "balances": true,
        "transactions": true,
      }
    ]
  }'
Response
{
  "id": "coll-456",
  "status": "RUNNING",
  "company": "se-demo-psd2",
  "pollingTimeout": "2026-03-05T10:05:00Z",
  "extraInformation": null
}

Poll collection status — Poll GET /wealth/collection/{collectionId}/status until the status is terminal. During WAITING_FOR_USER_ACTION, present BankID authentication to the user using the extraInformation field.

Request
curl https://api.insurely.com/wealth/collection/coll-456/status \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01"
Response waiting for user action
{
  "id": "coll-456",
  "status":"WAITING_FOR_USER_ACTION",
  "company":"se-demo-psd2",
  "extraInformation": {
    "SWEDISH_BANKID_QRCODE": "BASE_64_ENCODED_QR_CODE",
    "SWEDISH_MOBILE_BANKID_ANIMATED_QR_DATA": "BANK_ID_TOKEN CODE"
  }
}

Respect pollingTimeout — poll before this timestamp or the collection may be terminated. Recommended interval: 1–2 seconds.

Retrieve data — Call GET /collections/{collectionId}/wealth/data once the collection reaches COMPLETED, COMPLETED_PARTIAL, or COMPLETED_EMPTY.

Request
curl https://api.insurely.com/collections/coll-456/wealth/data \
  -H "authorization-token: <API_KEY>" \
  -H "Insurely-Version: 2026-04-01"

Returns an array of FinancialProduct objects (accounts, balances, transactions).

Notes

  • A short-lived consent is created during the collection process which will be automatically deleted once the collection is completed.
  • Failure to create a consent will result in the collection being marked as FAILED.

Sequence Diagram


Listing Consents

  • As the user (Authorization: Bearer): GET /consents — returns all consents for the authenticated user
  • As the backend (authorization-token): GET /users/{id}/consents — returns all consents for a specific user

Revoke a previously authorized consent via DELETE /consents/{consentId}:

Request
curl -X DELETE https://api.insurely.com/consents/consent-789 \
  -H "Authorization: Bearer <JWT>" \
  -H "Insurely-Version: 2026-04-01"
  • The revocation is forwarded to the bank (ASPSP)
  • Once revoked, the consent cannot be used for new collections
  • The validUntil field in the create request is a requested expiration date; the bank may enforce a shorter period
  • The actual expiration is in the expiresAt field of the ConsentStatusResponse
  • Expired consents cannot be used — create a new consent when the previous one expires
  • Check consent status before starting a collection to avoid using an expired consent

Listing Collections

  • As the user (Authorization: Bearer): GET /collections — returns all CollectionSummary objects for the authenticated user
    • Optional query params: latest=true (latest per company), statusIn=COMPLETED,FAILED (filter by status)
  • As the backend (authorization-token): GET /users/{id}/collections — returns all collections for a specific user

One-TimeConsent-Based
User interactionRequired every timeOnly on initial consent creation
Best forSingle snapshots, onboardingRecurring fetches, background refresh
BankID authDuring collectionDuring consent creation only
ReusableNoYes, until consent expires or is revoked
ComplexityLower (fewer API calls)Higher (consent lifecycle management)
Consent expirationN/AMust handle expiry and re-consent
API calls for first fetch2 (start + poll/data)6 (user + session + consent + poll consent + start + poll/data)
API calls for subsequent fetch2 (same as first)2 (start + poll/data, reuse consent)

Important Notes

PSU Presence (PSD2 Compliance)

PSD2 requires signaling whether the end user (PSU — Payment Service User) is present when interacting with the bank. This affects how the bank processes the request — without PSU presence fields, the request may be treated as a background refresh, which some banks handle differently or reject.

When creating a consent — include PSU fields in the Psd2AisConsentParameter:

FieldRequiredDescription
psuIpAddressYesThe end user's IP address (IPv4 or IPv6).
psuLocaleOptionalLocale string in xx-YY format (e.g., sv-SE, en-GB). Used for localization of consent flows.
validUntilOptionalRequested consent expiration date in YYYY-MM-DD format. The bank may enforce a shorter period.

When starting a collection with a stored consent — include PSU fields in the StoredConsentParameter to signal that the user is present:

FieldRequiredDescription
psuIpAddressOptionalThe end user's IP address. Set this when the user is actively requesting the data fetch.
psuUserAgentOptionalThe end user's browser or device User-Agent string. Set this when the user is actively requesting the data fetch.

If the collection is a background refresh (no user present), omit both fields.

When starting a One-Time Collection collection without a stored consent — you can omit the PSU fields, they are optional.

Account Scoping

The accountIds field in the Psd2AisConsentParameter controls which accounts the consent/collection covers:

  • Empty array or omitted: Consent applies to all accounts the user has at the bank
  • Specific IDs: Consent applies only to those accounts

Swedish BankID Authentication Variants

For Swedish companies, two BankID flows are available:

Login MethodAuth Instructions TypeUser Experience
SWEDISH_MOBILE_BANKID_OTHER_DEVICESwedishBankIdQrUser scans QR code with BankID app on another device. QR data refreshes on each poll — always render the latest.
SWEDISH_MOBILE_BANKID_SAME_DEVICESwedishBankIdAutostartTokenClient launches BankID app directly via bankid:/// URI with the autostart token.

Error Handling

Consent errors (when status is FAILED):

  • The ConsentStatusError object contains code (e.g., AUTHENTICATION_TIMEOUT) and a human-readable message

Collection errors:

  • Terminal failure statuses include: FAILED, AUTHENTICATION_TIMEOUT, INCORRECT_CREDENTIALS, AUTHENTICATION_CANCELLED, AUTHENTICATION_CONFLICT, THIRD_PARTY_ERROR, ACCOUNT_TEMPORARILY_LOCKED
  • For THIRD_PARTY_ERROR, the issue is on the bank's side — retry later
  • See Collection statuses for the full list with recommended actions

Polling Best Practices

  • Consent polling: Use the pollingInterval field from the ConsentStatusResponse (in milliseconds). Typically 1–2 seconds.
  • Collection polling: Respect the pollingTimeout timestamp in the CollectionStatus — poll before this time or the collection may be terminated. Recommended interval: 1–2 seconds.
  • Do not poll more aggressively than indicated — excessive polling may trigger rate limiting (HTTP 429).

Last updated on