Astrada bank-accounts API
Manage connected bank accounts. Bank accounts are created automatically when a bank link enrollment is completed.
Manage connected bank accounts. Bank accounts are created automatically when a bank link enrollment is completed.
openapi: 3.0.3
info:
title: Astrada bank-accounts API
version: '2024-02-28'
contact:
email: developer@astrada.co
description: 'Welcome to our API Reference. 👋
'
servers:
- url: https://api.astrada.co
security: null
tags:
- name: bank-accounts
description: Manage connected bank accounts. Bank accounts are created automatically when a bank link enrollment is completed.
paths:
/bank-accounts/{bankAccountId}:
parameters:
- $ref: '#/components/parameters/bank-account-id'
delete:
tags:
- bank-accounts
summary: Delete bank account
description: 'Deletes a bank account and all associated bank transactions and transaction matches.
**Note:** This action is irreversible.
'
operationId: DeleteBankAccount
security:
- main-auth:
- banking:admin
responses:
'204':
description: Bank account deleted
'400':
$ref: '#/components/responses/bad-request'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/not-found'
'500':
$ref: '#/components/responses/server-error'
get:
tags:
- bank-accounts
summary: Retrieve bank account
description: Returns detailed information about a specific bank account by its identifier.
operationId: GetBankAccount
security:
- main-auth:
- banking:read
responses:
'200':
description: Successful operation
content:
application/json:
schema:
$ref: '#/components/schemas/bank-account'
examples:
Example Get Bank Account Response:
$ref: '#/components/examples/bank-account'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/not-found'
'500':
$ref: '#/components/responses/server-error'
patch:
tags:
- bank-accounts
summary: Update bank account
description: 'Updates a bank account. Card links are detected automatically — the first time a card''s transactions produce a high-confidence match against this account''s feed, the card is linked without any API call. This endpoint is the manual override: use it to pre-link cards before any spend exists, correct an assignment, or import history.
Each card in `cardIds` must belong to the same subaccount as the bank account. A card can only be linked to one bank account at a time — attempting to link a card that is already associated with another bank account will return a `409 Conflict` error.
`cardIds` is a full replacement. Send `cardIds: []` to clear explicit links (automatic detection can re-link a card on its next high-confidence match). Virtual bank accounts declare their cards explicitly and must always have at least one.
Optionally include a `backfill` object with `startDate` and/or `endDate` to trigger a backfill of historical bank transactions for the specified date range. An automatically detected link re-matches the account''s already-synced unmatched transactions around the new card''s activity on its own; IMPORTING bank history from before the link (pulling older transactions from the provider) still happens only through this endpoint''s `backfill`.
The current card set is always readable at `GET /bank-accounts/{bankAccountId}` (`cardIds`), and `GET /bank-accounts?cardId=` finds the account a card is linked to.
'
operationId: UpdateBankAccount
security:
- main-auth:
- banking:write
requestBody:
description: Bank account update request
required: true
content:
application/json:
schema:
type: object
required:
- cardIds
properties:
cardIds:
description: The identifiers of cards to link to this bank account for transaction matching. Send an empty array to unlink all cards. Each card must belong to the same subaccount.
type: array
items:
type: string
format: uuid
backfill:
description: Optional backfill configuration to import historical bank transactions for the linked card.
type: object
properties:
startDate:
description: Start date for the backfill range in YYYY-MM-DD format.
type: string
format: date
endDate:
description: End date for the backfill range in YYYY-MM-DD format.
type: string
format: date
examples:
LinkCardExample:
value:
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
LinkMultipleCardsExample:
value:
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
- 8abc3d12-1bb6-4912-b421-6e8f2a7c9d0e
LinkCardWithBackfillExample:
value:
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
backfill:
startDate: '2025-09-01'
endDate: '2025-10-01'
UnlinkAllCardsExample:
value:
cardIds: []
responses:
'200':
description: Bank account updated
content:
application/json:
schema:
type: object
required:
- id
- cardIds
- state
- updatedAt
properties:
id:
type: string
format: uuid
description: The bank account identifier.
cardIds:
type: array
items:
type: string
format: uuid
description: The linked card identifiers.
state:
type: string
description: The current state of the bank account.
updatedAt:
type: string
format: date-time
description: When the bank account was last updated.
backfill:
type: object
description: Backfill results returned when a backfill was requested.
properties:
transactionsProcessed:
type: integer
description: Number of historical transactions processed.
matchesFound:
type: integer
description: Number of matches found during backfill.
examples:
Example Update Bank Account Response:
value:
id: 3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
state: active
updatedAt: '2025-10-03T11:00:00.000Z'
'400':
$ref: '#/components/responses/bad-request'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/not-found'
'409':
$ref: '#/components/responses/conflict'
'500':
$ref: '#/components/responses/server-error'
/bank-accounts/link-enrolled-cards:
post:
tags:
- bank-accounts
summary: Link enrolled cards to bank accounts (admin backfill)
description: 'Admin backfill/retry for immediate mask-linking: matches the subaccount''s
ENROLLED cards against its credit bank accounts by mask (an enrolled
card''s last 4 digits) and links each exact match. The same
exactly-one-or-skip rules as completion-time linking apply — a mask
matching multiple cards, or multiple accounts claiming a mask, links
nothing (transaction-based discovery remains the backstop). Idempotent:
already-linked pairs are skipped. Intended for onboarding backfills
(cards enrolled before the bank link) and recovery after a transient
directory failure at completion. Emits no webhook — linked cardIds
appear on subsequent bank-account reads.
'
operationId: LinkEnrolledCards
security:
- main-auth:
- banking:admin
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required:
- subaccountId
properties:
subaccountId:
type: string
format: uuid
description: The subaccount whose enrolled cards and bank accounts to match.
example:
subaccountId: f297d659-c13d-4219-aeaa-e10a845140a5
responses:
'201':
description: Backfill executed. Maps each bank account that gained links to the card ids linked in this run (empty object when nothing matched).
content:
application/json:
schema:
type: object
required:
- linked
properties:
linked:
type: object
description: bankAccountId -> cardIds linked in THIS run.
additionalProperties:
type: array
items:
type: string
format: uuid
examples:
Example Backfill Response:
value:
linked:
059d5e6a-cfb1-46e6-ab84-6586582b6b58:
- da28e1b8-c7a4-4575-b72f-3a88d6fe34df
'400':
$ref: '#/components/responses/bad-request'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'500':
$ref: '#/components/responses/server-error'
/bank-accounts:
get:
tags:
- bank-accounts
summary: List bank accounts
description: 'Returns a list of bank accounts under the account. Bank accounts are created automatically when a bank link enrollment is completed.
By default, `GET /bank-accounts` returns bank accounts ordered by the latest `createdAt`.
This endpoint supports cursor-based pagination.
'
operationId: ListBankAccounts
parameters:
- $ref: '#/components/parameters/subaccount-id'
- $ref: '#/components/parameters/bank-account-state'
- $ref: '#/components/parameters/card-id-2'
- $ref: '#/components/parameters/banking-limit'
- $ref: '#/components/parameters/cursor'
- in: query
name: virtual
description: Filter by virtual account status.
required: false
schema:
type: boolean
security:
- main-auth:
- banking:read
responses:
'200':
description: Successful operation
content:
application/json:
schema:
type: object
required:
- items
- pagination
properties:
items:
type: array
items:
$ref: '#/components/schemas/bank-account'
pagination:
type: object
required:
- hasMore
properties:
cursor:
type: string
description: Cursor to use for the next page of results.
hasMore:
type: boolean
description: Whether there are more results available.
examples:
Example List Bank Accounts Response:
value:
items:
- _links:
self:
href: /bank-accounts/3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
transactions:
href: /bank-transactions/1fcb895e-9217-4a6f-9d10-5a7dcef86c11?bankAccountId=3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
statements:
href: /bank-accounts/3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c/statements
bankLink:
href: /bank-links/enrollment_792dcb7d
id: 3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
accountId: 8f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c
subaccountId: 1fcb895e-9217-4a6f-9d10-5a7dcef86c11
bankLinkId: enrollment_792dcb7d
externalId: plaid_acc_792dcb7d
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
virtual: false
institutionName: Chase
name: Checking
mask: '1234'
type: checking
currency: USD
state: active
createdAt: '2025-10-03T10:55:42.000Z'
updatedAt: '2025-10-03T10:55:42.000Z'
- _links:
self:
href: /bank-accounts/9b7e4d2f-8a3c-1e6f-d5b0-2c4a6e8f0d1b
transactions:
href: /bank-transactions/1fcb895e-9217-4a6f-9d10-5a7dcef86c11?bankAccountId=9b7e4d2f-8a3c-1e6f-d5b0-2c4a6e8f0d1b
statements:
href: /bank-accounts/9b7e4d2f-8a3c-1e6f-d5b0-2c4a6e8f0d1b/statements
bankLink:
href: /bank-links/enrollment_792dcb7d
id: 9b7e4d2f-8a3c-1e6f-d5b0-2c4a6e8f0d1b
accountId: 8f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c
subaccountId: 1fcb895e-9217-4a6f-9d10-5a7dcef86c11
bankLinkId: enrollment_792dcb7d
externalId: plaid_acc_792dcb7e
cardIds: []
virtual: false
institutionName: Chase
name: Savings
mask: '5678'
type: checking
currency: USD
state: active
createdAt: '2025-10-03T10:55:42.000Z'
updatedAt: '2025-10-03T10:55:42.000Z'
pagination:
hasMore: false
links:
GetFirstBankAccount:
operationId: GetBankAccount
parameters:
bankAccountId: $response.body#/items/0/id
description: Retrieve the first bank account from the list.
'400':
$ref: '#/components/responses/bad-request'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'500':
$ref: '#/components/responses/server-error'
/bank-accounts/{bankAccountId}/refresh:
parameters:
- $ref: '#/components/parameters/bank-account-id'
post:
tags:
- bank-accounts
summary: Refresh bank account
description: 'Triggers a refresh of bank account data from the financial institution. If the account requires re-authentication, the response will include a new hosted link URL for the user to complete re-authentication.
'
operationId: RefreshBankAccount
security:
- main-auth:
- banking:write
responses:
'200':
description: Refresh triggered
content:
application/json:
schema:
type: object
required:
- id
- hostedLink
- expiresAt
properties:
id:
type: string
format: uuid
description: The bank account identifier.
hostedLink:
type: string
description: A hosted URL for the user to complete re-authentication.
expiresAt:
type: string
format: date-time
description: When the hosted link expires.
examples:
Example Refresh Bank Account Response:
value:
id: 3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
hostedLink: https://hosted.plaid.com/link/refresh123
expiresAt: '2025-10-03T14:55:42.000Z'
'400':
$ref: '#/components/responses/bad-request'
'401':
$ref: '#/components/responses/unauthorized'
'403':
$ref: '#/components/responses/forbidden'
'404':
$ref: '#/components/responses/not-found'
'500':
$ref: '#/components/responses/server-error'
components:
parameters:
subaccount-id:
in: query
name: subaccountId
required: false
schema:
type: string
format: uuid
example: 2fd4d402-b759-479c-87a6-58d85e345356
bank-account-id:
in: path
name: bankAccountId
required: true
schema:
type: string
format: uuid
example: a1b2c3d4-e5f6-7890-abcd-ef1234567890
card-id-2:
in: path
name: cardId
required: true
schema:
type: string
format: uuid
example: 6d18f5bb-b9d6-4237-97c2-44b1bdb71d6b
bank-account-state:
in: query
name: state
description: Filter bank accounts by state
required: false
schema:
type: string
enum:
- active
- auth_required
- disconnected
example: active
banking-limit:
in: query
name: limit
description: Maximum number of items to return
required: false
schema:
type: integer
minimum: 1
maximum: 1000
default: 250
example: 250
cursor:
in: query
name: cursor
required: false
description: The cursor to use for pagination. Identifies your place on the list
schema:
type: string
format: byte
example: ZXhhbXBsZQ==
responses:
conflict:
description: Request conflict with the current state of the target resource
content:
application/problem+json:
schema:
$ref: '#/components/schemas/conflict'
examples:
Minimum shape (detail only):
value:
detail: Card verification with id=9fab1bea-bc1e-4757-bd47-479422e5983b was abandoned by the user during the authentication process. Please start a new verification.
Resource conflict with currentValue:
value:
title: Conflict
detail: The target resource already exists.
currentValue: 396aebd2-002f-4ccf-9b4d-f961c693e6e2
not-found:
description: The requested resource was not found on the server
content:
application/problem+json:
schema:
type: object
properties:
type:
type: string
instance:
type: string
detail:
type: string
title:
type: string
enum:
- Not Found
required:
- detail
- title
example:
title: Not Found
detail: The requested resource was not found on the server.
unauthorized:
description: Authentication credentials were either missing or incorrect
content:
application/problem+json:
schema:
type: object
properties:
detail:
type: string
title:
type: string
enum:
- Unauthorized
required:
- detail
- title
example:
title: Unauthorized
detail: Authentication credentials were either missing or incorrect.
forbidden:
description: Authentication credentials used do not have have permissions to perform the request
content:
application/problem+json:
schema:
type: object
properties:
detail:
type: string
title:
type: string
enum:
- Forbidden
required:
- detail
- title
example:
title: Forbidden
detail: You do not have permission to access the requested resource.
server-error:
description: The server encountered an unexpected condition that prevented it from fulfilling the request
content:
application/problem+json:
schema:
type: object
properties:
detail:
type: string
title:
type: string
enum:
- Internal Server Error
required:
- detail
- title
example:
title: Internal Server Error
detail: The server encountered an unexpected condition that prevented it from fulfilling the request.
bad-request:
description: The server cannot or will not process the request due to something that is perceived to be a client error
content:
application/problem+json:
schema:
type: object
properties:
detail:
type: string
title:
type: string
enum:
- Bad Request
errors:
type: array
items:
type: object
properties:
title:
type: string
detail:
type: string
required:
- title
- detail
required:
- detail
- title
examples:
Example Generic Bad Request Payload Response:
value:
title: Bad Request
detail: Request object failed validation.
Example Generic Bad Request Parameters Response:
value:
title: Bad Request
detail: Request parameters are invalid.
examples:
bank-account:
description: Example of a Bank Account resource
value:
_links:
self:
href: /bank-accounts/3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
transactions:
href: /bank-transactions/1fcb895e-9217-4a6f-9d10-5a7dcef86c11?bankAccountId=3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
statements:
href: /bank-accounts/3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c/statements
bankLink:
href: /bank-links/enrollment_792dcb7d
id: 3a8f2c1d-5e7b-4d9a-b6c8-9f0e1d2a3b4c
accountId: 8f3a1b2c-4d5e-6f7a-8b9c-0d1e2f3a4b5c
subaccountId: 1fcb895e-9217-4a6f-9d10-5a7dcef86c11
bankLinkId: enrollment_792dcb7d
externalId: plaid_acc_792dcb7d
cardIds:
- 5dec2c49-0aa5-4683-a317-427eb5d115f3
virtual: false
institutionName: Chase
name: Checking
mask: '1234'
type: checking
currency: USD
state: active
createdAt: '2025-10-03T10:55:42.000Z'
updatedAt: '2025-10-03T10:55:42.000Z'
schemas:
bank-account:
type: object
required:
- _links
- id
- accountId
- subaccountId
- externalId
- institutionName
- cardIds
- virtual
- name
- currency
- type
- state
- createdAt
- updatedAt
properties:
_links:
type: object
description: HAL-style links to related resources.
required:
- self
- transactions
- statements
properties:
self:
$ref: '#/components/schemas/link'
transactions:
$ref: '#/components/schemas/link'
statements:
$ref: '#/components/schemas/link'
bankLink:
$ref: '#/components/schemas/link'
id:
type: string
format: uuid
description: The unique identifier of the bank account.
accountId:
type: string
format: uuid
description: The unique identifier of the account that owns this bank account.
subaccountId:
type: string
format: uuid
description: The unique identifier of the subaccount associated with this bank account.
bankLinkId:
type: string
nullable: true
description: The identifier of the bank link that created this account. Null for virtual accounts.
externalId:
type: string
description: The external identifier provided at creation for virtual accounts, or the provider account ID for Plaid-connected accounts.
cardIds:
type: array
items:
type: string
format: uuid
description: The identifiers of cards linked to this bank account for transaction matching, always current — linked immediately at bank-link completion when an enrolled card's last 4 digits match a credit account's mask, detected automatically on the first high-confidence match between a card's transactions and this account's feed, or set manually via PATCH. Cards must belong to the same subaccount.
cards:
type: array
description: 'Cards MATERIALIZED from this bank account (`bank-feed` enrollments
minted at bank-link completion for credit accounts whose mask matched
no already-enrolled card). Distinct from `cardIds`, which is the link
surface: a mask-matched or discovered card appears in `cardIds` only,
while a minted card appears in both. Empty for depository, virtual,
and mask-matched-only accounts.
'
items:
type: object
required:
- id
- subscriptionId
- last4digits
- network
- enrollmentType
properties:
id:
type: string
format: uuid
description: The minted card's identifier on the cards platform.
subscriptionId:
type: string
format: uuid
description: The bank-feed card subscription created by the mint.
last4digits:
type: string
pattern: ^\d{4}$
description: The card number's last 4 — equals this account's mask by construction.
network:
type: string
nullable: true
description: The card network when the institution implies it (e.g. `amex`); null until a PAN enrollment upgrades the card in place.
enrollmentType:
type: string
enum:
- bank-feed
description: Always `bank-feed` — the enrollment transport this card was materialized through.
virtual:
type: boolean
description: Whether this is a virtual (manually created) bank account.
institutionName:
type: string
description: The name of the connected financial institution.
institutionId:
type: string
nullable: true
description: The provider identifier of the connected institution (Plaid `ins_*`). Null for virtual accounts and connections made before this field was captured.
name:
type: string
description: The display name of the bank account (e.g. "Checking", "Savings").
mask:
type: string
nullable: true
description: The last 4 digits of the account number. For `credit` accounts this is the card number's last 4 — the per-card identity for bank-connected (e.g. American Express) card enrollments. Not guaranteed to be per-card when the institution combines multiple cards into a single account.
type:
type: string
description: The normalized type of bank account. (Correction — the service has always returned normalized values; the previous `depository`/`credit` enum understated live behavior. Codegen consumers should regenerate.)
enum:
- checking
- savings
- prepaid
- credit
- loan
- investment
- other
subtype:
type: string
nullable: true
description: The raw provider account subtype (e.g. Plaid `credit card`, `checking`). Null when the provider did not supply one or for accounts connected before this field was captured.
currency:
type: string
description: The currency of the account following ISO 4217 format.
minLength: 3
maxLength: 3
state:
type: string
description: 'Current state of the bank account.
- `active`: The account is connected and functioning normally.
- `auth_required`: The account requires re-authentication.
- `disconnected`: The account has been disconnected from the provider.
'
enum:
- active
- auth_required
- disconnected
createdAt:
description: Date and time when this resource was created, in UTC, following ISO 8601 format.
type: string
format: date-time
updatedAt:
description: Date and time when this resource was last updated, in UTC, following ISO 8601 format.
type: string
format: date-time
link:
type: object
properties:
href:
type: string
templated:
type: boolean
type:
type: string
deprecation:
type: string
name:
type: string
profile:
type: string
title:
type: string
hreflang:
type: string
required:
- href
conflict:
type: object
properties:
detail:
type: string
title:
type: string
enum:
- Conflict
currentValue:
type: string
description: Current value for the property causing the conflict
requestedValue:
type: string
description: Requested value for the property causing the conflict
required:
- detail
securitySchemes:
main-auth:
type: oauth2
flows:
implicit:
authorizationUrl: https://api.astrada.co/auth/realms/{accountId}/protocol/openid-connect/token
refreshUrl: https://api.astrada.co/auth/realms/{accountId}/protocol/openid-connect/token
scopes:
accounts:write: Accounts write resource
accounts:read: Accounts read resource
subaccounts:write: Subaccounts write resource
subaccounts:read: Subaccounts read resource
card-connector-data-links:write: card-connector-data-link resource
card-connector-consents:read: Card Consent read resource
card-connector-consents:write: Card Consent write resource
webhooks:read: Read Webhook resources
webhooks:write: Write Webhook resources
card-subscriptions:write: Create card subscription
car
# --- truncated at 32 KB (33 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/astrada/refs/heads/main/openapi/astrada-bank-accounts-api-openapi.yml