Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

Account represents a bank or financial account (deposit, credit, loan, investment, payroll, or other) held by a workspace, company, or individual. It is the primary model the connector layer (Plaid, Qonto, etc.) writes synced bank accounts into, and it is also used to record counterparty accounts extracted from invoice payment means. Key associations are to Workspace (tenant scope), Company (account holder or the workspace’s own company), People (individual holder), a bank Company via bank_company, a source WorkspaceConnector tracking provenance, and one-to-many AccountWorkspaceConnectors for multi-connector sync audit. The ownership field distinguishes workspace-held accounts from counterparty accounts from unclassified legacy rows.
NamingValue
ObjectAccount
Resource type (JSON:API type)account
Collection / records rootaccounts
REST base/v1/accounts
Entity classAccount

API operations

OperationMethod & pathStatus
ListGET /v1/accounts✅ Implemented
RetrieveGET /v1/accounts/{id}✅ Implemented
CreatePOST /v1/accounts🟡 Planned
UpdatePATCH /v1/accounts/{id}🟡 Planned
DeleteDELETE /v1/accounts/{id}🟡 Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
account_idstring, UUID, 🔒 system✅ Yesunique; generated via gen_random_uuid() on INSERTPublic immutable identifier for the account. Exposed in all API responses and external references.
account_external_idstring⚪ Nomax length 255; partial unique index on (workspace_pk, account_external_id) WHERE deleted_at IS NULL AND account_external_id IS NOT NULLProvider-assigned identifier for the account (e.g. Plaid account_id, Qonto account external id). Used as the deduplication key during connector sync to prevent re-creating an already-ingested account.
typestring (enum)✅ Yesnon-null; maps to native pg enum account_type_enumdeposit, credit, loan, investment, payroll, otherTop-level account classification. deposit and credit are the most common for operational bank accounts; investment covers treasury / brokerage accounts (e.g. Arc Treasury via Pershing).
subtypestring (enum)⚪ Nonullable; maps to native pg enum account_subtype_enumchecking account, savings account, money market account, cash management, certificate of deposit, electronic benefit transfer, health savings account, PayPal account, prepaid card (deposit); card (credit); auto, business, commercial, construction, consumer, home equity, home mortgage, line of credit, mortgage, overdraft, student (loan); 529 plan, 401a plan, 401k plan, 403b plan, 457b plan, brokerage account, cash isa, crypto exchange, education savings account, fixed annuity, guaranteed investment certificate, health reimbursement account, IRA, ISA, Keogh, lif, life insurance, LIRA, LRIF, LRSP, mutual fund, non custodial wallet, non taxable brokerage, other annuity, other insurance, pension, pension prif, profit sharing plan, QSHR, RDSP, RESP, retirement account, RLIF, ROTH, Roth 401k, RRIF, RRSP, SARSEP, sep IRA, simple IRA, SIPP, stock plan, TFSA, thrift savings plan, trust, UGMA, UTMA, variable annuity (investment); Roth IRA (payroll); other (generic)Granular Plaid-compatible account subtype. Provides detailed classification within each account type. Not always populated for non-Plaid connectors.
account_namestring⚪ Nomax length 255; user-editable in some connectors — must not be used as a unique keyHuman-readable display name for the account, typically provided by the bank or fintech (e.g. ‘Qonto EUR — Operating’). May contain the bank name as free text; use as display label only, not as an identity signal.
ibanstring⚪ Nomax length 34; CHECK: iban IS NULL OR iban ~ ’^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$’ (ISO 13616)International Bank Account Number in ISO 13616 format. Fully populated by the Qonto connector; absent for US-centric connectors (Plaid/Mercury). The IBAN prefix encodes the country and CIB (FR IBANs: positions 5–9 are the bank code).
account_numberstring⚪ Nomax length 50Domestic account number, used where IBAN is not applicable (e.g. US accounts). Stored as-is from the provider.
bicstring⚪ Nomax length 11; CHECK: bic IS NULL OR bic ~ ’^[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}([A-Z0-9]{3})?$’ (ISO 9362, 8 or 11 chars)BIC/SWIFT code for the account’s bank in ISO 9362 format. First 4 characters are the institution code. Used for bank identity resolution and cross-workspace deduplication.
routing_numberstring⚪ Nomax length 9; CHECK: routing_number IS NULL OR routing_number ~ ’^[0-9]{9}$’ (US ABA 9-digit)US ABA routing number. Maps deterministically to a US bank via the FedACH directory. Populated for some US-side accounts; absent for EU/UK accounts.
sort_codestring⚪ Nomax length 6; CHECK: sort_code IS NULL OR sort_code ~ ’^[0-9]{6}$’ (UK 6-digit)UK bank sort code. Maps to a specific UK bank and branch. Absent for non-UK accounts.
currencystring⚪ Nomax length 3; CHECK: currency IS NULL OR currency ~ ’^[A-Z]{3}$’ (ISO 4217)ISO 4217 three-letter currency code for the primary currency of the account. Helps disambiguate multiple accounts at the same institution (e.g. Mercury USD vs Mercury IO).
digital_wallet_providerstring (enum)⚪ Nonullable; maps to native pg enum digital_wallet_provider_enumpaypal, apple_pay, google_pay, samsung_pay, alipay, wechat_payProvider of the digital wallet when the account represents a digital wallet rather than a traditional bank account.
digital_wallet_idstring⚪ Nomax length 255External identifier for the digital wallet account at the specified digital_wallet_provider.
digital_wallet_typestring (enum)⚪ Nonullable; maps to native pg enum digital_wallet_type_enumpersonal, business, merchantClassification of the digital wallet account by usage context.
ownershipstring (enum)✅ Yesnon-null; default ‘unknown’; maps to native pg enum account_ownership_enum. Set at write time from structured signals only — never from string/regex matching.workspace, counterparty, unknownClassifies whether the account belongs to the workspace itself (a connector-synced bank account) or to a counterparty (extracted from an invoice or document payment means). ‘unknown’ is the safe default for legacy rows and rows lacking sufficient provenance signal. Backfilled to ‘workspace’ where source_workspace_connector_pk is set or where a PaymentMeans links the account back to the workspace’s own company.
raw_datajsonb⚪ Nonullable; shape varies by connector — always branch on originating connector before parsingComplete connector-native payload as received from the provider. For Plaid: contains institution_id, institution_name, official_name, and counterparty metadata. Shape is connector-specific; do not assume a fixed path without checking the source connector.
created_atDate, 🔒 system✅ Yesset once on INSERT via onCreate lifecycle hookTimestamp of record creation. Set automatically by MikroORM; never supplied by callers.
updated_atDate, 🔒 system⚪ Noset on INSERT and refreshed on every UPDATE via onCreate/onUpdate lifecycle hooksTimestamp of last update. Refreshed automatically by MikroORM on every write.
deleted_atDate⚪ Nonullable; soft-delete sentinel. All queries must filter deleted_at IS NULL. The partial index idx_accounts_workspace_external_id_active uses WHERE deleted_at IS NULL.Soft-delete timestamp. When set, the account is logically deleted and excluded from all standard queries. Hard deletes are not performed on this entity.

