BudgetBakers Partner AISP API v2 (2.0.0-draft.7)

Download OpenAPI specification:

Account and transaction data plane of the partner AISP API for contracted partners: providers, clients, connection records, accounts and transactions, plus connect sessions and partner capability discovery.

Connection lifecycle actions - create, refresh, reconnect, revoke and delete - exist only on /v1 (see the Partner API v1.1 reference). Connect sessions, partner config, providers, clients and all reads have their home on /v2 (this reference); the /v1 connect-session and partner-config paths are transitional aliases. Both path sets are served on the same host with the same API key, so do not hardcode a shared version prefix.

Sandbox and live mode are selected by the API key prefix (bb_test_… / bb_live_…), never by the host. Guides: https://aisp-docs.bbapi.io/guide/getting-started

The contract evolves additively: new endpoints, optional fields, envelope fields and enum values may be added without notice, and clients must ignore what they do not recognize.

Conventions (v2, normative)

  • Envelopes. Every 2xx body is an object: single resources are wrapped as {"data": …}, lists as {"limit": …, "nextCursor": …, "data": […]}. New envelope fields may be added without notice; unknown fields must be ignored.
  • Money is a decimal string with two fraction digits ("816.00", "-2326.00"), or three where the third digit carries value ("1.005") — the upstream store keeps three-decimal precision. Never parse as binary float.
  • Ordering is guaranteed and documented per endpoint. Where sorting is configurable, id is the tiebreaker in the same direction as order.
  • Cursors are opaque keysets (base64url). A cursor is only valid together with the identical sort, order and filter parameters it was produced with; any mismatch is rejected with validation_error. Keyset cursors are stable under concurrent inserts — a page walk never skips or duplicates rows because new rows arrived mid-walk.

Authentication

Identical to v1: every request requires X-Api-Key. Client-scoped endpoints (accounts, transactions, connection read, client get/delete) additionally require X-Client-Id; partner-scoped ones (client create/lookup, providers) do not. Traffic passes our API gateway with per-partner rate limits.

Errors (v2)

Same machine-readable model as v1.1 - {"error": {"code", "message"}, "requestId"} with a stable error.code - but the v1.1 errorDesc string is not part of v2 responses. Branch on error.code only. Resources outside the caller's partner + client scope are indistinguishable from absent ones: both return 404 not_found.

Connect sessions

Hosted connect flow orchestration (moved from /v1)

Create a hosted connect session

Same operation as v1.1 createConnectSession served by the same handler - the /v1 path remains a transitional alias. Creates a session for the hosted connect flow and returns a one-time hostedUrl. The underlying connection is created internally once the user confirms a bank — or, with connectionId set, the session reconnects that connection instead and the bank picker is skipped.

Authorizations:
ApiKeyAuth
header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Idempotency-Key
string <= 255 characters

Unique key (UUID recommended) making the request idempotent for 24 hours, scoped per partner. A replay with the same key returns the original response.

Request Body schema: application/json
required
returnUrl
required
string <uri>

Final destination after the hosted flow completes. Validated at session creation against the app's registered return-URL patterns. In sandbox mode the partner portal's own Try-it-now return page is accepted without registration. The redirect appends connectionId, resultCode (Ok|Error|Cancelled), sessionId, and error (failures only).

locale
string
Default: "en"

ISO 639-1; hosted UI language. The hosted flow ships en, cs, sk and hu; any other value falls back to en.

country
string

ISO 3166-1 alpha-2 preselect for the bank picker.

providerId
string or null <uuid>

When set, the bank picker is skipped and the flow starts at the consent step.

connectionId
string or null <uuid>

Reconnect mode: the session re-authorizes this existing connection instead of creating a new one; the bank picker is skipped because the bank is implied by the connection. Mutually exclusive with providerId; a Disabled connection is rejected with connection_not_recoverable. The reconnect starts when the user opens hostedUrl, so an unopened session leaves the connection untouched.

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{}

Get connect session status

For troubleshooting and server-side reconciliation; the webhook stream remains the authoritative completion signal. Same handler as the v1.1 operation.

Authorizations:
ApiKeyAuth
path Parameters
sessionId
required
string
header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "sessionId": "cs_9c1e7ab24d",
  • "state": "Completed",
  • "connectionId": "38d0322a-a01f-4ab5-811a-7014b597834a",
  • "resultCode": "Ok",
  • "error": null
}

Partner

Partner self-description and capability discovery (moved from /v1)

Capability discovery

Self-description of the calling partner (partner-scoped, no X-Client-Id). Same handler as the v1.1 operation. Calling a disabled capability elsewhere returns 403 capability_disabled.

Authorizations:
ApiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "partnerId": "2f5a1c3e-9b7d-4e21-a6c8-0d4f5e6a7b8c",
  • "name": "Acme Lending",
  • "mode": "sandbox",
  • "capabilities": {
    },
  • "consentDuration": "PT1H",
  • "countries": null,
  • "webhook": {
    }
}

