# info.description
Read-only API for bank accounts, balances and transactions. Authenticate every request with your API key: "Authorization: Bearer edk_...". All error responses share one envelope: {"error": {"code": "...", "message": "..."}}.

# paths./v1/accounts/{account_id}/transactions.get.parameters[].description
Opaque pagination cursor from the previous response's "next" URL. Newest first; treat transaction ids as the idempotency key when walking the feed.

# paths./v1/accounts/{account_id}/transactions.get.parameters[].description
Only transactions with booking_date on or after this date. Strictly YYYY-MM-DD.

# paths./v1/accounts/{account_id}/transactions.get.parameters[].description
Only transactions with booking_date on or before this date. Strictly YYYY-MM-DD.

# paths./v1/export.get.description
Download every record Endute holds for you as a zip of CSV files (accounts, transactions, the raw bank feed, investments and credential metadata). Rate limited to 4 downloads per day.

# paths./v1/investment-accounts.get.description
/v1/investment-accounts (list).

The "account" is an ``InvestmentAccountLink``; its owner hangs off
``connection__user``, so ``user_field`` is set accordingly (the base class
appends ``filter(connection__user=<user>)``).

# paths./v1/investment-accounts/{account_id}/activities.get.description
/v1/investment-accounts/{id}/activities (list).

HISTORY (4.2 carry-over): activities run from the link's ingestion start,
not the account's lifetime.

Ordering: ``-trade_date`` with NULLS LAST (Postgres DESC defaults NULLS
FIRST; cash-only rows carry a null trade_date, so a naive DESC would float
them to the top — ``F('trade_date').desc(nulls_last=True)`` fixes it),
tie-broken by ``-id``.

Pagination DECISION (plan-sanctioned): NOT cursor-paginated. A cursor
positions on the first ordering field, which here is nullable — the
null-trade_date rows have no cursor position, so a cursor would be
dishonest. Activities are bounded per account in practice, so the feed is
served UNPAGINATED with a hard cap of the ``ACTIVITY_CAP`` newest rows plus
a ``truncated`` boolean (honesty over complexity).

# paths./v1/investment-accounts/{account_id}/activities.get.parameters[].description
Only activities with trade_date on or after this date. Strictly YYYY-MM-DD. Cash-only rows (null trade_date) are excluded when this filter is set.

# paths./v1/investment-accounts/{account_id}/activities.get.parameters[].description
Only activities with trade_date on or before this date. Strictly YYYY-MM-DD. Cash-only rows (null trade_date) are excluded when this filter is set.

# paths./v1/investment-accounts/{account_id}/positions.get.description
/v1/investment-accounts/{id}/positions (list-shaped single object).

Serves the link's latest ``InvestmentSnapshot.positions`` VERBATIM plus
``as_of``. ABSENT SNAPSHOT (4.2 must-know): a link with no snapshot row
serves ``{"as_of": null, "positions": []}`` — never a 500.

# paths./v1/investment-connections.get.description
/v1/investment-connections (list).

The connection's owner FK is literally ``user``, so the default
``user_field`` applies unchanged.

# components.schemas.Account.description
Spec 4.3 account contract (list + retrieve).

# components.schemas.Account.properties.name.description
The account display name: the name set in the portal when one is set, otherwise the name the bank reports.

# components.schemas.Account.properties.masked_identifier.description
Last 4 of the IBAN, else last 4 of the BBAN, else null.

# components.schemas.Account.properties.account_type.description
The account type: current, savings, credit_card, cash, loan or investment. Derived from what the bank reports and correctable in the portal (some banks omit type metadata entirely). For credit_card accounts the balance endpoint serves the amount OWED (negative), not the available credit — if a card's balance looks like remaining credit, its type needs correcting in the portal. Nullable.

# components.schemas.Account.properties.status.description
Account status as reported by the bank (e.g. enabled).