Relationships

NameTypeRequiredDescription
workspaceto-one (Workspace)⚪ No (nullable FK)Tenant scope. Points to the Workspace that owns this account. Every standard query must filter through this relation. Indexed via idx_accounts_workspace_deleted (workspace, deleted_at).
companyto-one (Company)⚪ No (nullable FK, fieldName: company_pk)The company that holds this account. For workspace-owned accounts, this is typically the workspace’s own company. Mutually exclusive with the people relation in practice — each account belongs to either a Company or a People. Indexed via idx_accounts_company.
peopleto-one (People)⚪ No (nullable FK, fieldName: people_pk)The individual person who holds this account. Used when the account belongs to a natural person rather than a legal entity. Mutually exclusive with the company relation in practice. Indexed via idx_accounts_people.
bank_companyto-one (Company)⚪ No (nullable FK, fieldName: bank_company_pk)The bank institution (represented as a Company) that operates this account. Used for logo display and bank identity resolution. When NULL, the bank can sometimes be recovered from raw_data or inferred from IBAN/BIC. Indexed via idx_accounts_bank_company.
source_workspace_connectorto-one (WorkspaceConnector)⚪ No (nullable FK)The WorkspaceConnector instance that first created this account row. When non-NULL, indicates connector-confirmed provenance and is a primary signal for setting ownership = ‘workspace’. When NULL, the account was created by a fallback path (manual, invoice parse, payment means extraction).
workspace_connectorto-one (WorkspaceConnector)⚪ No (nullable FK, fieldName: workspace_connector_pk)The WorkspaceConnector currently associated with this account for ongoing sync operations. Distinct from source_workspace_connector — a different connector may currently manage sync even if it did not create the row.
account_workspace_connectorsto-many (AccountWorkspaceConnector)Collection of AccountWorkspaceConnector pivot rows recording per-connector sync provenance for this account, including the sync direction (inbound/outbound). Used for multi-connector audit trails.