Providers

Bank (provider) discovery (v2 data plane)

List providers available to the partner (paginated)

Providers filtered to the partner's allowed countries and integration sources (from platform configuration). Ordering (normative): stable ascending by id (pagination guarantee only). Partner-scoped — no X-Client-Id.

A provider whose effective status is Forbidden is absent from this page, unconditionally and with no parameter to include it. Forbidden is an internal curation decision, not a state of the bank: it says BudgetBakers has not offered this provider to this partner, so for the partner it does not exist rather than being unavailable. The status itself therefore never reaches this plane and is not in status's vocabulary.

Sandbox providers (code *_xf, country XF) are listed to a sandbox key (bb_test_) only. A live key (bb_live_) never reaches them, so they are absent from its pages the same way.

Authorizations:
ApiKeyAuth
query Parameters
limit
integer [ 1 .. 500 ]
Default: 100

Maximum number of items in this page. Values outside 1..500 are rejected with validation_error (v2 does not silently clamp).

nextCursor
string

Keyset cursor returned by the previous page's nextCursor field. Treat it as opaque and iterate until the response's nextCursor is null. Normative: the cursor must be sent together with the identical sort, order and filter parameters used when it was issued; a mismatch (or a tampered / undecodable cursor) is rejected with 400 validation_error. Unlike v1, this cursor is a keyset, not an offset — it is stable under concurrent inserts.

country
string = 2 characters

ISO 3166-1 alpha-2 filter (XF = sandbox-only fictional country).

search
string <= 100 characters

Case-insensitive substring match on the provider name.

Responses

Response samples

Content type
application/json
{
  • "limit": 100,
  • "nextCursor": null,
  • "data": [
    ]
}

Clients

End-user (client) lifecycle (v2 data plane)

Create a client (upsert by externalId)

Creates the partner's end user. Partner-scoped. Re-posting an existing externalId returns the existing client — never a duplicate.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
email
required
string
countryCode
required
string
externalId
string

Optional partner identifier. Re-posting an existing externalId returns the existing client (upsert semantics), never a duplicate.

Responses

Request samples

Content type
application/json
{
  • "email": "string",
  • "countryCode": "CZ",
  • "externalId": "string"
}

Response samples

Content type
application/json
{
  • "data": {
    }
}

Look up a client by externalId

Partner-scoped lookup; the page contains zero or one items.

Authorizations:
ApiKeyAuth
query Parameters
externalId
string <= 255 characters

Look up the client by the partner-supplied external id (exact match). Returns a page with zero or one items.

limit
integer [ 1 .. 500 ]
Default: 100

Maximum number of items in this page. Values outside 1..500 are rejected with validation_error (v2 does not silently clamp).

nextCursor
string

Keyset cursor returned by the previous page's nextCursor field. Treat it as opaque and iterate until the response's nextCursor is null. Normative: the cursor must be sent together with the identical sort, order and filter parameters used when it was issued; a mismatch (or a tampered / undecodable cursor) is rejected with 400 validation_error. Unlike v1, this cursor is a keyset, not an offset — it is stable under concurrent inserts.

Responses

Response samples

Content type
application/json
{
  • "limit": 100,
  • "nextCursor": null,
  • "data": [
    ]
}

Get a client

Authorizations:
ApiKeyAuth
path Parameters
clientId
required
string <uuid>
header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Delete a client and all their data

Removes the client and cascades to their connections, accounts and transactions in the v2 store. Idempotent — deleting an absent client returns 404.

Authorizations:
ApiKeyAuth
path Parameters
clientId
required
string <uuid>
header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "error": {
    },
  • "requestId": "req_8f3a2c1e"
}

Connections

Connection record retrieval (lifecycle actions stay on /v1)

Get a connection record

The stored connection record (state, provider, consent expiry). Lifecycle actions (create, refresh, revoke…) remain on their /v1 paths.

Authorizations:
ApiKeyAuth
path Parameters
connectionId
required
string <uuid>

Connection ID as returned by the v1 connection endpoints.

header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Accounts

Account retrieval for an authorized connection (v2 data plane)

List accounts of a connection (paginated)

Paginated list of the connection's accounts. Ordering (normative): stable ascending by id; the order carries no business meaning and is documented only as a pagination guarantee. Unlike v1 there is no 100-account cap — connections with more accounts paginate instead of being silently truncated. The list is not filtered by subscriptionStatus: accounts the user did not select in the account picker are returned too, as Disabled — visible, with their balance, but carrying no transactions.

Authorizations:
ApiKeyAuth
path Parameters
connectionId
required
string <uuid>

Connection ID as returned by the v1 connection endpoints.

query Parameters
limit
integer [ 1 .. 500 ]
Default: 100

Maximum number of items in this page. Values outside 1..500 are rejected with validation_error (v2 does not silently clamp).

nextCursor
string

