# Article Portfolio Relevance
Source: https://docs.tilt.io/api-reference/backchannel/article-portfolio-relevance
POST /api/v1/backchannel/risk/article_portfolio_relevance
Classifies each article once and returns a comparable portfolio relevance score without generating a scenario tree.
Use this endpoint to rank a news feed for a portfolio without generating a scenario tree. Send up to 100 articles per request and compare `relevance_score` values within the response.
Each article may contain up to 50,000 content characters, with a maximum of 2,000,000 content characters across the request. Supplied `article_id` values must be unique within the batch.
The default `response_detail` is `score`. Use `explain` when you also need the classification reason and leading portfolio contributors. Use `full` only for debugging or deeper analysis.
Article classification is cached independently of the portfolio. Reusing the same headline, content, and publication time across portfolios avoids repeating the classification work, while each portfolio still receives its own relevance score.
# Get Company News
Source: https://docs.tilt.io/api-reference/backchannel/get-company-news
POST /api/v1/backchannel/news/companies
# Get Macro Sensitivities
Source: https://docs.tilt.io/api-reference/backchannel/get-macro-sensitivities
POST /api/v1/backchannel/risk/sensitivities
# Get Scenario
Source: https://docs.tilt.io/api-reference/backchannel/get-scenario
POST /api/v1/backchannel/scenarios/{id}
# Run Macro Scenario
Source: https://docs.tilt.io/api-reference/backchannel/run-macro-scenario
POST /api/v1/backchannel/risk/scenario
# Scenario Portfolio Analysis
Source: https://docs.tilt.io/api-reference/backchannel/scenario-portfolio-analysis
POST /api/v1/backchannel/risk/scenario_portfolio_analysis
# Search Companies
Source: https://docs.tilt.io/api-reference/backchannel/search-companies
POST /api/v1/backchannel/companies/search
# Search Dow Jones Archive
Source: https://docs.tilt.io/api-reference/backchannel/search-dow-jones-archive
POST /api/v1/backchannel/dow-jones-archive/search
# Search Scenarios
Source: https://docs.tilt.io/api-reference/backchannel/search-scenarios
POST /api/v1/backchannel/scenarios/search
# Delete Asset Class
Source: https://docs.tilt.io/api-reference/endpoint/delete-asset-class
DELETE /api/v1/custom/org/{organization_uuid}/asset_classes/{asset_class_uuid}/
Delete asset class
# Delete Client
Source: https://docs.tilt.io/api-reference/endpoint/delete-client
POST /api/v1/custom/org/{organization_uuid}/clients/{uuid}/delete/
Soft delete a client from the organization
# Delete Portfolio Config
Source: https://docs.tilt.io/api-reference/endpoint/delete-portfolio-config
DELETE /api/v1/custom/org/{organization_uuid}/portfolio_configs/{config_uuid}/
Delete a portfolio config for the organization
# Get Account Backtest Result
Source: https://docs.tilt.io/api-reference/endpoint/get-account-backtest-result
GET /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/backtests/{job_id}/
# Get Asset Class
Source: https://docs.tilt.io/api-reference/endpoint/get-asset-class
GET /api/v1/custom/org/{organization_uuid}/asset_classes/{asset_class_uuid}/
Retrieve asset class details
# Get Asset Classes
Source: https://docs.tilt.io/api-reference/endpoint/get-asset-classes
GET /api/v1/custom/org/{organization_uuid}/asset_classes/
List asset classes in the organization
# Get Benchmark Index
Source: https://docs.tilt.io/api-reference/endpoint/get-benchmark-index
GET /api/v1/custom/benchmark_indexes/{benchmark_identifier}/
# Get Benchmark Indexes
Source: https://docs.tilt.io/api-reference/endpoint/get-benchmark-indexes
GET /api/v1/custom/benchmark_indexes/
List the available benchmark indices that can be used as reference
for creating custom indices.
Supports typeahead search using the 'search' query parameter.
# Get Optimization Task Status
Source: https://docs.tilt.io/api-reference/endpoint/get-bulk-optimization-status
POST /api/v1/custom/org/{organization_uuid}/optimized_proposals/status/
# Get Client
Source: https://docs.tilt.io/api-reference/endpoint/get-client-details
GET /api/v1/custom/org/{organization_uuid}/clients/{uuid}/
View for retrieving and updating organization clients.
Supports:
- GET: Retrieve client details
- PATCH: Update the first account under the client
# Get Preview Job Result
Source: https://docs.tilt.io/api-reference/endpoint/get-dynamic-rules-preview-job
GET /api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/{job_id}/
# Get Dynamic Rules Schema
Source: https://docs.tilt.io/api-reference/endpoint/get-dynamic-rules-schema
GET /api/v1/custom/org/{organization_uuid}/dynamic_rules/schema/
# Get Index Constituents
Source: https://docs.tilt.io/api-reference/endpoint/get-index-constituents
GET /api/v1/indexes/{index_id}/constituents
Index constituents for a date. With no `date`, uses the most recent published level (the latest level date). A date with no published level returns 404; a level present but with no constituent snapshot returns 200 with an empty `data` array.
## Description
Retrieves the constituents for a specific index.
## Parameters
### Path Parameters
| Parameter | Required | Description |
| ---------- | -------- | ---------------------------------- |
| `index_id` | Yes | The unique identifier of the index |
### Query Parameters
| Parameter | Required | Description |
| --------- | -------- | ---------------------------------------------------------------------------------- |
| `date` | No | Effective date in `YYYY-MM-DD` format. Defaults to the most recent available date. |
### Default Behavior
* If `date` is not provided, returns constituents for the most recent available date
# Get Index Corporate Actions
Source: https://docs.tilt.io/api-reference/endpoint/get-index-corporate-actions
GET /api/v1/indexes/{index_id}/corporate-actions
Corporate actions affecting the index on the given date.
The feed includes every CA the index applied — dividends, special dividends, splits, stock distributions, bonus issues, removals (delisting/bankruptcy/M&A), spin-offs, and exchange changes.
With no `date`, returns the most recent date that has corporate actions for this index (an event feed, so this differs from /levels and /constituents, which default to the latest level date). Because dividends are included, the default date typically lands on a recent dividend/distribution date rather than the last structural event. When the index has no corporate actions for the requested or defaulted date, returns 200 with an empty `data` array and `effective_date: null` (not 404).
Each Primary row describes one CA. Any CA can carry Redistribution rows describing per-ticker share changes attributed to it. Removal CAs (delisting, bankruptcy, M&A, sanction removal, and an exchange change that moves the ticker off a home-exchange-restricted index's eligible exchange) carry rows whenever value was reassigned. A removal is not guaranteed to have at least one row; an empty `redistribution_rows` array can mean either the CA produced no share change or no recorded attribution exists for it yet (see below).
**Redistribution rows — content and reconciliation:**
Redistribution rows are recorded by the index at the time it applied the corporate action and describe the action's isolated, as-applied effect (the acquirer's legs, any replacement constituent it forced, and the level-preserving rescale) — not a re-derivation. An empty `redistribution_rows` array means either the CA produced no share change (the typical case for vanilla dividends, identifier-rotation exchange changes, and other no-op CAs) or no recorded attribution exists for that CA; the two cases are not separately signaled. When two or more removals share a single rescale on the same proposal, that shared rescale is recorded identically on each contributing removal's redistribution rows — both jointly caused it. Do not sum `redistribution_shares` across CAs on the same proposal; each row set independently describes the joint effect. Implicit signals are `old_index_shares=null` for a newly-added constituent and a negative `redistribution_shares` for a survivor whose shares were scaled down.
**Spin-offs:** the deal terms are reported via the `spin_off` sub-object. By default (`spin_off_eligible=true`) the spun-off company is ADDED as a new constituent, the parent is retained, and the new name is re-evaluated against the index rules at the next reconstitution; the addition appears as a Redistribution row when recorded (`old_index_shares=null`, `new_index_shares` equal to the spun-off shares). When `spin_off_eligible=false` the spun-off company is dropped and its value redistributed pro-rata (delisting-style) on the settlement date; that share change is reflected in the settlement date's constituent shares, not as Redistribution rows attached to this spin-off row.
**As-applied event values:** the event-input values on each Primary row and its sub-object (cash_per_share, exchange_ratio, deal_type, dist_pct, price adjustment factor, etc.) are frozen as of when the index applied the action, so a later edit to a still-pending corporate action does not change them. Security identity — the ticker the action targets and any acquirer/spun-off ticker — instead reflects the current corporate-action record, not the as-applied snapshot.
## Description
Retrieves corporate actions for a specific index.
## Parameters
### Path Parameters
| Parameter | Required | Description |
| ---------- | -------- | ---------------------------------- |
| `index_id` | Yes | The unique identifier of the index |
### Query Parameters
| Parameter | Required | Description |
| --------- | -------- | ----------------------------------------------------------------------------------------------- |
| `date` | No | Effective date in `YYYY-MM-DD` format. Defaults to the most recent date with corporate actions. |
### Default Behavior
* If `date` is not provided, returns corporate actions for the most recent date with corporate actions
# Get Index
Source: https://docs.tilt.io/api-reference/endpoint/get-index-details
GET /api/v1/indexes/{index_id}
Retrieve an index by UUID.
# Get Index Levels
Source: https://docs.tilt.io/api-reference/endpoint/get-index-levels
GET /api/v1/indexes/{index_id}/levels
Index level for a date. With no `date`, returns the most recent published level (the latest level date). A date with no published level returns 404..
## Description
Retrieves the levels for a specific index.
## Parameters
### Path Parameters
| Parameter | Required | Description |
| ---------- | -------- | ---------------------------------- |
| `index_id` | Yes | The unique identifier of the index |
### Query Parameters
| Parameter | Required | Description |
| --------- | -------- | ---------------------------------------------------------------------------------- |
| `date` | No | Effective date in `YYYY-MM-DD` format. Defaults to the most recent available date. |
### Default Behavior
* If `date` is not provided, returns levels for the most recent available date
# List Index Levels History
Source: https://docs.tilt.io/api-reference/endpoint/get-index-levels-history
GET /api/v1/indexes/{index_id}/levels/history
Returns historical index levels, optionally filtered by date.
# List Index Notifications
Source: https://docs.tilt.io/api-reference/endpoint/get-index-notifications
GET /api/v1/indexes/notifications
Paginated list of published index governance notifications, ordered by effective date (most recent first, undated last). Each notification includes a link to its page on the Tilt website. Supports filtering by effective date range, announcement type, affected index, and (via subscribed=true) the indexes your API key is entitled to.
# Get Optimization Task Result
Source: https://docs.tilt.io/api-reference/endpoint/get-optimization-task-result
GET /api/v1/custom/org/{organization_uuid}/optimized_proposals/{proposal_uuid}/
# Get Clients
Source: https://docs.tilt.io/api-reference/endpoint/get-org-client
GET /api/v1/custom/org/{organization_uuid}/clients/
List clients in the organization. Supports optional search across external_id and metadata fields, and ordering by created date.
# Get Organization
Source: https://docs.tilt.io/api-reference/endpoint/get-org-details
GET /api/v1/custom/org/{organization_uuid}/
# Get Aggregate Holdings
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-holdings
GET /api/v1/custom/org/{organization_uuid}/reports/holdings/
Get an aggregated report for the holdings across all clients.
# Get Aggregate Holdings by Constituents
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-holdings-constituents
GET /api/v1/custom/org/{organization_uuid}/reports/holdings/constituents/
Get an aggregated report for the holdings across all clients, grouped by constituent. The results are sorted by descending total market value.
# Get Optimization Metrics
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-optimizations
GET /api/v1/custom/org/{organization_uuid}/reports/optimizations/
Get metrics for the portfolio optimizations which have been run.
# Get Aggregate Trade Proposals
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-proposals
GET /api/v1/custom/org/{organization_uuid}/reports/proposals/
Get an aggregated report for trade proposals which have been generated.
# Get Aggregate Proposals by Constituent
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-proposals-constituents
GET /api/v1/custom/org/{organization_uuid}/reports/proposals/constituents/
Get an aggregated report for trade proposals which have been generated, grouped by constituent. The results are sorted by descending proposal_count, and then descending sum of notional buys & sells.
# Get Requests
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-requests
GET /api/v1/custom/org/{organization_uuid}/reports/requests/
List all authenticated requests. Note that requests which fail to match a valid path are not included in these statistics.
# Get Aggregate Request Metrics
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-requests-aggregate
GET /api/v1/custom/org/{organization_uuid}/reports/requests/aggregate/
Get aggregate statistics for all authenticated requests. Note that requests which fail to match a valid path are not included in these statistics.
# Get Ticker Constraints
Source: https://docs.tilt.io/api-reference/endpoint/get-org-reports-ticker-constraints
GET /api/v1/custom/org/{organization_uuid}/reports/ticker_constraints/
Get a list of ticker constraints across all clients, including at the organization level.
# Get Organization Risk Model
Source: https://docs.tilt.io/api-reference/endpoint/get-org-risk-model
GET /api/v1/custom/org/{organization_uuid}/risk_model
# Get Portfolio Config
Source: https://docs.tilt.io/api-reference/endpoint/get-portfolio-config
GET /api/v1/custom/org/{organization_uuid}/portfolio_configs/{config_uuid}/
Retrieve a portfolio config for the organization
# Get Portfolio Configs
Source: https://docs.tilt.io/api-reference/endpoint/get-portfolio-configs
GET /api/v1/custom/org/{organization_uuid}/portfolio_configs/
List portfolio configs for the organization
# Get Tilt
Source: https://docs.tilt.io/api-reference/endpoint/get-tilt-details
GET /api/v1/tilts/{tilt_uuid}
Retrieves stored Marketplace display data for a Tilt owned by the API key's organization.
# List Account Backtests
Source: https://docs.tilt.io/api-reference/endpoint/list-account-backtests
GET /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/backtests/
List all backtest jobs for a client
# List Preview Jobs
Source: https://docs.tilt.io/api-reference/endpoint/list-dynamic-rules-preview-jobs
GET /api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/jobs/
# List Indexes
Source: https://docs.tilt.io/api-reference/endpoint/list-indexes
GET /api/v1/indexes
Returns all indexes your account is subscribed to.
# List Tilts
Source: https://docs.tilt.io/api-reference/endpoint/list-tilts
GET /api/v1/tilts
Returns the current version of each Tilt owned by the API key's organization. Drafts and published Tilts are returned by default.
# Update Asset Class
Source: https://docs.tilt.io/api-reference/endpoint/patch-asset-classes
PATCH /api/v1/custom/org/{organization_uuid}/asset_classes/{asset_class_uuid}/
Update asset class data
# Update Client Account
Source: https://docs.tilt.io/api-reference/endpoint/patch-client-account
PATCH /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}
View for retrieving and updating a specific client account.
Supports:
- GET: Retrieve account details with holdings and portfolio data
- PATCH: Update account data
# Update Portfolio Config
Source: https://docs.tilt.io/api-reference/endpoint/patch-portfolio-configs
PATCH /api/v1/custom/org/{organization_uuid}/portfolio_configs/{config_uuid}/
Update a portfolio config for the organization
# Create Account Backtest
Source: https://docs.tilt.io/api-reference/endpoint/post-account-backtest
POST /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/backtests/
Start a new backtest job for a client
# Optimize Account Portfolio
Source: https://docs.tilt.io/api-reference/endpoint/post-account-optimize
POST /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/optimize/
Get the customized weights for a client.
# Create Account Trade Proposal
Source: https://docs.tilt.io/api-reference/endpoint/post-account-proposal
POST /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/proposal/
Create a rebalance proposal for a client.
# Create Asset Class
Source: https://docs.tilt.io/api-reference/endpoint/post-asset-class
POST /api/v1/custom/org/{organization_uuid}/asset_classes/
Create a new asset class in the organization
# Create Bulk Optimization Task
Source: https://docs.tilt.io/api-reference/endpoint/post-bulk-client-optimize-proposal
POST /api/v1/custom/org/{organization_uuid}/optimized_proposals/
Create optimized portfolio proposals for multiple client accounts in bulk.
This endpoint creates proposals asynchronously. Optimization errors (infeasible/unbounded problems)
will be handled during the async task execution and reflected in the proposal's status and failure_reason field.
Create tasks to optimize portfolio and generate proposals for multiple clients.
# Create Client Account
Source: https://docs.tilt.io/api-reference/endpoint/post-client-account
POST /api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/
Create a new account under an existing client
# Create Preview Job
Source: https://docs.tilt.io/api-reference/endpoint/post-dynamic-rules-preview
POST /api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/
# Simulate Dynamic Rules
Source: https://docs.tilt.io/api-reference/endpoint/post-dynamic-rules-simulate
POST /api/v1/custom/org/{organization_uuid}/dynamic_rules/simulate/
# Validate Expression
Source: https://docs.tilt.io/api-reference/endpoint/post-dynamic-rules-validate
POST /api/v1/custom/org/{organization_uuid}/dynamic_rules/validate/
# Create Client
Source: https://docs.tilt.io/api-reference/endpoint/post-org-client
POST /api/v1/custom/org/{organization_uuid}/clients/
Create a new client in the organization
# Create Organization Risk Model
Source: https://docs.tilt.io/api-reference/endpoint/post-org-risk-model
POST /api/v1/custom/org/{organization_uuid}/risk_model
# Create Portfolio Config
Source: https://docs.tilt.io/api-reference/endpoint/post-portfolio-config
POST /api/v1/custom/org/{organization_uuid}/portfolio_configs/
Create a new portfolio config for the organization
# Update Client
Source: https://docs.tilt.io/api-reference/endpoint/put-client-update
PATCH /api/v1/custom/org/{organization_uuid}/clients/{uuid}/
View for retrieving and updating organization clients.
Supports:
- GET: Retrieve client details
- PATCH: Update the first account under the client
# Update Organization Risk Model
Source: https://docs.tilt.io/api-reference/endpoint/put-org-risk-model
PUT /api/v1/custom/org/{organization_uuid}/risk_model
# Search Optimization Proposals
Source: https://docs.tilt.io/api-reference/endpoint/search-optimized-proposals
POST /api/v1/custom/org/{organization_uuid}/optimized_proposals/list/
# Search Tickers
Source: https://docs.tilt.io/api-reference/endpoint/search-tickers
GET /api/v1/tickers/search
Search for tickers, filtering by ticker property. At least one filter property must be provided. The searchable universe is Tilt's listed-security index (equities, ETFs, and related types); brokerage-specific instruments outside it — e.g. event-contract market tickers such as Kalshi markets, or spot crypto — are never indexed: searching for them returns zero results, not an error.
# Update Organization
Source: https://docs.tilt.io/api-reference/endpoint/update-org-details
PATCH /api/v1/custom/org/{organization_uuid}/
# Introduction
Source: https://docs.tilt.io/backchannel/introduction
API for integrating Tilt market intelligence capabilities.
## Welcome
The Pulse API exposes Tilt's market intelligence primitives for external integrations. The public v1 surface is intentionally narrow: scenarios, topics, company search, company news, and risk analysis.
The retired mobile-only Backchannel routes are not part of the application or the public Pulse contract.
## What You Can Build
Search and display curated market scenarios with impact analysis relevant to your users' holdings.
Surface macro sensitivities and run scenario-based risk analysis against portfolios.
Deliver market topics, expert commentary, and company-specific news feeds.
Resolve companies into Tilt's current v1 entity identifiers before calling downstream analysis endpoints.
## Getting Started
Authenticate and make your first API calls in minutes
Explore the scenarios endpoint
# Quick Start
Source: https://docs.tilt.io/backchannel/quick-start
Authenticate and start making Pulse API calls
## Overview
### Base URL
```bash theme={null}
https://tilt.io
```
### Authentication
All public Pulse API endpoints require an API key.
Include the API key in the header of each request:
```bash theme={null}
X-Api-Key:
```
Reuse your existing Tilt API key. Pulse does not issue a separate key type in v1.
## Making Your First API Calls
### 1. Search Scenarios
Search for relevant market scenarios:
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/scenarios/search" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": [{"weight": 1, "query": "tariffs"}],
"limit": 5
}'
```
[View full API reference →](/api-reference/backchannel/search-scenarios)
### 2. Get Scenario Detail
Fetch a single scenario by ID:
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/scenarios/POINT_ID" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"include_content": true
}'
```
[View full API reference →](/api-reference/backchannel/get-scenario)
### 3. Get Macro Sensitivities
Analyze how macro factors affect a portfolio:
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/risk/sensitivities" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"tilt_ids": ["Q2YN1N-R"],
"limit": 10
}'
```
[View full API reference →](/api-reference/backchannel/get-macro-sensitivities)
### Public v1 Scope
The public Pulse API is limited to scenarios, topics, company search, company news, and risk analysis. End-user account, holdings, and brokerage operations are not part of the public contract.
# Scenario Analysis Guide
Source: https://docs.tilt.io/backchannel/scenario-analysis-guide
Analyze how news events and macro shocks affect a portfolio using the Pulse API.
## Overview
The Pulse API lets you answer two core questions about a portfolio:
1. **"What would happen to my portfolio if X occurred?"** — Describe any scenario in plain English and get a probability-weighted impact analysis.
2. **"How does this news event affect my holdings?"** — Search curated news scenarios and compute portfolio exposure against them.
3. **"What happens if macro conditions change?"** — Run what-if analysis with specific macro factor shocks (USD strength, oil prices, etc.).
All workflows require a portfolio expressed as a map of `tilt_asset_id → weight`. This guide walks through resolving tickers, building portfolio weights, and calling the scenario and risk endpoints.
## Step 1: Resolve Tickers to Tilt Asset IDs
All portfolio-related endpoints accept weights keyed by **Tilt Asset ID** — an internal identifier for each security. Use the Search Tickers endpoint to resolve symbols.
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/tickers/search?symbols=AAPL,MSFT,NVDA" \
-H "X-Api-Key: YOUR_API_KEY"
```
Response:
```json theme={null}
{
"count": 6,
"results": [
{
"symbol": "AAPL",
"name": "Apple, Inc.",
"exchange": "NAS",
"ticker_type": "common_stock",
"tilt_asset_id": "MH33D6-R"
},
{
"symbol": "AAPL",
"name": "Apple, Inc.",
"exchange": "TSE",
"ticker_type": "dr",
"tilt_asset_id": "W0R2RY-R"
},
...
]
}
```
A symbol may return multiple results across exchanges (e.g. NAS and TSE listings). Filter by `ticker_type: "common_stock"` and the relevant exchange to get the primary US listing.
Extract the `tilt_asset_id` from each result.
[View API Reference →](/api-reference/endpoint/search-tickers)
You can resolve multiple symbols in a single call by passing a comma-separated list. Cache the mapping — tilt asset IDs are stable identifiers that don't change.
## Step 2: Build Portfolio Weights
Construct a `portfolio_weights` object mapping each `tilt_asset_id` to a decimal weight (summing to 1.0):
```json theme={null}
{
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
}
```
Weights should sum to 1.0. If they don't, the API will still work but exposure calculations will be proportional to the weights provided.
This `portfolio_weights` object is reused across all the endpoints below.
## Step 3: Scenario Portfolio Analysis
The simplest way to analyze portfolio impact. Describe any scenario in plain English and the API generates a probability tree of outcomes with portfolio-level returns.
### Recommended: Use `flat_scenarios` mode
We recommend using `flat_scenarios: true` for most integrations. This generates a clean, single-level structure where each scenario directly contains its macro shocks — no nested sub-scenarios to traverse. The result is simpler to parse and display.
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/risk/scenario_portfolio_analysis" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"scenario_description": "China begins naval blockade of Taiwan, semiconductor supply chain completely severed",
"portfolio_weights": {
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
},
"flat_scenarios": true,
"search_for_context": true,
"include_security_details": true
}'
```
### Key parameters
| Parameter | Type | Default | Description |
| -------------------------- | ------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `scenario_description` | string | — | Plain English description of the scenario to analyze. |
| `portfolio_weights` | object | — | Map of `tilt_asset_id` → weight. |
| `as_of_date` | string | today | Date for the analysis (YYYY-MM-DD). |
| `flat_scenarios` | boolean | `false` | **Recommended: `true`.** Generates flat scenarios where each scenario directly contains its macro shocks. When `false`, generates a two-level tree with sub-scenarios. |
| `search_for_context` | boolean | `true` | Search for relevant background articles to improve scenario quality. |
| `include_security_details` | boolean | `true` | Include per-security breakdown in each leaf scenario. |
| `aggregate_scenarios` | boolean | `false` | Collapse the scenario tree into summary stats (mean/std per top-level scenario). |
| `force_regenerate` | boolean | `false` | Bypass the scenario cache and regenerate from scratch. |
### Caching behavior
Scenario generation results are **automatically cached**. The first call for a given scenario generates fresh results (10–15 seconds). All subsequent calls with the same `scenario_description`, `as_of_date`, `search_for_context`, and `flat_scenarios` combination return cached results in **under 1 second**.
The cache is keyed on these four parameters. The portfolio weights are **not** part of the cache key — portfolio impact computation happens after scenario generation, so a single cached scenario tree can be reused for any portfolio instantly.
**Best practice for article-driven scenarios:** When you ingest a new article, immediately call `scenario_portfolio_analysis` with the article headline/summary as the `scenario_description`. This warms the cache so that any subsequent request — for any portfolio — returns instantly. This is ideal for "preload at login" flows.
If you only need to rank articles by their relevance to a portfolio, use [Article Portfolio Relevance](/api-reference/backchannel/article-portfolio-relevance). It returns a comparable score without generating the scenario tree or per-security scenario returns.
Use `force_regenerate: true` to bypass the cache if you need fresh results for an already-cached scenario.
### Response structure
The response includes an AI-generated scenario tree, leaf-level portfolio impacts, and a probability-weighted expected return:
```json theme={null}
{
"success": true,
"scenario_description": "China begins naval blockade of Taiwan...",
"as_of_date": "2026-03-10",
"expected_portfolio_return_pct": -0.0607,
"cache_hit": true,
"portfolio_summary": {
"num_scenarios": 3,
"num_leaf_scenarios": 3,
"num_securities": 3
},
"scenario_tree": [
{
"probability": 40,
"title": "Full blockade with military escalation",
"description": "...",
"macro_shocks": [
{"indicator": "VIXCLS", "impact": 0.25},
{"indicator": "rbics_55", "impact": -0.15}
]
}
],
"leaf_scenarios": [
{
"path": ["Full blockade with military escalation"],
"joint_probability_pct": 40,
"portfolio_return_pct": -0.12,
"portfolio_expected_return_pct": -0.12,
"contribution_to_expected_return_pct": -0.048,
"top_movers": [
{"tilt_id": "K7TPSX-R", "ticker": "NVDA", "expected_return_pct": -0.22, "contribution_to_portfolio_pct": -0.055},
{"tilt_id": "P8R3C2-R", "ticker": "MSFT", "expected_return_pct": 0.01, "contribution_to_portfolio_pct": 0.004}
],
"security_details": [
{
"tilt_id": "MH33D6-R",
"ticker": "AAPL",
"company_name": "Apple, Inc.",
"weight": 0.40,
"expected_return_pct": -0.1559,
"contribution_to_portfolio_pct": -0.0624,
"factor_contributions": {}
}
]
}
],
"context_articles": ["Taiwan Export Growth Lost Momentum in February", "..."],
"context_article_ids": ["a1b2c3d4-...", "e5f6g7h8-..."],
"warnings": null,
"generated_at": "2026-03-10T14:30:00"
}
```
When `flat_scenarios: true`, each scenario in `scenario_tree` contains its `macro_shocks` directly (no `sub_scenarios`), and `leaf_scenarios` has one entry per scenario. When `flat_scenarios: false` (default), scenarios have nested `sub_scenarios` and `leaf_scenarios` contains one entry per sub-scenario with joint probabilities.
**Key fields:**
| Field | Description |
| ------------------------------------------------------ | ------------------------------------------------------------------------------------------------------- |
| `expected_portfolio_return_pct` | Probability-weighted expected portfolio return across all leaf scenarios. Decimal form (0.01 = 1%). |
| `portfolio_summary` | Counts of scenarios, leaf scenarios, and securities analyzed. |
| `scenario_tree` | The full probability tree. Flat when `flat_scenarios: true`, nested with `sub_scenarios` when `false`. |
| `leaf_scenarios` | Flattened leaf nodes with joint probabilities, portfolio returns, top movers, and per-security details. |
| `leaf_scenarios[].portfolio_return_pct` | Portfolio return for this specific leaf scenario. |
| `leaf_scenarios[].contribution_to_expected_return_pct` | This leaf's contribution to the overall expected return (joint\_probability \* portfolio\_return). |
| `leaf_scenarios[].top_movers` | Top 3 gainers and top 3 losers by contribution to portfolio return. |
| `context_articles` | Headlines of articles used as background context (when `search_for_context` is true). |
| `context_article_ids` | Point IDs of context articles used as background context. |
| `cache_hit` | `true` if the scenario tree was served from cache, `false` if freshly generated. |
| `warnings` | Array of warnings (e.g., unknown tilt\_ids skipped). `null` if no warnings. |
This endpoint uses AI to generate scenarios on first encounter (\~10–15 seconds). Cached scenarios return in under 1 second. For instant results on pre-computed news scenarios, use the Search Scenarios endpoint below instead.
[View API Reference →](/api-reference/backchannel/scenario-portfolio-analysis)
### Flat vs. hierarchical scenarios
| | `flat_scenarios: true` | `flat_scenarios: false` (default) |
| -------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **Structure** | 3 top-level scenarios, each with `macro_shocks` directly | 3–5 top-level scenarios, each with 2–3 `sub_scenarios` containing `macro_shocks` |
| **Leaf count** | 3 leaves (one per scenario) | 6–15 leaves (sub-scenarios) |
| **Best for** | Simple UIs, mobile cards, quick summaries | Detailed analysis, drill-down interfaces |
| **Parse complexity** | Flat list — no nesting to traverse | Two levels of nesting |
## Step 4: Search News Scenarios with Portfolio Exposure
Search for curated, pre-computed news scenarios and see how each one affects your portfolio. This is instant (no AI generation) and useful for browsing recent events.
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/scenarios/search" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"queries": [{"weight": 1, "query": "tariffs trade war"}],
"portfolio_weights": {
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
},
"aggregate_scenarios": true,
"limit": 5
}'
```
### Key parameters
| Parameter | Type | Default | Description |
| --------------------- | ------- | ------- | ------------------------------------------------------------------------------------------------------- |
| `queries` | array | — | Weighted search queries. Each has `query` (string) and `weight` (0–1). |
| `subject_code` | string | `null` | Filter by subject code (e.g. `"Technology"`, `"Tariffs & Trade"`). Can be used alone or with `queries`. |
| `portfolio_weights` | object | `null` | Map of `tilt_asset_id` → weight. When provided, each result includes a `portfolio_exposure` field. |
| `aggregate_scenarios` | boolean | `false` | When `true`, collapses the scenario tree into probability-weighted summary stats. |
| `order_by_exposure` | boolean | `false` | When `true`, sorts results by portfolio impact instead of relevance. Requires `portfolio_weights`. |
| `limit` | integer | `10` | Number of results (1–100). |
| `min_importance` | integer | `null` | Filter to scenarios with importance rating >= this value (1–10). |
At least one of `queries` or `subject_code` must be provided. Sending an empty request body will return a `422 Validation Error`.
### Response structure
The response wraps results in `articles`. Each article is a news scenario with timeline, probability tree, and (when `portfolio_weights` is provided) portfolio exposure:
```json theme={null}
{
"success": true,
"articles_found": 5,
"articles": [
{
"point_id": "3fb7a574-c0d7-53b0-96cc-b98a2882f1c7",
"headline": "Nvidia Invests in Mira Murati's Thinking Machines Lab",
"date": "2026-03-10T00:00:00",
"tilt_source": "WSJ",
"importance_rating": 6,
"timeline": [
{"date": "2024-09-28", "summary": "OpenAI CTO Mira Murati resigns amid tensions"},
{"date": "2026-01-26", "summary": "Nvidia invests $2B in CoreWeave for 5GW AI-factories"}
],
"scenarios": [
{
"probability": 34,
"title": "Compute-fueled breakout",
"description": "Thinking Machines converts Nvidia's investment into a fast ramp of training and inference capacity...",
"macro_shocks": [
{"indicator": "rbics_55", "impact": 0.012},
{"indicator": "VIXCLS", "impact": -0.6},
{"indicator": "company_K7TPSX-R", "impact": 0.09}
],
"sub_scenarios": [
{
"probability": 60,
"title": "Frontier model debut",
"description": "...",
"macro_shocks": [...]
}
]
}
],
"portfolio_exposure": {
"expected_return_pct": 0.0049,
"mad_pct": 0.0441,
"num_leaf_scenarios": 8,
"scenario_level_details": [
{
"title": "Compute-fueled breakout",
"probability_pct": 34,
"portfolio_return_mean_pct": 0.0693,
"portfolio_return_std_pct": 0.0309,
"sub_scenario_count": 2
}
]
}
}
]
}
```
**Key fields in `portfolio_exposure`:**
| Field | Description |
| ------------------------ | --------------------------------------------------------------------------------------------------- |
| `expected_return_pct` | Probability-weighted expected portfolio return across all leaf scenarios. Decimal form (0.01 = 1%). |
| `mad_pct` | Mean absolute deviation of returns across leaf scenarios — a measure of outcome uncertainty. |
| `num_leaf_scenarios` | Number of leaf nodes in the scenario tree used for the calculation. |
| `scenario_level_details` | Per-scenario breakdown with mean return, standard deviation, and sub-scenario count. |
[View API Reference →](/api-reference/backchannel/search-scenarios)
## Step 5: Get a Single Scenario with Portfolio Exposure
Once you have a `point_id` from search results, fetch its full detail with portfolio exposure:
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/scenarios/3fb7a574-c0d7-53b0-96cc-b98a2882f1c7" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"include_content": true,
"portfolio_weights": {
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
},
"aggregate_scenarios": false
}'
```
When `aggregate_scenarios` is `false`, the response includes `leaf_details` and `scenario_level_details` within `portfolio_exposure`, giving you the full probability tree with per-leaf portfolio returns.
[View API Reference →](/api-reference/backchannel/get-scenario)
## Step 6: Macro Factor Analysis
### Get Macro Sensitivities
Understand which macro factors your portfolio is most exposed to:
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/risk/sensitivities" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"portfolio_weights": {
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
},
"limit": 5
}'
```
The response ranks macro factors by portfolio-level exposure, showing which factors would move your portfolio the most:
```json theme={null}
{
"success": true,
"type": "portfolio",
"valid_securities": 3,
"total_weight": 1,
"portfolio_macro_exposures": [
{
"macro_factor": "macro_DTWEXBGS",
"description": "US Dollar Index (Trade Weighted)",
"portfolio_exposure": -2.1324,
"top_contributors": [
{"tilt_id": "MH33D6-R", "weight": 0.4, "sensitivity": -2.0164, "contribution": -0.8065},
{"tilt_id": "K7TPSX-R", "weight": 0.25, "sensitivity": -3.1648, "contribution": -0.7912},
{"tilt_id": "P8R3C2-R", "weight": 0.35, "sensitivity": -1.5277, "contribution": -0.5347}
]
}
]
}
```
[View API Reference →](/api-reference/backchannel/get-macro-sensitivities)
### Run a Macro Scenario
Use the sensitivities output to stress-test with specific macro shocks. The `shocks` object maps factor identifiers to shock magnitudes in standard deviations.
The sensitivities endpoint returns factor names with a `macro_` prefix (e.g. `macro_DTWEXBGS`). When passing shocks to the scenario endpoint, **drop the prefix** — use the raw identifier (e.g. `DTWEXBGS`).
```bash theme={null}
curl -X POST "https://tilt.io/api/v1/backchannel/risk/scenario" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"portfolio_weights": {
"MH33D6-R": 0.40,
"P8R3C2-R": 0.35,
"K7TPSX-R": 0.25
},
"shocks": {
"DTWEXBGS": 0.5
},
"include_security_details": true
}'
```
The response shows the expected portfolio return and per-security breakdown:
```json theme={null}
{
"success": true,
"portfolio_expected_return_pct": -1.0662,
"shocks_applied": {
"DTWEXBGS": 0.5
},
"factor_summary": [
{
"factor": "DTWEXBGS",
"type": "fred",
"description": "US Dollar Index (Trade Weighted)",
"shock": 0.5,
"portfolio_impact_pct": -1.0662
}
],
"security_details": [
{
"tilt_id": "MH33D6-R",
"ticker": "AAPL",
"company_name": "Apple, Inc.",
"weight": 0.40,
"expected_return_pct": -0.8066,
"contribution_to_portfolio_pct": -0.3226,
"factor_contributions": {
"DTWEXBGS": -0.8066
}
}
]
}
```
[View API Reference →](/api-reference/backchannel/run-macro-scenario)
## Putting It Together
A typical integration flow:
1. **Resolve tickers** once and cache the `tilt_asset_id` mapping.
2. **Run scenario portfolio analysis** with a plain English description to quickly assess portfolio impact for any hypothetical event. Use `flat_scenarios: true` for the simplest response structure. This is the easiest starting point.
3. **Search news scenarios** with `portfolio_weights` to find real-world events that matter to the portfolio. Use `order_by_exposure: true` to surface the highest-impact stories first.
4. **Fetch individual scenarios** with `portfolio_weights` for detailed drill-down with leaf-level probability breakdowns.
5. **Get macro sensitivities** to understand the portfolio's factor exposures.
6. **Run macro scenarios** to stress-test against specific factor shocks (e.g., "what if the US Dollar Index rises 0.5 standard deviations?").
**Scenario Portfolio Analysis** (Step 2) generates scenarios on-the-fly using AI. The first call takes \~10–15 seconds, but results are automatically cached — subsequent calls for the same scenario return in under 1 second, for any portfolio. **Search Scenarios** (Step 3) returns pre-computed news scenarios instantly. Use scenario portfolio analysis for hypothetical what-if questions, and search scenarios for browsing recent real-world events.
## Rate Limits
All endpoints are rate-limited at **120 requests per minute** per API key. The `scenario_portfolio_analysis` endpoint has an additional limit of **10 requests per minute** to protect the AI generation backend.
If you exceed the limit, you'll receive a `429 Too Many Requests` response:
```json theme={null}
{
"error": "Rate limit exceeded",
"message": "Too many requests. Please slow down and try again."
}
```
## Error Handling
All error responses follow a consistent format:
```json theme={null}
{
"error": "Error type",
"message": "Human-readable description"
}
```
| Status Code | Meaning |
| ----------- | -------------------------------------------------------------- |
| `400` | Bad request (e.g., empty portfolio weights) |
| `401` | Missing or invalid authentication. Use the `X-Api-Key` header. |
| `403` | Invalid API key |
| `415` | Unsupported Content-Type. Use `application/json`. |
| `422` | Validation error with field-level details |
| `429` | Rate limit exceeded |
| `500` | Internal server error |
# Customization Guide
Source: https://docs.tilt.io/customization/guide
An introduction to setting up and optimizing a client portfolio.
## Overview
The Tilt Portfolio Optimization Platform enables you to create personalized portfolio optimizations for your clients. This guide walks through the complete workflow from initial organization setup to generating optimized trade proposals.
## Step 1: Organization Setup
### Configure Asset Classes
We'll start by defining the asset classes available in your organization. An asset class consists of a name, description, and a benchmark that represents it. We'll first search for available benchmark indexes, and then use that to create the asset class.
#### Search Available Benchmarks
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/custom/benchmark_indexes/ \
--header 'X-Api-Key: '
```
[View API Reference →](/api-reference/endpoint/get-benchmark-indexes)
#### Create Asset Classes
Now we can create an asset class using one of our benchmarks. The example below uses `M75BNK-R`, which is the identifier for the `SPY` ETF.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/asset_classes/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"name": "US Equities",
"description": "Example US Equities Asset Class",
"benchmark_index_identifier": "M75BNK-R"
}'
```
[View API Reference →](/api-reference/endpoint/post-asset-class)
## Step 2. Portfolio Setup
Now that we have an asset class, let's create a portfolio which uses that asset class. We can make an example portfolio with a single allocation to US equities, although it is possible to blend multiple asset classes together.
We reference the asset class using it's UUID that was returned when creating it. We can always [list available asset classes](/api-reference/endpoint/get-asset-classes) to retrieve all asset classes.
At this point, we can enable direct indexing per asset class, for this portfolio. Later, we can override this setting per client too.
Direct indexing only takes affect if the underlying benchmark index also supports direct indexing.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/portfolio_configs/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"name": "Example Portfolio",
"asset_allocations": [
{
"asset_class_uuid": "asset-class-uuid",
"target_allocation": "1",
"direct_indexing_enabled": true
}
]
}'
```
[View API Reference →](/api-reference/endpoint/post-portfolio-config)
## Step 3: Client and Account Setup
### Understanding Clients and Accounts
In Tilt, a **client** represents a person or entity in your system, and each client can have one or more **accounts**. Holdings, portfolio assignments, and optimizations all operate at the account level.
When you create a client, a default account is automatically created. The response includes both the client UUID and the account UUID within the `accounts` array.
### Create a Client
Let's create a new client, which will also create a default account. The `external_id` should be a string that represents this client in your system.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/clients/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"external_id": ""
}'
```
The response will include:
* `uuid`: The client UUID
* `accounts`: An array containing the default account with its own `uuid`
When creating a client, we can also provide configuration and holdings information for the default account, but we'll update those separately in this guide.
[View API Reference →](/api-reference/endpoint/post-org-client)
### Update Account Holdings
Now, let's assign the account to a portfolio and update its holdings.
We use the portfolio UUID which was returned when creating the portfolio, or we can find it by [listing the available portfolios](/api-reference/endpoint/get-portfolio-configs).
```bash theme={null}
curl --request PATCH \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid} \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"portfolio_config_uuid": "portfolio-config-uuid",
"holdings": {
"tax_lots": [
{
"tilt_asset_id": "MH33D6-R",
"quantity": "100",
"cost_basis": "250",
"trade_date": "2025-01-01",
"wash_sale_date": "2025-01-01",
"last_sold_for_loss_date": "2025-01-01"
},
{
"tilt_asset_id": "P8R3C2-R",
"quantity": "50",
"cost_basis": "120",
"trade_date": "2025-01-01",
"wash_sale_date": "2025-01-01",
"last_sold_for_loss_date": "2025-01-01"
}
],
"cash_balance": "50000",
"non_tradable_assets_value": "5000"
}
}'
```
`MH33D6-R` and `P8R3C2-R` are the identifiers for Apple and Microsoft respectively. More information on asset identifiers is in the [Tilt Asset IDs](#tilt-asset-ids) section.
[View API Reference →](/api-reference/endpoint/patch-client-account)
### Update Direct Indexing Preference
We may override the direct indexing preferences for an account by updating `asset_class_settings`. For example, we can disable direct indexing for a particular asset class:
```bash theme={null}
curl --request PATCH \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid} \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"asset_class_settings": [
{
"asset_class_uuid": "asset-class-uuid",
"direct_indexing_enabled": false
}
]
}'
```
[View API Reference →](/api-reference/endpoint/patch-client-account)
## Step 4: Portfolio Optimization
We can run optimization either for a single account, or in bulk across many accounts and clients. To start with, let's run the optimization for a single account.
### Single Account Optimization
Run an optimization for an individual account to get customized portfolio weights:
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/optimize/ \
--header 'X-Api-Key: '
```
[View API Reference →](/api-reference/endpoint/post-account-optimize)
### Generate Trade Proposals
Convert the optimized weights into actionable trade proposals.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/clients/{client_uuid}/accounts/{account_uuid}/proposal/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"optimized_weights": {
"MH33D6-R": "0.5",
"P8R3C2-R": "0.5"
}
}'
```
[View API Reference →](/api-reference/endpoint/post-account-proposal)
## Step 5: Bulk Operations
### Bulk Optimization and Proposals
We can optimize clients in bulk by calling the bulk optimize endpoint, passing in a list of client UUIDs. This responds with a list of proposal UUID's, that we can then check the result of.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/optimized_proposals/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"client_uuids": [
"client-uuid-1",
"client-uuid-2",
"client-uuid-3"
]
}'
```
[View API Reference →](/api-reference/endpoint/post-bulk-client-optimize-proposal)
### Check Task Results
We can get the status for each proposal by calling the check status endpoint:
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/optimized_proposals/status/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"uuids": [
"proposal-uuid-1",
"proposal-uuid-2",
"proposal-uuid-3"
]
}'
```
[View API Reference →](/api-reference/endpoint/get-bulk-optimization-status)
To get the result for a generated proposal, we can call the get task result endpoint. This will return both the optimized weights and generated trades for that proposal.
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/optimized_proposals/{proposal_uuid}/ \
--header 'X-Api-Key: '
```
[View API Reference →](/api-reference/endpoint/get-optimization-task-result)
We can also search all generated proposals, and filter them based on criteria such as age, drift or turnover.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/optimized_proposals/list/ \
--header 'Content-Type: application/json' \
--header 'X-Api-Key: ' \
--data '{
"status": "pending",
"created_after": "2025-10-01",
"min_average_drift": "0.1"
}'
```
[View API Reference →](/api-reference/endpoint/search-optimized-proposals)
## Configuration Hierarchy
Optimization configuration can be set on the account-level, portfolio-level, and organization level, and are merged together based on this order of precedence:
1. **Account config** (highest priority)
2. **Portfolio config**
3. **Organization config** (fallback defaults)
The configs are represented by the same schema, so all config values can be overriden at each level. The account and organization config is set in the `customization_config` field in their respective schemas.
Note that account and organization values outside of `customization_config` are unique to the account or organization, and are not merged. For example, `factor_values` is a top-level field in the organization schema. It is set globally for the organization, and cannot be overridden. Most properties are set via config however, and can be flexibly overridden as needed.
For list values (e.g., `no_trade` assets), the system uses the most specific non-empty list available. For example, if an account has any `no_trade` assets defined, these completely replace any organization-level `no_trade` assets rather than merging.
You can also set **dynamic rules** on configs at any level to make parameter values change automatically based on time schedules and conditions. See the [Dynamic Rules Guide](/dynamic-rules/guide) for details.
## Tilt Asset IDs
We use asset IDs throughout the API to identify assets, rather than symbols. We can use the [search tickers endpoint](/api-reference/endpoint/search-tickers) to find the tilt asset ID corresponding to a certain ticker symbol.
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/tickers/search?symbols=MSFT&ticker_types=common_stock \
--header 'X-Api-Key: '
```
# Dynamic Rules Guide
Source: https://docs.tilt.io/dynamic-rules/guide
Automatically adjust optimization parameters based on time schedules and conditions.
## Overview
Dynamic rules let you make optimization config values change automatically based on **time** (cron schedules) and **conditions** (expressions evaluated against portfolio context). Instead of manually updating configs when market conditions change or calendar events occur, you define rules that activate automatically.
Common use cases:
* Increase tax-loss harvesting aggressiveness in December
* Adjust position weight limits based on AUM
* Change optimization mode based on portfolio characteristics
* Apply different parameters for accounts meeting specific criteria
## Rule Structure
Dynamic rules are attached to a config (organization, portfolio, or account level) via the `dynamic_rules` array. Each entry targets a specific config field and contains one or more rules:
```json theme={null}
{
"dynamic_rules": [
{
"field_name": "max_weight",
"rules": [
{
"cron": "",
"condition": "aum > 1000000",
"value": 0.08,
"priority": 0
},
{
"cron": "",
"condition": "aum > 5000000",
"value": 0.05,
"priority": 1
}
]
}
]
}
```
### Fields
| Field | Type | Required | Description |
| ------------ | ------ | -------- | -------------------------------------------------------------------------------- |
| `field_name` | string | Yes | Config field to set dynamically (e.g. `max_weight`, `tax_preferences.tax_gamma`) |
| `rules` | array | Yes | One or more rule entries |
### Rule Entry Fields
| Field | Type | Required | Default | Description |
| ----------- | ------- | -------- | ------- | ------------------------------------------------------------------------------------- |
| `cron` | string | No | `""` | Cron expression for time-based activation (e.g. `* * * 12 *` for December) |
| `condition` | string | No | `""` | Boolean expression evaluated against context variables (e.g. `aum > 1000000`) |
| `value` | any | Yes | — | Value to apply when the rule matches |
| `priority` | integer | No | `0` | Evaluation order (0-9999). Lowest number is evaluated first; first matching rule wins |
A rule matches when **both** its cron schedule and condition are satisfied. An empty cron or condition field is treated as always matching, but at least one of the two must be provided.
## Rule Resolution
For each dynamic rule field (e.g. `max_weight`), the system follows a three-step resolution path:
### Step 1: Collect rules from all config levels
Rules from every config level are gathered and given a priority offset so that higher-level configs always take precedence:
| Config level | Priority offset | Precedence |
| --------------- | ----------------- | ---------- |
| Account rules | priority + 0 | Highest |
| Portfolio rules | priority + 10,000 | Middle |
| Org rules | priority + 20,000 | Lowest |
### Step 2: Find first static value and prune
Walk the config chain from most specific to least. The first level that sets a static value for the field becomes the default. Rules from levels **below** that level are pruned — rules at the same level still apply.
```
Account config has field?
|
|-- YES --> default = account value
| prune rules with priority >= 10,000
| (portfolio + org rules removed; account rules survive)
|
NO
|
v
Portfolio config has field?
|
|-- YES --> default = portfolio value
| prune rules with priority >= 20,000
| (org rules removed; account + portfolio rules survive)
|
NO
|
v
Org config has field?
|
|-- YES --> default = org value
| no pruning needed (nothing below org)
| (all rules survive)
|
NO
|
v
default = None (no static value anywhere, no rules pruned)
```
### Step 3: Evaluate remaining rules
Remaining rules are sorted by priority ascending. **First matching rule wins** — the first rule whose cron and condition both evaluate to true is used. If no rule matches, the default value from step 2 is used.
**Key concepts:**
* **Priority offsets**: Account rules keep their raw priority, portfolio rules add 10,000, and org rules add 20,000. This means account-level rules are always evaluated before lower levels.
* **Static value pruning**: When a static value is found at a config level, rules from levels below are pruned. Rules at the same level as the static value still apply. This prevents lower-level dynamic rules from overriding an explicit static value set at a higher level.
* **First match wins**: Rules are evaluated in ascending priority order. The first rule whose cron and condition both match is used.
* **Fallback**: If no rule matches, the static default value from step 2 is used.
## Supported Fields
### Config Fields
Dynamic rules can target any config field, including:
* `max_weight`, `min_weight` — position weight limits
* `optimization_mode` — optimization strategy
* `tax_gamma` — tax-loss harvesting aggressiveness
* `cash_buffer`, `cash_buffer_usd`, `cash_buffer_cad` — cash reserves
* `round_lot_size` — trade rounding
### Tax Preference Fields
Use the `tax_preferences.` prefix for tax preference fields:
* `tax_preferences.tax_gamma`
* `tax_preferences.short_term_rate`
* `tax_preferences.long_term_rate`
Use the [Get Dynamic Rules Schema](/api-reference/endpoint/get-dynamic-rules-schema) endpoint to discover all supported fields, available context variables, functions, and operators for your organization.
## Context Variables
Conditions in dynamic rules are evaluated against context variables that describe the portfolio and account at optimization time.
### Portfolio-Level Variables
Variables like `aum`, `cash_balance`, and `position_count` describe the current state of the portfolio being optimized.
### Account-Level Variables
Variables like `organization_name` and `client_external_id` describe the account and organization.
### Fundamental Per-Ticker Variables
Variables like `market_cap` and `pe_ratio` provide fundamental data for individual securities. These are available when rules are evaluated at the ticker level.
### Enrichment Columns
Custom enrichment data columns uploaded to your organization are also available as context variables.
The exact set of available variables depends on your organization's configuration. Use the schema endpoint to discover what's available.
## Workflow
### Step 1: Explore the Schema
Discover available fields, variables, operators, and functions:
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/schema/ \
--header 'X-Api-Key: '
```
[View API Reference →](/api-reference/endpoint/get-dynamic-rules-schema)
The response includes:
* **fields**: Config fields that support dynamic rules
* **variables**: Context variables available in conditions
* **functions**: Functions you can use in expressions (e.g. `abs()`, `max()`)
* **operators**: Supported operators (`>`, `<`, `==`, `and`, `or`, etc.)
* **examples**: Example expressions
### Step 2: Validate Expressions
Before deploying rules, validate that your condition expressions are syntactically correct:
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/validate/ \
--header 'X-Api-Key: ' \
--header 'Content-Type: application/json' \
--data '{
"expression": "aum > 1000000 and position_count < 50"
}'
```
[View API Reference →](/api-reference/endpoint/post-dynamic-rules-validate)
You can also pass a `sample_context` to test evaluation:
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/validate/ \
--header 'X-Api-Key: ' \
--header 'Content-Type: application/json' \
--data '{
"expression": "aum > 1000000",
"sample_context": {"aum": 2000000}
}'
```
### Step 3: Attach Rules to a Config
Add dynamic rules when creating or updating a config at any level. For example, to add rules to a portfolio config:
```bash theme={null}
curl --request PATCH \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/portfolio_configs/{config_uuid}/ \
--header 'X-Api-Key: ' \
--header 'Content-Type: application/json' \
--data '{
"customization_config": {
"dynamic_rules": [
{
"field_name": "max_weight",
"rules": [
{
"condition": "aum > 1000000",
"value": 0.08,
"priority": 0
}
]
}
]
}
}'
```
### Step 4: Simulate Rule Evaluation
Test how rules resolve for a specific account and date without running an optimization:
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/simulate/ \
--header 'X-Api-Key: ' \
--header 'Content-Type: application/json' \
--data '{
"client_account_uuid": "account-uuid-here",
"trade_date": "2025-12-15"
}'
```
[View API Reference →](/api-reference/endpoint/post-dynamic-rules-simulate)
The response shows:
* **resolved\_values**: The final config values after rule evaluation
* **context**: The context variables used during evaluation
* **rule\_evaluations**: Which rules matched and which didn't, with details
You can also pass `dynamic_rules` directly to simulate rules that haven't been saved yet.
### Step 5: Preview Optimization Impact
See how dynamic rules affect actual optimization results by comparing scenarios. Preview runs asynchronously — you submit a job, then poll for results.
#### Submit a preview job
POST your scenarios to create a preview job. Each scenario requires a `label` and `context_overrides` (e.g. to vary `aum` or `trade_date`). You can optionally include `as_of_datetime`, `fundamentals_overrides`, and `config_overrides`.
```bash theme={null}
curl --request POST \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/ \
--header 'X-Api-Key: ' \
--header 'Content-Type: application/json' \
--data '{
"client_account_uuid": "account-uuid-here",
"scenarios": [
{
"label": "Summer baseline",
"context_overrides": {"trade_date": "2025-06-15"}
},
{
"label": "Year-end TLH",
"context_overrides": {"trade_date": "2025-12-15"}
}
],
"include_baseline": true
}'
```
The endpoint returns `202 Accepted` with a job object:
```json theme={null}
{
"id": "job-uuid",
"status": "PENDING",
"params": { ... },
"result": null,
"error_message": null,
"created_at": "2025-06-01T12:00:00Z",
"started_at": null,
"finished_at": null
}
```
[View API Reference →](/api-reference/endpoint/post-dynamic-rules-preview)
#### Poll for results
Use the job ID to check status and retrieve results:
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/{job_id}/ \
--header 'X-Api-Key: '
```
| Status | Meaning |
| --------- | ---------------------------------------------- |
| `PENDING` | Job is queued |
| `RUNNING` | Optimization is in progress |
| `SUCCESS` | Results are available in the `result` field |
| `FAILURE` | Job failed — check `error_message` for details |
Poll every 2–5 seconds. Most preview jobs complete within 30 seconds.
[View API Reference →](/api-reference/endpoint/get-dynamic-rules-preview-job)
#### List previous jobs
Browse your organization's preview job history:
```bash theme={null}
curl --request GET \
--url https://api.tilt.io/api/v1/custom/org/{organization_uuid}/dynamic_rules/preview/jobs/ \
--header 'X-Api-Key: '
```
[View API Reference →](/api-reference/endpoint/list-dynamic-rules-preview-jobs)
## Examples
### Year-End Tax-Loss Harvesting
Increase the tax-loss harvesting aggressiveness during December:
```json theme={null}
{
"dynamic_rules": [
{
"field_name": "tax_preferences.tax_gamma",
"rules": [
{
"cron": "* * * 12 *",
"value": 5.0,
"priority": 0
}
]
}
]
}
```
**Resolution in December (e.g. trade date 2025-12-15):**
```
Rule priority 0: cron "* * * 12 *" → matches → value = 5.0 ✓ MATCH
────────
Result: tax_gamma = 5.0
```
**Resolution outside December (e.g. trade date 2025-06-15):**
```
Rule priority 0: cron "* * * 12 *" → does not match → skipped
No rules matched → use default from static config
```
### AUM-Based Weight Limits
Tighten position concentration limits for larger portfolios:
```json theme={null}
{
"dynamic_rules": [
{
"field_name": "max_weight",
"rules": [
{
"condition": "aum > 1000000",
"value": 0.08,
"priority": 0
},
{
"condition": "aum > 5000000",
"value": 0.05,
"priority": 1
}
]
}
]
}
```
**Resolution for a portfolio with 2M AUM:**
```
Rule priority 0: condition "aum > 1000000" → true → value = 0.08 ✓ MATCH
────────
Result: max_weight = 0.08
```
**Resolution for a portfolio with 10M AUM:**
```
Rule priority 0: condition "aum > 1000000" → true → value = 0.08 ✓ MATCH
────────
Result: max_weight = 0.08
```
Both portfolios match the first rule. If you want different behavior for larger portfolios, put the more specific condition at a lower priority number so it matches first:
```json theme={null}
{
"dynamic_rules": [
{
"field_name": "max_weight",
"rules": [
{
"condition": "aum > 5000000",
"value": 0.05,
"priority": 0
},
{
"condition": "aum > 1000000",
"value": 0.08,
"priority": 1
}
]
}
]
}
```
Now a 10M AUM portfolio matches priority 0 first and gets `0.05`, while a 2M AUM portfolio skips priority 0 and matches priority 1 for `0.08`.
### Multi-Level Rules with Static Value Pruning
This example shows how rules accumulate across config levels and how a static value prunes lower-level rules.
**Config state for `max_weight`:**
```
Account: rule {cron: Dec → 0.50, priority: 1} max_weight = NULL
Portfolio: rule {always → 0.06, priority: 1} max_weight = 0.05
Org: rule {always → 0.03, priority: 1} max_weight = NULL
```
**Step 1 — Collect and offset rules:**
```
Account rule: {cron: Dec, value: 0.50, priority: 1 + 0 = 1}
Portfolio rule: {always, value: 0.06, priority: 1 + 10000 = 10001}
Org rule: {always, value: 0.03, priority: 1 + 20000 = 20001}
```
**Step 2 — Find static value and prune:**
```
Account config → max_weight = NULL → skip
Portfolio config → max_weight = 0.05 → default = 0.05
Prune rules with priority ≥ 10,000
├── Portfolio rule (pri 10001) → PRUNED
└── Org rule (pri 20001) → PRUNED
Remaining rules: [{cron: Dec, value: 0.50, priority: 1}]
Default value: 0.05
```
**Step 3 — Evaluate remaining rules:**
**In December:**
```
Rule priority 1: cron "Dec" → matches → value = 0.50 ✓ MATCH
────────
Result: max_weight = 0.50
```
**In June:**
```
Rule priority 1: cron "Dec" → does not match → skipped
No rules matched → use default
────────
Result: max_weight = 0.05 (portfolio static)
```
The portfolio's static `max_weight = 0.05` serves two purposes: it becomes the fallback default, and it prunes both the portfolio-level and org-level dynamic rules. Only the account-level rule (which has higher precedence) survives.
## Best Practices
* **Simulate before deploying** — Always use the simulate endpoint to verify rule behavior before saving rules to a config. Check that the right rules match and produce expected values.
* **Start priorities at 0** — Use sequential integers starting from 0 (0, 1, 2, ...). You can leave gaps if you anticipate inserting rules later.
* **Understand static blocking** — Be intentional about static values at higher config levels, as they suppress dynamic rules from lower levels for that field.
* **Use the schema endpoint** — Discover available fields and variables programmatically rather than hardcoding. The available set may expand over time.
* **Keep conditions simple** — Prefer clear, readable expressions. Use the validate endpoint to catch syntax errors early.
# Introduction
Source: https://docs.tilt.io/introduction
RESTful API for accessing real-time index data, levels, constituents, and corporate actions. Built for financial professionals and institutions managing index-based portfolios.
## Welcome
The API provides programmatic access to detailed information for indices you've subscribed to. This API allows you to retrieve index levels, constituents, and corporate actions to help you utilize your indexes.
## Getting Started
To begin using the API:
1. Ensure you have an active Tilt subscription
2. Follow our [Quick Start Guide](/quick-start) for a step-by-step walkthrough
Get up and running with the Tilt API in minutes
Explore the complete list of API endpoints
# Quick Start
Source: https://docs.tilt.io/quick-start
Quickly start using the API by following this step by step guide
## Overview
### Base URL
```bash theme={null}
https://api.tilt.io
```
### Authentication
All API endpoints require authentication using an API token. Include your API token in the header of each request:
```bash theme={null}
x-api-key:
```
### Getting Your API Token
1. Log in to your [Tilt dashboard](https://tilt.io)
2. Click the gear icon in the bottom left of the dashboard
3. Select `API Keys` from the menu
4. Enter API key name and create a new key
Keep your API token secure and never share it publicly. If your token is compromised,
you can revoke it and generate a new one from your dashboard.
## Making Your First API Calls
### 1. List Indexes
Get a list of all indexes you have access to:
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/indexes" \
-H "x-api-key: YOUR_API_TOKEN"
```
[View full API reference →](/api-reference/endpoint/list-indexes)
### 2. Get Index Details
Fetch detailed information about a specific index:
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/indexes/{index_uuid}" \
-H "x-api-key: YOUR_API_TOKEN"
```
Replace `{index_uuid}` with an actual index ID from step 1.
[View full API reference →](/api-reference/endpoint/get-index-details)
### 3. Get Index Levels
Retrieve the levels for your index:
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/indexes/{index_id}/levels" \
-H "x-api-key: YOUR_API_TOKEN"
```
Replace `{index_id}` with the same index ID you used in step 2.
[View full API reference →](/api-reference/endpoint/get-index-levels)
### 4. Get Index Constituents
Retrieve constituents for your index:
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/indexes/{index_id}/constituents" \
-H "x-api-key: YOUR_API_TOKEN"
```
[View full API reference →](/api-reference/endpoint/get-index-constituents)
### 5. Get Index Corporate Actions
Retrieve corporate actions for your index:
```bash theme={null}
curl -X GET "https://api.tilt.io/api/v1/indexes/{index_id}/corporate-actions" \
-H "x-api-key: YOUR_API_TOKEN"
```
[View full API reference →](/api-reference/endpoint/get-index-corporate-actions)
### Important Reminders
Remember to replace `YOUR_API_TOKEN` with your actual API token in all requests.