System-computed

  • account_id: generated via gen_random_uuid() on INSERT; unique constraint enforced at the database level.
  • created_at: set once on INSERT via MikroORM onCreate lifecycle hook; never supplied by callers.
  • updated_at: set on INSERT and refreshed on every UPDATE via MikroORM onCreate/onUpdate lifecycle hooks.
  • deleted_at: soft-delete sentinel. When set, the account is excluded from all standard queries. The partial index idx_accounts_workspace_external_id_active uses WHERE deleted_at IS NULL AND account_external_id IS NOT NULL for the Plaid-sync hot-path dedup lookup.
  • ownership default: defaults to ‘unknown’ at the database level for all new rows. Backfilled to ‘workspace’ by Migration20260527120000_account_ownership where source_workspace_connector_pk IS NOT NULL, or where a PaymentMeans row links the account to the workspace’s own company (payment_means.account_pk = accounts.pk AND payment_means.company_pk = workspace.own_company_pk).
  • account_external_id dedup: the partial unique index idx_accounts_workspace_external_id_active on (workspace_pk, account_external_id) WHERE deleted_at IS NULL AND account_external_id IS NOT NULL is the connector-layer dedup key. Plaid sync uses this to find an existing account before creating a new one, preventing re-linking on reconnect.
  • source_workspace_connector provenance: when source_workspace_connector_pk IS NOT NULL, the account was created by the connector pipeline and ownership should be ‘workspace’. A NULL source_workspace_connector_pk means the account was created via a fallback path (manual entry, invoice payment means extraction) and ownership defaults to ‘unknown’ pending classification.
  • bank_company recovery: when bank_company_pk IS NULL, the bank identity may be recoverable from raw_data (look for raw_data->>‘institution_name’ or raw_data->‘institution’->>‘name’) or inferred from the IBAN bank code prefix (FR IBANs: positions 5–9 = CIB) or BIC first 4 characters.
  • Composite composites.yml definitions: two composites are defined for the accounts root — composite_account_summary (source_fields: account_id, bank_company.primary_media.url, account_name, currency, iban, account_number; display_type: account_summary) and composite_latest_balance_currency (source_fields: account_id, account_balances.accounting_balance; display_type: currency_amount).

Example

{
  "data": {
    "type": "account",
    "id": "a3f7c2e1-84b0-4d5e-9f12-6c8a1b0e3d7f",
    "attributes": {
      "account_external_id": "qonto_acc_EU84QNTO00001234567890",
      "type": "deposit",
      "subtype": "checking account",
      "account_name": "Qonto EUR — Operating",
      "iban": "FR7616958000010000012345678",
      "account_number": null,
      "bic": "QNTOFRP1XXX",
      "routing_number": null,
      "sort_code": null,
      "currency": "EUR",
      "digital_wallet_provider": null,
      "digital_wallet_id": null,
      "digital_wallet_type": null,
      "ownership": "workspace",
      "raw_data": {
        "institution_id": "ins_qonto",
        "institution_name": "Qonto",
        "official_name": "Qonto Business Current Account"
      },
      "created_at": "2025-03-14T09:22:11.000Z",
      "updated_at": "2026-02-01T14:05:33.000Z",
      "deleted_at": null
    },
    "relationships": {
      "workspace": {
        "data": { "type": "workspace", "id": "b1e9d4f2-3301-4a8c-b7e0-9f4c2d1a5e88" }
      },
      "company": {
        "data": { "type": "company", "id": "c2a8f5e3-7712-4b9d-a1f2-8e3d0c6b4a21" }
      },
      "people": {
        "data": null
      },
      "bank_company": {
        "data": { "type": "company", "id": "d4b7e8f1-2290-4c3a-b5e7-1f9d0a2c8b64" }
      },
      "source_workspace_connector": {
        "data": { "type": "workspace_connector", "id": "e5c9d1a2-4403-4e7b-c2f3-2a4b5d0e9c77" }
      },
      "workspace_connector": {
        "data": { "type": "workspace_connector", "id": "e5c9d1a2-4403-4e7b-c2f3-2a4b5d0e9c77" }
      },
      "account_workspace_connectors": {
        "data": [
          { "type": "account_workspace_connector", "id": "f6d0e2b3-5514-4f8c-d3g4-3b5c6e1f0d88" }
        ]
      }
    }
  }
}
Source: apps/api/src/database/entities/Account.ts · domain: financial-graph · tier: Main