Keyset cursor returned by the previous page's nextCursor field. Treat it as opaque and iterate until the response's nextCursor is null. Normative: the cursor must be sent together with the identical sort, order and filter parameters used when it was issued; a mismatch (or a tampered / undecodable cursor) is rejected with 400 validation_error. Unlike v1, this cursor is a keyset, not an offset — it is stable under concurrent inserts.

header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "limit": 100,
  • "nextCursor": null,
  • "data": [
    ]
}

Get a single account

Single account wrapped in the {"data": …} envelope.

Authorizations:
ApiKeyAuth
path Parameters
accountId
required
string <uuid>

Account ID as returned by GET /v2/connections/{connectionId}/accounts.

header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "data": {
    }
}

Transactions

Transaction retrieval for an account (v2 data plane)

List transactions of an account (sorted, filtered, paginated)

Paginated transaction list. Default ordering (normative): recordDate descending, then id descending — newest first, deterministic. Sorting is configurable via sort/order; filters (dateFrom/dateTo, recordState, variableSymbol) combine with AND semantics. All filter and sort parameters must stay constant across a cursor walk (see nextCursor). History depth is provider-driven — typically around 90 days of history is available after the initial connect. Delta sync: poll with sinceSeq (combinable only with limit) to receive every row inserted or modified since your last position, ordered by seq — including late-arriving transactions whose recordDate predates rows you already hold, which date-based paging would miss.

Authorizations:
ApiKeyAuth
path Parameters
accountId
required
string <uuid>

Account ID as returned by GET /v2/connections/{connectionId}/accounts.

query Parameters
limit
integer [ 1 .. 500 ]
Default: 100

Maximum number of items in this page. Values outside 1..500 are rejected with validation_error (v2 does not silently clamp).

nextCursor
string

Keyset cursor returned by the previous page's nextCursor field. Treat it as opaque and iterate until the response's nextCursor is null. Normative: the cursor must be sent together with the identical sort, order and filter parameters used when it was issued; a mismatch (or a tampered / undecodable cursor) is rejected with 400 validation_error. Unlike v1, this cursor is a keyset, not an offset — it is stable under concurrent inserts.

sort
string
Default: "recordDate"
Enum: "recordDate" "amount"

Sort key for the transaction list. recordDate (default) or amount. The id tiebreak (see order) makes every sort total, so pagination is deterministic.

order
string
Default: "desc"
Enum: "asc" "desc"

Sort direction, desc (default) or asc. Normative: rows are ordered by (sort key, then id) with both keys in this direction; null sort-key values sort last for desc and first for asc.

dateFrom
string <date>

Inclusive lower bound on recordDate, as a calendar date (UTC): recordDate >= dateFrom T00:00:00Z.

dateTo
string <date>

Inclusive upper bound on recordDate, as a calendar date (UTC): recordDate < (dateTo + 1 day) T00:00:00Z. dateTo must not precede dateFrom (validation_error).

recordState
string
Enum: "Cleared" "Uncleared"

Return only transactions in the given record state.

variableSymbol
Array of strings <= 20 items [ items <= 64 characters ]

Return only transactions whose details.variableSymbol matches one of the given values. Repeatable standard query parameter (?variableSymbol=888&variableSymbol=456), at most 20 values (validation_error beyond that). Matching ignores leading zeros on both sides (00123 matches 123); trailing digits are significant. Note this replaces v1's JSON-array-in-query encoding with plain repetition.

sinceSeq
integer <int64> >= 0

Delta sync (exclusive lower bound): return only rows whose seq is greater than the given value, ordered by seq ascending. Poll with the highest seq you have processed (sinceSeq=0 for a full initial sync); a row re-appears whenever it changes server-side. Combinable ONLY with limit — any other filter, sort/order, or a foreign cursor is rejected with validation_error. Continue a page walk via the returned nextCursor or simply by the last item's seq; both are equivalent. Gaps in seq are normal. The feed is per-account; within an account the ingest pipeline is serialized, so a poll never misses a lower seq committed late.

sinceCreatedSeq
integer <int64> >= 0

Create-only delta sync (exclusive lower bound): return only rows whose createdSeq is greater than the given value, ordered by createdSeq ascending. Unlike sinceSeq, a row appears on this feed exactly once — server-side modifications never re-deliver it. Combinable ONLY with limit; mutually exclusive with sinceSeq. Continue via the returned nextCursor or the last item's createdSeq; gaps are normal.

header Parameters
X-Client-Id
required
string <uuid>

Client ID obtained from POST /v2/clients. Required on client-scoped endpoints.

Responses

Response samples

Content type
application/json
{
  • "limit": 100,
  • "nextCursor": "eyJ2IjoxLCJzb3J0IjoicmVjb3JkRGF0ZSIsIm9yZGVyIjoiZGVzYyIsImsiOlsiMjAyNi0wNy0wMVQwOToxNTowMFoiLCI3YzUwZjA5ZS0zZDQ0LTRiNmEtYThiOS0xZjJlM2Q0YzViNmEiXX0",
  • "data": [
    ]
}