Get Institution Grid Endpoint
const url = 'https://example.com/api/v1/institutions/grid?limit=25&offset=0&include_archived=true&sort_by=date&sort_dir=asc';const options = {method: 'GET'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request GET \ --url 'https://example.com/api/v1/institutions/grid?limit=25&offset=0&include_archived=true&sort_by=date&sort_dir=asc'Institution-grouped, all-history, currency-converted pivot grid.
Declared above GET /{institution_id} — as a literal path, /grid would otherwise be swallowed by that int path parameter.
Always paginated by distinct date (never a partial date, never unbounded): limit defaults to 25, capped at 100. Always returns X-Total-Count (total distinct dates matching the resolved institution column set and date_from/date_to). search, when given, filters the institution column set by case-insensitive name substring; grand_total always sums exactly the columns returned. Archived institutions are included as columns by default (only soft-deleted ones are excluded); include_archived=false drops them from the column set, and therefore from grand_total, X-Total-Count and the valid sort_column_id values.
sort_by/sort_dir/sort_column_id order the grid server-side,
across the whole matching date range rather than just the loaded page.
sort_column_id, when the column mode is requested, must name one of the
institution ids this request itself just resolved (already user-scoped
and already narrowed by search and include_archived) – membership in that list is the
complete ownership check, so a foreign id, a search-filtered-out id and
a nonexistent id are rejected identically with a 422 that names the
constraint only. Supplying sort_column_id with any other mode
is ignored rather than rejected. Omitting all three sort params
reproduces the pre-existing row order and total-count header exactly.
Sorting by date keeps the existing SQL-level date pagination — one page of dates is aggregated, not the whole range. Sorting by total or by a column aggregates the whole matching date range and slices the sorted result to the requested offset/limit in Python, since neither ordering key exists until after aggregation. The total-count header comes from the dates helper’s own count in both branches, so it never varies with the chosen ordering.
Parameters
Section titled “Parameters”Query Parameters
Section titled “Query Parameters”Responses
Section titled “Responses”Successful Response
One date row in the institution-grouped pivot grid.
cells has one InstitutionGridCell per non-deleted institution owned by the caller, in sort_order/name order. grand_total_has_missing_rate is derived purely by OR-ing this row’s own cells’ has_missing_rate values, so it can never disagree with what the row’s cells visibly show.
object
One institution’s aggregated data within a grid row.
total is None only when the institution had no snapshot at all on that date – no account under it contributed anything. Unlike snapshot.py’s GridCell, where a null converted_balance implicitly signals a missing conversion rate for that one account’s single currency, has_missing_rate here is an explicit boolean: an institution cell aggregates accounts that may span several currencies, so there is no single cell currency left to compare against the base currency.
Example generated
[ { "date": "example", "cells": [ { "institution_id": 1, "total": "example", "has_missing_rate": true } ], "grand_total": "example", "grand_total_has_missing_rate": true }]Validation Error
object
object
object
Example generated
{ "detail": [ { "loc": [ "example" ], "msg": "example", "type": "example", "input": "example", "ctx": {} } ]}