# components.schemas.Account.properties.last_synced_at.description
When transaction DATA was last received for this account. Honest caveat: this is the last successful data delivery, not the last poll attempt -- a quiet account with no new transactions keeps an older stamp.

# components.schemas.Account.properties.oldest_booking_date.description
Booking date of the earliest transaction served for this account: the stored feed spans this date to now and only ever grows (history is never trimmed or expired). Use it with the transactions from/to filters to pull the window you want. Null until the first transaction lands.

# components.schemas.Account.properties.consent_renewal_due.description
When bank access for this account's connection next needs renewing (UTC). For UK connections this is a periodic confirmation checkpoint (renewed in the portal without a bank sign-in); for EU connections it is the consent end date and renewal is a full reconnect with a bank sign-in. After this passes without renewal, the feed stops receiving new data until the connection is renewed. Null for connections whose access does not time-expire (e.g. US and Canadian connections) and for the sandbox.

# components.schemas.Account.properties.available_history_days.description
The approximate number of days of transaction history this bank serves when an account is FIRST linked (90 for most banks; some card providers serve less, some banks more). The stored feed only ever grows from that starting window, so oldest_booking_date-to-now can exceed this figure over time.

# components.schemas.Balance.description
Spec 4.3 balances contract: the CACHED balance -- /v1 never triggers
a bank fetch (billing/refresh cadence is the platform's, spec D3).

``balance`` keeps the stored 4-dp precision; ``fetched_at`` is
``last_balance_update_at`` (when the cached value was last refreshed
from the bank). Both null until the first balance sync.

# components.schemas.Balance.properties.balance.description
Decimal string, 4 decimal places as stored.

# components.schemas.Connection.description
Spec 4.3 connection contract: consent status + expiry.

# components.schemas.Connection.properties.expires_at.description
When the underlying bank consent expires; null for connections without consent expiry (e.g. sandbox).

# components.schemas.InvestmentAccount.description
Spec 4.3 investment-account contract (list), serving one
``InvestmentAccountLink``.

``name`` and ``number`` come from what Task 4.2 stores on the link's
``provider_metadata`` (the provider does not always supply both), with a
sane fallback: ``name`` falls back to the broker name, ``number`` to null.
``currency`` is the mapped ``account_currency`` when set, else the first
cash currency on the snapshot, else null. ``last_holdings_sync_at`` is the
freshness field (the plan's chosen stamp — holdings, not transactions).

# components.schemas.InvestmentAccount.properties.number.description
Masked/partial account number as the provider supplied it (provider_metadata); null when unavailable.

# components.schemas.InvestmentAccount.properties.last_holdings_sync_at.description
When holdings were last successfully synced for this account; null until the first sync.

# components.schemas.InvestmentActivities.properties.truncated.description
True when the feed was capped at 500 rows and older rows were omitted.

# components.schemas.InvestmentActivity.description
Spec 4.3 activities contract, serving ``InvestmentActivityRecord``.

HISTORY NOTE (4.2 carry-over): activities run FROM the link's ingestion
start (when this brokerage account was first connected), not the account's
lifetime — there is no back-fill of pre-connection history.

``units``/``price``/``amount`` are Decimal-as-string (or null for the
field the provider omitted — a cash-only activity such as a dividend
carries null units/price). ``symbol`` may be '' for cash-only rows.
``trade_date`` may be null (cash-only rows).

# components.schemas.InvestmentActivity.properties.type.description
Provider activity type (e.g. BUY, SELL, DIVIDEND).

# components.schemas.InvestmentActivity.properties.units.description
Quantity, Decimal string; null for cash-only rows.

# components.schemas.InvestmentActivity.properties.price.description
Per-unit price, Decimal string; null for cash-only rows.

# components.schemas.InvestmentActivity.properties.amount.description
Total cash amount, Decimal string; signed as the provider reported.

# components.schemas.InvestmentActivity.properties.trade_date.description
Trade/settlement date; null for cash-only rows.

# components.schemas.InvestmentConnection.description
Spec 4.3 investment-connection contract (list).

``broker`` is the human-readable brokerage name the connection stores
(``brokerage_name``): the USER-FACING broker identity (e.g. 'Interactive
Brokers'), NOT the aggregation provider (which is internal). ``status`` is
the public label (like the bank connections do), never the raw DB code.

# components.schemas.InvestmentConnection.properties.broker.description
The user-facing brokerage name (e.g. "Interactive Brokers"). Never an aggregation provider identity.

# components.schemas.InvestmentConnection.properties.last_synced_at.description
When the most recent successful sync completed; null until the first sync.

# components.schemas.InvestmentPosition.properties.description.description
Human-readable instrument name; may be "".

# components.schemas.InvestmentPosition.properties.units.description
Quantity held, a Decimal rendered as a string. "0" when the provider omitted it; large/small values may use exponent notation (e.g. "1E+1").

# components.schemas.InvestmentPosition.properties.price.description
Current per-unit price, Decimal as a string; "0" when omitted.

# components.schemas.InvestmentPosition.properties.currency.description
ISO currency of price/market_value; may be "".

# components.schemas.InvestmentPositions.description
Spec 4.3 positions contract, serving one ``InvestmentSnapshot``.

``positions`` is served VERBATIM from ``snapshot.positions`` — the Task
4.2 normalized shape (Decimal-strings; "0" for an omitted units/price, and
a value may carry exponent notation such as "1E+1" since it is
``str(Decimal(...))``). ``as_of`` is the snapshot's provider-data
timestamp.

ABSENT SNAPSHOT (4.2 must-know): a link with no snapshot row serves
``{"as_of": null, "positions": []}`` — never a 500. The view builds that
dict directly, so this serializer only ever runs over a real snapshot.

# components.schemas.InvestmentPositions.properties.as_of.description
Provider data timestamp the snapshot reflects; null when no snapshot exists yet.

# components.schemas.Transaction.description
Spec 4.3 transaction contract, serving ``BankTransactionRecord``.

``description`` is the raw bank remittance text VERBATIM -- no
trimming, casing or cleanup: integrators build their own matching on
it, so any normalisation here is data loss.

# components.schemas.Transaction.properties.amount.description
Signed, as the bank reported: negative = outflow.

# components.schemas.Transaction.properties.upstream_transaction_id.description
The transaction id assigned by the BANK itself, when it assigns one -- stable at the bank across fetches, so use it for reconciliation against statements or other tools. Distinct from id (our stable identifier). Nullable.

# components.schemas.Transaction.properties.merchant_category_code.description
Four-digit card Merchant Category Code, where the bank supplies it (mostly card issuers). Nullable.

# components.schemas.Transaction.properties.bank_transaction_code.description
ISO 20022 bank transaction code (domain-family-subfamily, e.g. PMNT-CCRD-POSD), where the bank supplies it. Nullable.

# components.schemas.Transaction.properties.proprietary_bank_transaction_code.description
The bank's own transaction-type code, verbatim (vocabulary varies per bank). The most widely supplied of the code fields. Nullable.

# components.schemas.Transaction.properties.end_to_end_id.description
PSD2 end-to-end payment identifier, where the bank supplies it. Nullable.

# components.schemas.Transaction.properties.mandate_id.description
Direct Debit mandate identifier, where the bank supplies it. Useful for grouping recurring payments. Nullable.

# components.schemas.Transaction.properties.entry_reference.description
The bank's ledger entry reference, where the bank supplies it. Nullable.

# components.schemas.TransactionEnrichment.properties.brand_domain.description
The merchant's website domain when known (e.g. "tesco.com"): a stable brand key you can feed to the logo service of your choice.

# components.securitySchemes.connectApiKey.description
Connect API key, sent as "Authorization: Bearer edk_...".