Documentation Index
Fetch the complete documentation index at: https://docs.ivory.finance/llms.txt
Use this file to discover all available pages before exploring further.
Authentication
All portfolio endpoints require a valid JWT Bearer token. Thetenant_id is extracted from the token’s sub claim — each portfolio is isolated to the calling tenant.
Portfolios
Create portfolio
POST /v1/portfolios
Creates a new portfolio aggregate. After creation, the read-model snapshot is seeded automatically.
| Field | Required | Default | Description |
|---|---|---|---|
name | Yes | — | Portfolio display name |
portfolio_type | Yes | — | long_only | long_short | balanced | fixed_income | alternatives | multi_asset | fund_of_funds |
currency | No | USD | ISO 4217 currency code |
inception_date | No | today | ISO date string |
benchmark_ticker | No | — | Benchmark ticker, e.g. SPY |
rebalance_threshold | No | 0.05 | Drift % that triggers a rebalance recommendation (0.05 = 5%) |
metadata | No | {} | Arbitrary key/value metadata |
List portfolios
GET /v1/portfolios
Returns all portfolios for the tenant from the CQRS read model, ordered by AUM descending.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 50 | Max results (1–200) |
offset | integer | 0 | Pagination offset |
Get portfolio
GET /v1/portfolios/{portfolio_id}
Returns write-model detail plus the latest risk decomposition snapshot and position count.
Update portfolio
PATCH /v1/portfolios/{portfolio_id}
Send only the fields you want to change.
| Field | Description |
|---|---|
name | Portfolio display name |
rebalance_threshold | New drift threshold (e.g. 0.08) |
benchmark_ticker | New benchmark ticker |
is_active | false to archive |
metadata | Replace metadata object |
Positions
Import positions (CSV / Excel)
POST /v1/portfolios/{portfolio_id}/positions/import
Upload a CSV or Excel file of positions. The file is parsed, entity-resolved, and upserted. PortfolioRiskAgent and RebalanceAgent are fired asynchronously after a successful import.
Expected columns (case-insensitive, extras ignored):
| Column | Description |
|---|---|
ticker | Equity ticker symbol |
security_name | Full security name |
asset_class | equity | fixed_income | cash | alternatives | derivatives | real_estate | commodity | crypto |
quantity | Number of shares / units |
avg_cost_price | Average cost per unit |
current_price | Current market price |
sector | Sector slug (e.g. technology) |
geography | ISO-2 country code (e.g. US) |
isin | ISIN (used for entity resolution if ticker absent) |
cusip | CUSIP |
List positions
GET /v1/portfolios/{portfolio_id}/positions
| Parameter | Type | Description |
|---|---|---|
asset_class | string | Filter by asset class |
sector | string | Filter by sector slug |
limit | integer | Max results (1–500, default 100) |
offset | integer | Pagination offset |
Risk & Analytics
Get risk decomposition
GET /v1/portfolios/{portfolio_id}/risk
Returns the latest PortfolioRiskAgent output. Pass ?refresh=true to recompute synchronously before returning.
| Parameter | Type | Default | Description |
|---|---|---|---|
refresh | boolean | false | Recompute VaR/CVaR before returning |
Get performance attribution
GET /v1/portfolios/{portfolio_id}/attribution
Brinson-Fachler decomposition by sector. Breaks down active return into allocation effect, selection effect, and interaction effect.
| Parameter | Type | Default | Description |
|---|---|---|---|
period | string | ytd | ytd | 1y | q1_2025 etc. |
refresh | boolean | false | Recompute before returning |
Get factor exposures
GET /v1/portfolios/{portfolio_id}/factors
Factor regression loadings (market, size, value, momentum, quality, low_volatility) with t-stats and R².
| Parameter | Type | Default | Description |
|---|---|---|---|
refresh | boolean | false | Recompute before returning |
Trigger rebalance
POST /v1/portfolios/{portfolio_id}/rebalance
Manually trigger RebalanceAgent. If actual position weights have drifted beyond rebalance_threshold (or force: true), publishes an event to the pm:rebalance:recommended stream.
| Field | Type | Default | Description |
|---|---|---|---|
force | boolean | false | Recommend rebalance regardless of drift threshold |
Target allocations
Set allocation
POST /v1/portfolios/{portfolio_id}/allocations
Set or update a target allocation weight for a portfolio bucket. The RebalanceAgent compares actual weights against these targets to determine drift.
| Field | Required | Description |
|---|---|---|
allocation_type | Yes | sector | asset_class | geography | security |
bucket | Yes | The bucket identifier (e.g. technology, equity, US, AAPL) |
target_weight | Yes | Target portfolio weight (0.0–1.0) |
min_weight | No | Minimum allowed weight (default 0.0) |
max_weight | No | Maximum allowed weight (default 1.0) |

