This is the discovery call: unpriced. Returns a single denormalized
blob with the portfolio, the holdings in shares, the active
scenario’s rules, the recorded levels, and monitor configuration.
current_price, position_value and position_pct on every
non-cash position, total_value, exposure, compliance, and every
monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price
lists every symbol you would need to price to see the rest. A held
option is the exception: it is priced at its mark, the user’s own
number, so it keeps its current_price and position_value here,
and expired_on and expired_options show what has expired
(ADR-147).
Allocait never fills a symbol from its own market data on this
surface (ADR-036). The flow is two calls: GET this to see what’s
held, then POST here with prices for the symbols it listed (or
call /compliance/check / /rebalance/preview directly, which
require full coverage).
The rebalance block (sized amounts) is left out unless you add
include_rebalance=true. Ask for it when the person wants to know
what it would take to get back inside a band; a check answer comes
from compliance (ADR-113).
The monitors block reports where each recorded level stands at the
prices you pass. It is a reading, not a break. A break is confirmed
only by the once-daily close check, which this endpoint does not
report. GET /monitors returns each monitor’s full configuration.
If scenario_id is omitted, the portfolio’s active_scenario_id is used.
GET
/
portfolio
/
snapshot
Get a portfolio snapshot (unpriced)
curl --request GET \ --url https://allocait.app/api/v1/portfolio/snapshot \ --header 'x-api-key: <api-key>'
Raw API key shown once when created in the Allocait app (Settings > API keys). Send it verbatim in this header; the server stores and compares only its SHA-256 hash. Allocait generates every key: alc_ followed by 64 lowercase hex characters. Keys issued before 2026-10-10 are 64 hex characters with no prefix and keep working. A key may carry an expiry (90 days or 1 year, or never). A malformed, unknown, revoked or expired key gets 401 with no further detail, and a malformed one is refused before any lookup. Keys cannot be created through this API.
Add the rebalance block. Default false. Any other value than true or false is a 400.
Response
Portfolio snapshot
Single denormalized blob: portfolio + positions + rules +
compliance violations + condition monitors, and rebalance amounts
when the request sets include_rebalance=true.
The agent's primary "look at the world" response. See ADR-007
and ADR-026. A check answer comes from compliance; sized amounts
are there only when asked for (ADR-113). prices_complete / unpriced_symbols (the fields
ComplianceResponse / RebalanceResponse both omit for the same
reason) are not carried on this surface either: both are computed
from Allocait's own stored quote, not from your coverage of it, so
neither can be scrubbed the way current_price, total_value and
exposure are; use symbols_to_price instead (ADR-036).
The portfolio header as carried inside PortfolioSnapshot.portfolio.
PortfolioSummary without position_count; the RPC builds this
object itself and does not count positions here.
Null when any non-cash position is unpriced; a value spanning the whole portfolio can't stand on one stored quote (ADR-036). Present only once every non-cash position is covered by your prices map or owns its price (an option with a mark, or an expired one, ADR-147). Signed, since shorts subtract, so it can be zero or negative. At zero or less every position_pct is null and compliance reads unjudged (ADR-153).
How much of the portfolio gains if prices rise, as percents of its
value: long, short, net and gross, by asset class and per holding.
A reading, not a rule; there is no range, cap or status to compare
it with. Always present. Null unless your prices map holds a
number for every non-cash holding, and while any holding is
unpriced, even where Allocait holds a quote of its own that could
fill the gap: every percent is a share of the whole book, so one
stored quote would reach all of them (ADR-036, ADR-142). A holding
that owns its price, an option with a mark or an expired one,
counts as covered. Options count at their premium (ADR-147).
Computed from your prices and the user's marks, and never stored.
overrides once every symbol this response needed came from
your prices map (symbols_to_price is then empty);
unpriced while at least one still does not. Allocait's own
stored quote (market_data) never appears on this surface
(ADR-036).
Every symbol, sorted, that you would need to add to prices to clear every null from this response. Empty once the payload is entirely your own numbers.
How many held options have passed their expiry (expired_on set, shares not 0). The user's own record, so it needs no price and is present whatever else is null. Allocait changes nothing on them and sends no alert; the person decides what each became (ADR-147).
Null when any non-cash position is unpriced. An {error}
object when the portfolio has no scenario to evaluate against.
Otherwise the shape POST /compliance/check returns, computed
from this request's prices, including status, issue_count
and unchecked.
Present only when the request sets include_rebalance=true
(ADR-113); left out otherwise. Same nullability as
compliance: null when any non-cash position is unpriced, an
{error} object when no scenario is set, otherwise the same
shape POST /rebalance/preview returns, computed from this
request's prices.
Each condition monitor measured against the levels and ranges
the user recorded, at the price you passed for its symbol (null,
unmeasured, if you did not). One entry per (monitor, resolved
symbol); [] when the portfolio has no monitors. See ADR-020
and ADR-026.
The portfolio's playbooks with at least one blank cell today
(US Eastern, or the playbook's pinned date), as the playbook's
needs_input counts them: blank cells of Inputs that are not
optional. [] when none. The user's own recorded data, never
priced (ADR-204).
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Allocait","description":"Allocait checks a portfolio against the owner's own allocation rules. This site documents the REST API agents call and how to connect Claude, ChatGPT and Codex to it.","colors":{"primary":"#0b0b0b","light":"#ffc629","dark":"#0b0b0b"},"logo":{"light":"https://mintcdn.com/allocait/N9X8GrpLUSiZAKIm/logo/light.svg?fit=max\u0026auto=format\u0026n=N9X8GrpLUSiZAKIm\u0026q=85\u0026s=37c68a7ac5dc3550d24f484060530ea6","dark":"https://mintcdn.com/allocait/N9X8GrpLUSiZAKIm/logo/dark.svg?fit=max\u0026auto=format\u0026n=N9X8GrpLUSiZAKIm\u0026q=85\u0026s=64ac292a0a27672b4ff7d318734b0a5a","href":"https://allocait.app"},"favicon":"https://mintcdn.com/allocait/N9X8GrpLUSiZAKIm/logo/favicon.svg?fit=max\u0026auto=format\u0026n=N9X8GrpLUSiZAKIm\u0026q=85\u0026s=ff094ad764f4dfe37dbf99bdd5c9aaf4","api":{"playground":{"display":"simple"}},"appearance":{"default":"dark"},"background":{"color":{"light":"#ffffff","dark":"#09090b"}},"navbar":{"links":[{"href":"mailto:support@allocait.app","label":"Support"}],"primary":{"type":"button","label":"allocait.app","href":"https://allocait.app"}},"footer":{"links":[{"header":"Product","items":[{"label":"allocait.app","href":"https://allocait.app"},{"label":"Support","href":"mailto:support@allocait.app"}]}]},"icons":{"library":"tabler"},"contextual":{"options":["copy","view","chatgpt","claude","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":true},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"allocait","hasAudioNarration":false,"actualSubdomain":"allocait","customDomains":["docs.allocait.app"],"gitSource":{"type":"github","owner":"allocait-app","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"entitlements":{"AI_CHAT":{"status":"DISABLED"},"WEB_MCP":{"status":"DISABLED"},"NARRATION":{"status":"DISABLED"}},"buildId":"6af158c3927786a3649023cd","clientVersion":"0.0.4102","searchFilterCounts":[{"language":"default","tag":"API reference","count":95},{"language":"default","tag":"Endpoints","count":84},{"language":"default","tag":"Concepts","count":24},{"language":"default","tag":"Claude \u0026 MCP","count":23},{"language":"default","tag":"Rules","count":22},{"language":"default","tag":"Guides","count":13},{"language":"default","tag":"Tools","count":12},{"language":"default","tag":"Inputs","count":12},{"language":"default","tag":"ChatGPT \u0026 Codex","count":10},{"language":"default","tag":"Watchlists","count":9}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-rbac-roles","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"img.nav-logo{height:1rem!important;width:auto!important}.callout[data-callout-type=\"note\"],.callout[data-callout-type=\"info\"],.callout[data-callout-type=\"tip\"]{background-color:rgb(255 198 41 / 0.2)!important;border-color:rgb(255 198 41 / 0.6)!important}.callout[data-callout-type=\"note\"] *,.callout[data-callout-type=\"info\"] *,.callout[data-callout-type=\"tip\"] *{color:#0b0b0b!important}.callout[data-callout-type=\"note\"] svg,.callout[data-callout-type=\"info\"] svg,.callout[data-callout-type=\"tip\"] svg{fill:#0b0b0b!important}html.dark .callout[data-callout-type=\"note\"],html.dark .callout[data-callout-type=\"info\"],html.dark .callout[data-callout-type=\"tip\"]{background-color:rgb(255 198 41 / 0.1)!important;border-color:rgb(255 198 41 / 0.35)!important}html.dark .callout[data-callout-type=\"note\"] *,html.dark .callout[data-callout-type=\"info\"] *,html.dark .callout[data-callout-type=\"tip\"] *{color:#ffc629!important}html.dark .callout[data-callout-type=\"note\"] svg,html.dark .callout[data-callout-type=\"info\"] svg,html.dark .callout[data-callout-type=\"tip\"] svg{fill:#ffc629!important}"}],"page":{"pagePath":"api-reference/portfolios/get-a-portfolio-snapshot-unpriced","slug":"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced","pageMetadata":{"title":"Get a portfolio snapshot (unpriced)","description":"This is the discovery call: unpriced. Returns a single denormalized\nblob with the portfolio, the holdings in shares, the active\nscenario's rules, the recorded levels, and monitor configuration.\n`current_price`, `position_value` and `position_pct` on every\nnon-cash position, `total_value`, `exposure`, `compliance`, and every\nmonitor measurement all come back null (and `rebalance`, when you ask for it). `symbols_to_price`\nlists every symbol you would need to price to see the rest. A held\noption is the exception: it is priced at its `mark`, the user's own\nnumber, so it keeps its `current_price` and `position_value` here,\nand `expired_on` and `expired_options` show what has expired\n(ADR-147).\n\nAllocait never fills a symbol from its own market data on this\nsurface (ADR-036). The flow is two calls: GET this to see what's\nheld, then POST here with `prices` for the symbols it listed (or\ncall `/compliance/check` / `/rebalance/preview` directly, which\nrequire full coverage).\n\nThe `rebalance` block (sized amounts) is left out unless you add\n`include_rebalance=true`. Ask for it when the person wants to know\nwhat it would take to get back inside a band; a check answer comes\nfrom `compliance` (ADR-113).\n\nThe `monitors` block reports where each recorded level stands at the\nprices you pass. It is a reading, not a break. A break is confirmed\nonly by the once-daily close check, which this endpoint does not\nreport. `GET /monitors` returns each monitor's full configuration.\n\nIf `scenario_id` is omitted, the portfolio's `active_scenario_id` is used.\n","deprecated":null,"version":null,"openapi":"/openapi.yaml get /portfolio/snapshot","href":"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"This is the discovery call: unpriced. Returns a single denormalized\\nblob with the portfolio, the holdings in shares, the active\\nscenario’s rules, the recorded levels, and monitor configuration.\\n\", _jsx(_components.code, {\n children: \"current_price\"\n }), \", \", _jsx(_components.code, {\n children: \"position_value\"\n }), \" and \", _jsx(_components.code, {\n children: \"position_pct\"\n }), \" on every\\nnon-cash position, \", _jsx(_components.code, {\n children: \"total_value\"\n }), \", \", _jsx(_components.code, {\n children: \"exposure\"\n }), \", \", _jsx(_components.code, {\n children: \"compliance\"\n }), \", and every\\nmonitor measurement all come back null (and \", _jsx(_components.code, {\n children: \"rebalance\"\n }), \", when you ask for it). \", _jsx(_components.code, {\n children: \"symbols_to_price\"\n }), \"\\nlists every symbol you would need to price to see the rest. A held\\noption is the exception: it is priced at its \", _jsx(_components.code, {\n children: \"mark\"\n }), \", the user’s own\\nnumber, so it keeps its \", _jsx(_components.code, {\n children: \"current_price\"\n }), \" and \", _jsx(_components.code, {\n children: \"position_value\"\n }), \" here,\\nand \", _jsx(_components.code, {\n children: \"expired_on\"\n }), \" and \", _jsx(_components.code, {\n children: \"expired_options\"\n }), \" show what has expired\\n(ADR-147).\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Allocait never fills a symbol from its own market data on this\\nsurface (ADR-036). The flow is two calls: GET this to see what’s\\nheld, then POST here with \", _jsx(_components.code, {\n children: \"prices\"\n }), \" for the symbols it listed (or\\ncall \", _jsx(_components.code, {\n children: \"/compliance/check\"\n }), \" / \", _jsx(_components.code, {\n children: \"/rebalance/preview\"\n }), \" directly, which\\nrequire full coverage).\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The \", _jsx(_components.code, {\n children: \"rebalance\"\n }), \" block (sized amounts) is left out unless you add\\n\", _jsx(_components.code, {\n children: \"include_rebalance=true\"\n }), \". Ask for it when the person wants to know\\nwhat it would take to get back inside a band; a check answer comes\\nfrom \", _jsx(_components.code, {\n children: \"compliance\"\n }), \" (ADR-113).\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"The \", _jsx(_components.code, {\n children: \"monitors\"\n }), \" block reports where each recorded level stands at the\\nprices you pass. It is a reading, not a break. A break is confirmed\\nonly by the once-daily close check, which this endpoint does not\\nreport. \", _jsx(_components.code, {\n children: \"GET /monitors\"\n }), \" returns each monitor’s full configuration.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"If \", _jsx(_components.code, {\n children: \"scenario_id\"\n }), \" is omitted, the portfolio’s \", _jsx(_components.code, {\n children: \"active_scenario_id\"\n }), \" is used.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Get a portfolio snapshot (unpriced)","description":"This is the discovery call: unpriced. Returns a single denormalized\nblob with the portfolio, the holdings in shares, the active\nscenario's rules, the recorded levels, and monitor configuration.\n`current_price`, `position_value` and `position_pct` on every\nnon-cash position, `total_value`, `exposure`, `compliance`, and every\nmonitor measurement all come back null (and `rebalance`, when you ask for it). `symbols_to_price`\nlists every symbol you would need to price to see the rest. A held\noption is the exception: it is priced at its `mark`, the user's own\nnumber, so it keeps its `current_price` and `position_value` here,\nand `expired_on` and `expired_options` show what has expired\n(ADR-147).\n\nAllocait never fills a symbol from its own market data on this\nsurface (ADR-036). The flow is two calls: GET this to see what's\nheld, then POST here with `prices` for the symbols it listed (or\ncall `/compliance/check` / `/rebalance/preview` directly, which\nrequire full coverage).\n\nThe `rebalance` block (sized amounts) is left out unless you add\n`include_rebalance=true`. Ask for it when the person wants to know\nwhat it would take to get back inside a band; a check answer comes\nfrom `compliance` (ADR-113).\n\nThe `monitors` block reports where each recorded level stands at the\nprices you pass. It is a reading, not a break. A break is confirmed\nonly by the once-daily close check, which this endpoint does not\nreport. `GET /monitors` returns each monitor's full configuration.\n\nIf `scenario_id` is omitted, the portfolio's `active_scenario_id` is used.\n","deprecated":null,"version":null,"openapi":"/openapi.yaml get /portfolio/snapshot","href":"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"tags":["Portfolios"],"operationId":"getPortfolioSnapshot","summary":"Get a portfolio snapshot (unpriced)","description":"This is the discovery call: unpriced. Returns a single denormalized\nblob with the portfolio, the holdings in shares, the active\nscenario's rules, the recorded levels, and monitor configuration.\n`current_price`, `position_value` and `position_pct` on every\nnon-cash position, `total_value`, `exposure`, `compliance`, and every\nmonitor measurement all come back null (and `rebalance`, when you ask for it). `symbols_to_price`\nlists every symbol you would need to price to see the rest. A held\noption is the exception: it is priced at its `mark`, the user's own\nnumber, so it keeps its `current_price` and `position_value` here,\nand `expired_on` and `expired_options` show what has expired\n(ADR-147).\n\nAllocait never fills a symbol from its own market data on this\nsurface (ADR-036). The flow is two calls: GET this to see what's\nheld, then POST here with `prices` for the symbols it listed (or\ncall `/compliance/check` / `/rebalance/preview` directly, which\nrequire full coverage).\n\nThe `rebalance` block (sized amounts) is left out unless you add\n`include_rebalance=true`. Ask for it when the person wants to know\nwhat it would take to get back inside a band; a check answer comes\nfrom `compliance` (ADR-113).\n\nThe `monitors` block reports where each recorded level stands at the\nprices you pass. It is a reading, not a break. A break is confirmed\nonly by the once-daily close check, which this endpoint does not\nreport. `GET /monitors` returns each monitor's full configuration.\n\nIf `scenario_id` is omitted, the portfolio's `active_scenario_id` is used.\n","parameters":["43134c54-f47b-4b7e-a66c-f707450f9acc","a2153f0e-53e4-45fa-83a7-e2f6e0c0fd0c","f8c8bb5c-74f3-425d-b90d-96d859bcf841"],"responses":{"200":"a6f4681d-92c9-4ff6-a72c-337ca4c55a8f","400":"fc5451e6-8adf-4f62-b392-ae69cfc45c53","401":"d3522f3c-a35f-4521-87fa-c0b1baa15ceb","403":"f48a9c89-17a0-432e-8f18-083fb977d05c","404":"7451dd6c-fc52-43ff-9339-2842e7b83354","429":"adf0e1a7-dd9b-4d12-be97-c77d76b177bc","500":"9f31cad5-29e7-4fb4-aaf5-ebebf2039deb"},"method":"get","type":"path","servers":["13120e45-325e-41e1-99fd-a11d6f409d02"],"security":["7fd1832f-5a87-49c5-91d9-dd9065c02713"],"path":"/portfolio/snapshot","baseUrlOptions":["https://allocait.app/api/v1"],"title":"Get a portfolio snapshot (unpriced)","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"43134c54-f47b-4b7e-a66c-f707450f9acc":{"name":"portfolio_id","in":"query","required":true,"schema":{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"","typeLabel":"string\u003cuuid>"}},"a2153f0e-53e4-45fa-83a7-e2f6e0c0fd0c":{"name":"scenario_id","in":"query","required":false,"description":"Defaults to the portfolio's active scenario","schema":{"type":"string","format":"uuid","isRequired":false,"description":"Defaults to the portfolio's active scenario","uniqueKey":"","typeLabel":"string\u003cuuid>"}},"f8c8bb5c-74f3-425d-b90d-96d859bcf841":{"name":"include_rebalance","in":"query","required":false,"description":"Add the `rebalance` block. Default `false`. Any other value than `true` or `false` is a `400`.","schema":{"type":"boolean","isRequired":false,"description":"Add the `rebalance` block. Default `false`. Any other value than `true` or `false` is a `400`.","uniqueKey":"","typeLabel":"boolean"}}},"responses":{"a6f4681d-92c9-4ff6-a72c-337ca4c55a8f":{"description":"Portfolio snapshot","headers":{"X-RateLimit-Limit":{"description":"The per-minute request budget, always `60`. Sent on every response that reaches a route and on the per-minute `429`.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Requests left in the current one-minute window, after this one. The daily count is not reported until it is reached.","schema":{"type":"integer","example":41}}},"content":{"application/json":{"schema":{"type":"object","description":"Single denormalized blob: portfolio + positions + rules +\ncompliance violations + condition monitors, and rebalance amounts\nwhen the request sets `include_rebalance=true`.\nThe agent's primary \"look at the world\" response. See ADR-007\nand ADR-026. A check answer comes from `compliance`; sized amounts\nare there only when asked for (ADR-113). `prices_complete` / `unpriced_symbols` (the fields\n`ComplianceResponse` / `RebalanceResponse` both omit for the same\nreason) are not carried on this surface either: both are computed\nfrom Allocait's own stored quote, not from your coverage of it, so\nneither can be scrubbed the way `current_price`, `total_value` and\n`exposure` are; use `symbols_to_price` instead (ADR-036).\n","properties":{"portfolio":{"type":"object","description":"The portfolio header as carried inside `PortfolioSnapshot.portfolio`.\n`PortfolioSummary` without `position_count`; the RPC builds this\nobject itself and does not count positions here.\n","properties":{"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"portfolio.portfolio_id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"portfolio.name","typeLabel":"string"},"description":{"oneOf":[{"type":"string","uniqueKey":"portfolio.description.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"portfolio.description.oneOf.1","typeLabel":"null"}],"uniqueKey":"portfolio.description","typeLabel":"string | null"},"base_currency":{"type":"string","enum":["USD"],"description":"Always USD. Allocait supports US dollars only.","uniqueKey":"portfolio.base_currency","typeLabel":"enum\u003cstring>"},"active_scenario_id":{"oneOf":[{"type":"string","format":"uuid","uniqueKey":"portfolio.active_scenario_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","uniqueKey":"portfolio.active_scenario_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"portfolio.active_scenario_id","typeLabel":"string\u003cuuid> | null"},"active_scenario_name":{"oneOf":[{"type":"string","uniqueKey":"portfolio.active_scenario_name.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"portfolio.active_scenario_name.oneOf.1","typeLabel":"null"}],"uniqueKey":"portfolio.active_scenario_name","typeLabel":"string | null"},"allow_shorts":{"type":"boolean","description":"Whether holdings may carry a negative share count (a short). Off by default (ADR-153).","uniqueKey":"portfolio.allow_shorts","typeLabel":"boolean"}},"uniqueKey":"portfolio","typeLabel":"object"},"scenario_id":{"oneOf":[{"type":"string","format":"uuid","uniqueKey":"scenario_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","uniqueKey":"scenario_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"scenario_id","typeLabel":"string\u003cuuid> | null"},"total_value":{"oneOf":[{"type":"number","description":"Null when any non-cash position is unpriced; a value spanning the whole portfolio can't stand on one stored quote (ADR-036). Present only once every non-cash position is covered by your `prices` map or owns its price (an option with a mark, or an expired one, ADR-147). Signed, since shorts subtract, so it can be zero or negative. At zero or less every `position_pct` is null and `compliance` reads `unjudged` (ADR-153).","uniqueKey":"total_value.oneOf.0","typeLabel":"number"},{"type":"null","description":"Null when any non-cash position is unpriced; a value spanning the whole portfolio can't stand on one stored quote (ADR-036). Present only once every non-cash position is covered by your `prices` map or owns its price (an option with a mark, or an expired one, ADR-147). Signed, since shorts subtract, so it can be zero or negative. At zero or less every `position_pct` is null and `compliance` reads `unjudged` (ADR-153).","uniqueKey":"total_value.oneOf.1","typeLabel":"null"}],"uniqueKey":"total_value","typeLabel":"number | null"},"exposure":{"oneOf":[{"type":"object","description":"How much of the portfolio gains if prices rise, as percents of its\nvalue: long, short, net and gross, by asset class and per holding.\nA reading, not a rule; there is no range, cap or status to compare\nit with. Always present. Null unless your `prices` map holds a\nnumber for every non-cash holding, and while any holding is\nunpriced, even where Allocait holds a quote of its own that could\nfill the gap: every percent is a share of the whole book, so one\nstored quote would reach all of them (ADR-036, ADR-142). A holding\nthat owns its price, an option with a mark or an expired one,\ncounts as covered. Options count at their premium (ADR-147).\nComputed from your prices and the user's marks, and never stored.\n","required":["total_value","long_pct","short_pct","net_pct","gross_pct","options_counted","options_not_counted","options_not_counted_symbols","classes","holdings"],"example":{"total_value":100000,"long_pct":86,"short_pct":10,"net_pct":76,"gross_pct":96,"options_counted":1,"options_not_counted":0,"options_not_counted_symbols":[],"classes":[{"asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","asset_class":"Equities","long_pct":86,"short_pct":9,"net_pct":77},{"asset_class_id":"5b0e3f6a-8c1d-4b7e-9a42-6d1f0c8e2b97","asset_class":"Options","long_pct":0,"short_pct":1,"net_pct":-1}],"holdings":[{"symbol":"ALFA","asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","moves":1,"exposure_value":86000,"exposure_pct":86},{"symbol":"BRAV","asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","moves":1,"exposure_value":-6000,"exposure_pct":-6},{"symbol":"CHAR","asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","moves":-3,"exposure_value":-3000,"exposure_pct":-3},{"symbol":"ECHO281215P00050000","asset_class_id":"5b0e3f6a-8c1d-4b7e-9a42-6d1f0c8e2b97","moves":1,"exposure_value":-1000,"exposure_pct":-1,"basis":"premium","option_type":"put"}]},"properties":{"total_value":{"type":"number","description":"Portfolio value, the denominator of every percent. Equal to the snapshot's `total_value` once every holding is priced.","example":100000,"isRequired":true,"uniqueKey":"exposure.oneOf.0.total_value","typeLabel":"number"},"long_pct":{"oneOf":[{"type":"number","description":"Sum of the positive exposures as a percent of `total_value`, two decimals.","example":86,"isRequired":true,"uniqueKey":"exposure.oneOf.0.long_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Sum of the positive exposures as a percent of `total_value`, two decimals.","example":86,"isRequired":true,"uniqueKey":"exposure.oneOf.0.long_pct.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.long_pct","typeLabel":"number | null"},"short_pct":{"oneOf":[{"type":"number","description":"Absolute sum of the negative exposures as a percent of `total_value`. A positive number.","example":9,"isRequired":true,"uniqueKey":"exposure.oneOf.0.short_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Absolute sum of the negative exposures as a percent of `total_value`. A positive number.","example":9,"isRequired":true,"uniqueKey":"exposure.oneOf.0.short_pct.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.short_pct","typeLabel":"number | null"},"net_pct":{"oneOf":[{"type":"number","description":"`long_pct` minus `short_pct`. Negative when the book gains if prices fall.","example":77,"isRequired":true,"uniqueKey":"exposure.oneOf.0.net_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"`long_pct` minus `short_pct`. Negative when the book gains if prices fall.","example":77,"isRequired":true,"uniqueKey":"exposure.oneOf.0.net_pct.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.net_pct","typeLabel":"number | null"},"gross_pct":{"oneOf":[{"type":"number","description":"`long_pct` plus `short_pct`.","example":95,"isRequired":true,"uniqueKey":"exposure.oneOf.0.gross_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"`long_pct` plus `short_pct`.","example":95,"isRequired":true,"uniqueKey":"exposure.oneOf.0.gross_pct.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.gross_pct","typeLabel":"number | null"},"options_counted":{"type":"integer","description":"Options inside the four figures. Unexpired, priced, with a symbol that parses. Above 0 is the app's cue to label the reading \"options at premium\".","example":1,"isRequired":true,"uniqueKey":"exposure.oneOf.0.options_counted","typeLabel":"integer"},"options_not_counted":{"type":"integer","description":"Priced options in the Options class left out of the four figures because the symbol is not an option symbol, so it has no direction. They still count in `total_value`.","example":0,"isRequired":true,"uniqueKey":"exposure.oneOf.0.options_not_counted","typeLabel":"integer"},"options_not_counted_symbols":{"type":"array","items":{"type":"string","uniqueKey":"exposure.oneOf.0.options_not_counted_symbols.items.[INDEX]","typeLabel":"string"},"description":"The symbols behind `options_not_counted`, sorted.","example":[],"isRequired":true,"uniqueKey":"exposure.oneOf.0.options_not_counted_symbols","typeLabel":"string[]"},"classes":{"type":"array","description":"One entry per asset class with exposure, biggest gross first. A holding with no class is an entry with a null `asset_class_id` and `asset_class`.","items":{"type":"object","required":["asset_class_id","asset_class","long_pct","short_pct","net_pct"],"properties":{"asset_class_id":{"oneOf":[{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class_id.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid> | null"},"asset_class":{"oneOf":[{"type":"string","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class.oneOf.0","typeLabel":"string"},{"type":"null","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].asset_class","typeLabel":"string | null"},"long_pct":{"type":"number","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].long_pct","typeLabel":"number"},"short_pct":{"type":"number","description":"Positive.","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].short_pct","typeLabel":"number"},"net_pct":{"type":"number","isRequired":true,"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX].net_pct","typeLabel":"number"}},"uniqueKey":"exposure.oneOf.0.classes.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"exposure.oneOf.0.classes","typeLabel":"object[]"},"holdings":{"type":"array","description":"Every holding with a nonzero exposure, largest first. `moves` is the setting the exposure used.","items":{"type":"object","required":["symbol","asset_class_id","moves","exposure_value","exposure_pct"],"properties":{"symbol":{"type":"string","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].symbol","typeLabel":"string"},"asset_class_id":{"oneOf":[{"type":"string","format":"uuid","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].asset_class_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].asset_class_id.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid> | null"},"moves":{"type":"integer","enum":[1,2,3,-1,-2,-3],"description":"Always 1 for an option; Moves does not apply to one.","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].moves","typeLabel":"enum\u003cinteger>"},"exposure_value":{"type":"number","description":"`shares x price x moves`, signed. For an option, `shares x price`, positive for a call and negative for a put.","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].exposure_value","typeLabel":"number"},"exposure_pct":{"type":"number","description":"`exposure_value` as a signed percent of `total_value`.","isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].exposure_pct","typeLabel":"number"},"basis":{"type":"string","enum":["premium"],"description":"Present on an option only. It counts at its premium, which understates how far it moves.","uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].basis","typeLabel":"enum\u003cstring>"},"option_type":{"type":"string","enum":["call","put"],"description":"Present on an option only, read from its symbol.","uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX].option_type","typeLabel":"enum\u003cstring>"}},"uniqueKey":"exposure.oneOf.0.holdings.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"exposure.oneOf.0.holdings","typeLabel":"object[]"}},"uniqueKey":"exposure.oneOf.0","typeLabel":"object"},{"type":"null","description":"How much of the portfolio gains if prices rise, as percents of its\nvalue: long, short, net and gross, by asset class and per holding.\nA reading, not a rule; there is no range, cap or status to compare\nit with. Always present. Null unless your `prices` map holds a\nnumber for every non-cash holding, and while any holding is\nunpriced, even where Allocait holds a quote of its own that could\nfill the gap: every percent is a share of the whole book, so one\nstored quote would reach all of them (ADR-036, ADR-142). A holding\nthat owns its price, an option with a mark or an expired one,\ncounts as covered. Options count at their premium (ADR-147).\nComputed from your prices and the user's marks, and never stored.\n","uniqueKey":"exposure.oneOf.1","typeLabel":"null"}],"uniqueKey":"exposure","typeLabel":"object | null"},"price_source":{"type":"string","enum":["overrides","unpriced"],"description":"`overrides` once every symbol this response needed came from\nyour `prices` map (`symbols_to_price` is then empty);\n`unpriced` while at least one still does not. Allocait's own\nstored quote (`market_data`) never appears on this surface\n(ADR-036).\n","uniqueKey":"price_source","typeLabel":"enum\u003cstring>"},"symbols_to_price":{"type":"array","items":{"type":"string","uniqueKey":"symbols_to_price.items.[INDEX]","typeLabel":"string"},"description":"Every symbol, sorted, that you would need to add to `prices` to clear every null from this response. Empty once the payload is entirely your own numbers.","uniqueKey":"symbols_to_price","typeLabel":"string[]"},"positions":{"type":"array","items":{"type":"object","description":"One holding as carried inside `PortfolioSnapshot.positions`. Narrower\nthan `Position` from `GET /positions` (no `id`, `portfolio_id` or\n`position_sizing`) and priced only as far as the\nrequest's `prices` map reaches.\n","properties":{"symbol":{"type":"string","uniqueKey":"positions.items.[INDEX].symbol","typeLabel":"string"},"shares":{"type":"number","description":"Signed. Negative is a short (ADR-153); its `position_value` and `position_pct` are negative too. For a holding filed under the Options system asset class, recorded as contracts × 100 at the per-share premium (ADR-056).","uniqueKey":"positions.items.[INDEX].shares","typeLabel":"number"},"is_cash":{"type":"boolean","uniqueKey":"positions.items.[INDEX].is_cash","typeLabel":"boolean"},"asset_class_id":{"oneOf":[{"type":"string","format":"uuid","uniqueKey":"positions.items.[INDEX].asset_class_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","uniqueKey":"positions.items.[INDEX].asset_class_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid> | null"},"asset_class":{"oneOf":[{"type":"string","uniqueKey":"positions.items.[INDEX].asset_class.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"positions.items.[INDEX].asset_class.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].asset_class","typeLabel":"string | null"},"moves":{"type":"integer","enum":[1,2,3,-1,-2,-3],"description":"Times its index a fund moves; negative is inverse. 1 unless the user set it (ADR-142). Present on every row, cash included.","uniqueKey":"positions.items.[INDEX].moves","typeLabel":"enum\u003cinteger>"},"mark":{"oneOf":[{"type":"number","description":"The per-share premium the user recorded for an option; null off the Options class and for an option with no mark (ADR-147). The user's own number.","uniqueKey":"positions.items.[INDEX].mark.oneOf.0","typeLabel":"number"},{"type":"null","description":"The per-share premium the user recorded for an option; null off the Options class and for an option with no mark (ADR-147). The user's own number.","uniqueKey":"positions.items.[INDEX].mark.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].mark","typeLabel":"number | null"},"mark_on":{"oneOf":[{"type":"string","format":"date","description":"The day (US Eastern) the mark was last set, changed, or confirmed by a trade price. Null when there is no mark.","uniqueKey":"positions.items.[INDEX].mark_on.oneOf.0","typeLabel":"string\u003cdate>"},{"type":"null","format":"date","description":"The day (US Eastern) the mark was last set, changed, or confirmed by a trade price. Null when there is no mark.","uniqueKey":"positions.items.[INDEX].mark_on.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].mark_on","typeLabel":"string\u003cdate> | null"},"expired_on":{"oneOf":[{"type":"string","format":"date","description":"The option's expiry date once it has passed, else null. An expired option's `current_price` is 0 whatever you pass.","uniqueKey":"positions.items.[INDEX].expired_on.oneOf.0","typeLabel":"string\u003cdate>"},{"type":"null","format":"date","description":"The option's expiry date once it has passed, else null. An expired option's `current_price` is 0 whatever you pass.","uniqueKey":"positions.items.[INDEX].expired_on.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].expired_on","typeLabel":"string\u003cdate> | null"},"current_price":{"oneOf":[{"type":"number","description":"Cash is always 1. For any other position, the price you passed for its symbol, or null if you did not (including on a GET, which passes none), never Allocait's own stored quote (ADR-036). An option is the exception, priced at its `mark` (your price for the call replaces it) or at 0 once it has expired, because both are the user's own numbers. An option with no mark and no price from you is null.","uniqueKey":"positions.items.[INDEX].current_price.oneOf.0","typeLabel":"number"},{"type":"null","description":"Cash is always 1. For any other position, the price you passed for its symbol, or null if you did not (including on a GET, which passes none), never Allocait's own stored quote (ADR-036). An option is the exception, priced at its `mark` (your price for the call replaces it) or at 0 once it has expired, because both are the user's own numbers. An option with no mark and no price from you is null.","uniqueKey":"positions.items.[INDEX].current_price.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].current_price","typeLabel":"number | null"},"position_value":{"oneOf":[{"type":"number","description":"shares × current_price. Null under the same conditions as current_price (never null for cash).","uniqueKey":"positions.items.[INDEX].position_value.oneOf.0","typeLabel":"number"},{"type":"null","description":"shares × current_price. Null under the same conditions as current_price (never null for cash).","uniqueKey":"positions.items.[INDEX].position_value.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].position_value","typeLabel":"number | null"},"position_pct":{"oneOf":[{"type":"number","description":"Share of total portfolio value. Null whenever any non-cash position is unpriced, since one stored quote in the sum would contaminate every position's share. Also null when the portfolio is worth zero or less, where a share is undefined (ADR-153).","uniqueKey":"positions.items.[INDEX].position_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Share of total portfolio value. Null whenever any non-cash position is unpriced, since one stored quote in the sum would contaminate every position's share. Also null when the portfolio is worth zero or less, where a share is undefined (ADR-153).","uniqueKey":"positions.items.[INDEX].position_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"positions.items.[INDEX].position_pct","typeLabel":"number | null"}},"uniqueKey":"positions.items.[INDEX]","typeLabel":"object"},"uniqueKey":"positions","typeLabel":"object[]"},"expired_options":{"type":"integer","description":"How many held options have passed their expiry (`expired_on` set, shares not 0). The user's own record, so it needs no price and is present whatever else is null. Allocait changes nothing on them and sends no alert; the person decides what each became (ADR-147).","uniqueKey":"expired_options","typeLabel":"integer"},"rules":{"type":"array","description":"The active scenario's position rules. Same fields as `GET /position-rules` minus the ids and timestamps.","items":{"type":"object","properties":{"asset_class_id":{"type":"string","format":"uuid","uniqueKey":"rules.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid>"},"asset_class":{"type":"string","uniqueKey":"rules.items.[INDEX].asset_class","typeLabel":"string"},"min_position_pct":{"oneOf":[{"type":"number","description":"Lower bound of the allocation band on the asset class total, as % of portfolio value. Null, with `max_position_pct`, when the rule has no band; the class total is not judged.","uniqueKey":"rules.items.[INDEX].min_position_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Lower bound of the allocation band on the asset class total, as % of portfolio value. Null, with `max_position_pct`, when the rule has no band; the class total is not judged.","uniqueKey":"rules.items.[INDEX].min_position_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].min_position_pct","typeLabel":"number | null"},"max_position_pct":{"oneOf":[{"type":"number","description":"Upper bound of the allocation band on the asset class total, as % of portfolio value. Null when the rule has no band.","uniqueKey":"rules.items.[INDEX].max_position_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Upper bound of the allocation band on the asset class total, as % of portfolio value. Null when the rule has no band.","uniqueKey":"rules.items.[INDEX].max_position_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].max_position_pct","typeLabel":"number | null"},"target_allocation_pct":{"oneOf":[{"type":"number","description":"Optional aim point inside the allocation band that `rebalance` moves toward.","uniqueKey":"rules.items.[INDEX].target_allocation_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Optional aim point inside the allocation band that `rebalance` moves toward.","uniqueKey":"rules.items.[INDEX].target_allocation_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].target_allocation_pct","typeLabel":"number | null"},"band_min_pct":{"oneOf":[{"type":"number","description":"The same value as `min_position_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].band_min_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"The same value as `min_position_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].band_min_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].band_min_pct","typeLabel":"number | null"},"band_max_pct":{"oneOf":[{"type":"number","description":"The same value as `max_position_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].band_max_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"The same value as `max_position_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].band_max_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].band_max_pct","typeLabel":"number | null"},"target_pct":{"oneOf":[{"type":"number","description":"The same value as `target_allocation_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].target_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"The same value as `target_allocation_pct`, under the name the MCP tools use.","uniqueKey":"rules.items.[INDEX].target_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].target_pct","typeLabel":"number | null"},"size_min_pct":{"oneOf":[{"type":"number","description":"Lower bound of the position size range for one holding in this class, as % of portfolio value. Null when no size range is set.","uniqueKey":"rules.items.[INDEX].size_min_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Lower bound of the position size range for one holding in this class, as % of portfolio value. Null when no size range is set.","uniqueKey":"rules.items.[INDEX].size_min_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].size_min_pct","typeLabel":"number | null"},"size_max_pct":{"oneOf":[{"type":"number","description":"Upper bound of the position size range for one holding in this class, as % of portfolio value. Null when no size range is set.","uniqueKey":"rules.items.[INDEX].size_max_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Upper bound of the position size range for one holding in this class, as % of portfolio value. Null when no size range is set.","uniqueKey":"rules.items.[INDEX].size_max_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].size_max_pct","typeLabel":"number | null"},"short_size_min_pct":{"oneOf":[{"type":"number","description":"Lower bound of the short size range for one short in this class, as % of portfolio value. Null when no short size range is set.","uniqueKey":"rules.items.[INDEX].short_size_min_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Lower bound of the short size range for one short in this class, as % of portfolio value. Null when no short size range is set.","uniqueKey":"rules.items.[INDEX].short_size_min_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].short_size_min_pct","typeLabel":"number | null"},"short_size_max_pct":{"oneOf":[{"type":"number","description":"Upper bound of the short size range for one short in this class, as % of portfolio value. Null when no short size range is set.","uniqueKey":"rules.items.[INDEX].short_size_max_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"Upper bound of the short size range for one short in this class, as % of portfolio value. Null when no short size range is set.","uniqueKey":"rules.items.[INDEX].short_size_max_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rules.items.[INDEX].short_size_max_pct","typeLabel":"number | null"}},"uniqueKey":"rules.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rules","typeLabel":"object[]"},"compliance":{"oneOf":[{"type":"object","description":"Null when any non-cash position is unpriced. An `{error}`\nobject when the portfolio has no scenario to evaluate against.\nOtherwise the shape POST /compliance/check returns, computed\nfrom this request's `prices`, including `status`, `issue_count`\nand `unchecked`.\n","properties":{"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.0.portfolio_id","typeLabel":"string\u003cuuid>"},"scenario_id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.0.scenario_id","typeLabel":"string\u003cuuid>"},"total_value":{"type":"number","description":"Total portfolio value in base currency","uniqueKey":"compliance.oneOf.0.total_value","typeLabel":"number"},"price_source":{"type":"string","enum":["overrides"],"description":"Always `overrides` on this surface. `prices` is required and\nchecked to cover every non-cash position before this is computed\n(a held option that owns its price is the exception, ADR-147),\nso every value here is the caller's or the person's own (ADR-036). The dashboard's\n`data_age_seconds` is not carried; it measures Allocait's own\nstored quote, which this call never uses.\n","uniqueKey":"compliance.oneOf.0.price_source","typeLabel":"enum\u003cstring>"},"violation_count":{"type":"integer","uniqueKey":"compliance.oneOf.0.violation_count","typeLabel":"integer"},"violations":{"type":"array","description":"One entry per non-cash holding in an asset class whose total is\noutside its allocation band, each with `outside_by`, the class's\ndistance from its band (ADR-113). Cash, and a class you hold\nnothing in, have no holding to list, so those breaches appear in\n`class_violations` only. A holding priced at 0 has no entry\neither (ADR-080).\n","items":{"type":"object","properties":{"symbol":{"type":"string","example":"ALFA","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].symbol","typeLabel":"string"},"asset_class":{"type":"string","example":"Equities","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].asset_class","typeLabel":"string"},"status":{"type":"string","enum":["ABOVE_MAX","BELOW_MIN"],"description":"This position's class verdict, computed from the class's priced\nholdings only. Allocait's own dashboard shows a per-class\npriced_count/unpriced_count/prices_complete disclosure alongside\nthis same verdict for a partially priced class (ADR-057).\nIt is never carried here, because `prices` is required to cover every\nnon-cash position before this is computed, so on this surface\nevery class's own count can only ever read fully priced\n(ADR-036).\n","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].status","typeLabel":"enum\u003cstring>"},"current_pct":{"type":"number","description":"Current position as % of portfolio","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].current_pct","typeLabel":"number"},"min_pct":{"type":"number","description":"Lower bound of the allocation band on the asset class total this position's class is measured against. Not a position size limit.","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].min_pct","typeLabel":"number"},"max_pct":{"type":"number","description":"Upper bound of the allocation band on the asset class total this position's class is measured against. Not a position size limit.","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].max_pct","typeLabel":"number"},"current_price":{"type":"number","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].current_price","typeLabel":"number"},"current_value":{"type":"number","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].current_value","typeLabel":"number"},"outside_by":{"type":"object","description":"How far this holding's class total sits outside its band. The same figure on every row of one class.","required":["edge","pct_points"],"properties":{"edge":{"type":"string","enum":["above_max","below_min"],"description":"Which side of the band or range the figure is on.","isRequired":true,"uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].outside_by.edge","typeLabel":"enum\u003cstring>"},"pct_points":{"type":"number","description":"How far outside, in percentage points of portfolio value, rounded to 4 places.","isRequired":true,"uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].outside_by.pct_points","typeLabel":"number"},"value":{"type":"number","description":"The dollar amount that is outside, at the prices you passed, rounded to 2 places. Webhook payloads are worked out from Allocait's stored closing prices and never carry it.","uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].outside_by.value","typeLabel":"number"}},"uniqueKey":"compliance.oneOf.0.violations.items.[INDEX].outside_by","typeLabel":"object"}},"uniqueKey":"compliance.oneOf.0.violations.items.[INDEX]","typeLabel":"object"},"uniqueKey":"compliance.oneOf.0.violations","typeLabel":"object[]"},"class_violation_count":{"type":"integer","uniqueKey":"compliance.oneOf.0.class_violation_count","typeLabel":"integer"},"class_violations":{"type":"array","description":"One entry per asset class whose total, cash included, is outside\nits allocation band. Every class with a band is judged, including\none you hold nothing in: it sits at 0%, so a band with a minimum\nabove 0 reads BELOW_MIN (ADR-069). The same class verdict the app\nshows. A class total is the net of its holdings: a short\nsubtracts, and a total below zero counts as 0 (ADR-153).\n","items":{"type":"object","description":"An asset class whose total is outside its allocation band. Reports the breach only; no trade is suggested.","properties":{"asset_class_id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid>"},"asset_class":{"type":"string","example":"Cash","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].asset_class","typeLabel":"string"},"status":{"type":"string","enum":["ABOVE_MAX","BELOW_MIN"],"uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].status","typeLabel":"enum\u003cstring>"},"current_pct":{"type":"number","description":"Class total as % of portfolio","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].current_pct","typeLabel":"number"},"min_pct":{"type":"number","description":"Lower bound of the class allocation band","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].min_pct","typeLabel":"number"},"max_pct":{"type":"number","description":"Upper bound of the class allocation band","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].max_pct","typeLabel":"number"},"current_value":{"type":"number","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].current_value","typeLabel":"number"},"outside_by":{"type":"object","description":"How far a listed breach sits outside its own band or range (ADR-113).\nA fact about the rule: it holds no share count, no BUY or SELL and no\ntarget. Amounts come from `POST /rebalance/preview`, or from the\nsnapshot with `include_rebalance=true`, when a caller asks for them.\n","required":["edge","pct_points"],"properties":{"edge":{"type":"string","enum":["above_max","below_min"],"description":"Which side of the band or range the figure is on.","isRequired":true,"uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].outside_by.edge","typeLabel":"enum\u003cstring>"},"pct_points":{"type":"number","description":"How far outside, in percentage points of portfolio value, rounded to 4 places.","isRequired":true,"uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].outside_by.pct_points","typeLabel":"number"},"value":{"type":"number","description":"The dollar amount that is outside, at the prices you passed, rounded to 2 places. Webhook payloads are worked out from Allocait's stored closing prices and never carry it.","uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].outside_by.value","typeLabel":"number"}},"uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX].outside_by","typeLabel":"object"}},"uniqueKey":"compliance.oneOf.0.class_violations.items.[INDEX]","typeLabel":"object"},"uniqueKey":"compliance.oneOf.0.class_violations","typeLabel":"object[]"},"size_violation_count":{"type":"integer","uniqueKey":"compliance.oneOf.0.size_violation_count","typeLabel":"integer"},"size_violations":{"type":"array","description":"One entry per non-cash holding outside its class's range for the\nside it is on, by its size without a sign: a long against the\nposition size range, a short (negative `shares`) against the\nshort size range (ADR-144). The same position verdict the app\nshows. A holding on a side with no range is not listed. Each\nentry carries `side`.\n","items":{"type":"object","description":"A holding outside its class's position size range. Reports the breach only; no trade is suggested.","properties":{"symbol":{"type":"string","example":"ALFA","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].symbol","typeLabel":"string"},"asset_class_id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid>"},"asset_class":{"type":"string","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].asset_class","typeLabel":"string"},"side":{"type":"string","enum":["long","short"],"description":"Which side the holding is on. It mirrors the sign of `shares` and decides which range was used (ADR-144).","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].side","typeLabel":"enum\u003cstring>"},"status":{"type":"string","enum":["ABOVE_MAX","BELOW_MIN"],"uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].status","typeLabel":"enum\u003cstring>"},"current_pct":{"type":"number","description":"This holding's size as % of portfolio, without a sign. A short of 6% reads 6.","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].current_pct","typeLabel":"number"},"size_min_pct":{"type":"number","description":"Lower bound of the range for this holding's side in this class (the position size range for a long, the short size range for a short)","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].size_min_pct","typeLabel":"number"},"size_max_pct":{"type":"number","description":"Upper bound of the range for this holding's side in this class","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].size_max_pct","typeLabel":"number"},"current_price":{"type":"number","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].current_price","typeLabel":"number"},"current_value":{"type":"number","description":"Signed. Negative for a short.","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].current_value","typeLabel":"number"},"outside_by":{"type":"object","description":"How far a listed breach sits outside its own band or range (ADR-113).\nA fact about the rule: it holds no share count, no BUY or SELL and no\ntarget. Amounts come from `POST /rebalance/preview`, or from the\nsnapshot with `include_rebalance=true`, when a caller asks for them.\n","required":["edge","pct_points"],"properties":{"edge":{"type":"string","enum":["above_max","below_min"],"description":"Which side of the band or range the figure is on.","isRequired":true,"uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].outside_by.edge","typeLabel":"enum\u003cstring>"},"pct_points":{"type":"number","description":"How far outside, in percentage points of portfolio value, rounded to 4 places.","isRequired":true,"uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].outside_by.pct_points","typeLabel":"number"},"value":{"type":"number","description":"The dollar amount that is outside, at the prices you passed, rounded to 2 places. Webhook payloads are worked out from Allocait's stored closing prices and never carry it.","uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].outside_by.value","typeLabel":"number"}},"uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX].outside_by","typeLabel":"object"}},"uniqueKey":"compliance.oneOf.0.size_violations.items.[INDEX]","typeLabel":"object"},"uniqueKey":"compliance.oneOf.0.size_violations","typeLabel":"object[]"},"status":{"type":"string","enum":["compliant","partial","violations","unjudged"],"description":"The verdict in one word (ADR-073, ADR-080). `violations` when any\nclass or size breach is listed. `partial` when nothing judged\nbreaches but `unchecked` lists holdings no rule judged.\n`compliant` only when there is no breach and `unchecked` is\nempty. `unjudged` when nothing can be judged, for example a\nportfolio worth zero or less or a scenario with no rules. An\n`unjudged` answer lists no breach and `issue_count` is 0\n(ADR-153).\n","uniqueKey":"compliance.oneOf.0.status","typeLabel":"enum\u003cstring>"},"issue_count":{"type":"integer","description":"Class and size breaches together.","uniqueKey":"compliance.oneOf.0.issue_count","typeLabel":"integer"},"unchecked":{"type":"array","description":"Holdings no rule could judge, such as a holding with no asset class, each with the reason. A holding is judged by its class's band or by the size range for its side (a long by the position size, a short by the short size). A holding priced at 0 is judged at 0%, so it is not listed here.","items":{"type":"object","properties":{"symbol":{"type":"string","uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX].symbol","typeLabel":"string"},"pct":{"oneOf":[{"type":"number","description":"The holding as % of portfolio value. Null when the holding is unpriced.","uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX].pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"The holding as % of portfolio value. Null when the holding is unpriced.","uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX].pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX].pct","typeLabel":"number | null"},"reason":{"type":"string","enum":["unclassified","no_rule","unpriced"],"uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX].reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"compliance.oneOf.0.unchecked.items.[INDEX]","typeLabel":"object"},"uniqueKey":"compliance.oneOf.0.unchecked","typeLabel":"object[]"}},"uniqueKey":"compliance.oneOf.0","typeLabel":"object"},{"type":"object","description":"Null when any non-cash position is unpriced. An `{error}`\nobject when the portfolio has no scenario to evaluate against.\nOtherwise the shape POST /compliance/check returns, computed\nfrom this request's `prices`, including `status`, `issue_count`\nand `unchecked`.\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"compliance.oneOf.1.error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"compliance.oneOf.1.error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"compliance.oneOf.1.request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"compliance.oneOf.1.issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"compliance.oneOf.1.issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"compliance.oneOf.1.later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"compliance.oneOf.1.limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"compliance.oneOf.1.current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"compliance.oneOf.1.max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"compliance.oneOf.1.existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.1.duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"compliance.oneOf.1.duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"compliance.oneOf.1.would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"compliance.oneOf.1.would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"compliance.oneOf.1.would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"compliance.oneOf.1.valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"compliance.oneOf.1.valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"compliance.oneOf.1.input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"compliance.oneOf.1.short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"compliance.oneOf.1.symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"compliance.oneOf.1.symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.1.monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"compliance.oneOf.1.monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"compliance.oneOf.1.monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"compliance.oneOf.1.monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"compliance.oneOf.1.monitors","typeLabel":"object[]"}},"uniqueKey":"compliance.oneOf.1","typeLabel":"object"},{"type":"null","description":"Null when any non-cash position is unpriced. An `{error}`\nobject when the portfolio has no scenario to evaluate against.\nOtherwise the shape POST /compliance/check returns, computed\nfrom this request's `prices`, including `status`, `issue_count`\nand `unchecked`.\n","uniqueKey":"compliance.oneOf.2","typeLabel":"null"}],"uniqueKey":"compliance","typeLabel":"object · object · null"},"rebalance":{"oneOf":[{"type":"object","description":"Present only when the request sets `include_rebalance=true`\n(ADR-113); left out otherwise. Same nullability as\n`compliance`: null when any non-cash position is unpriced, an\n`{error}` object when no scenario is set, otherwise the same\nshape POST /rebalance/preview returns, computed from this\nrequest's `prices`.\n","properties":{"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.0.portfolio_id","typeLabel":"string\u003cuuid>"},"scenario_id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.0.scenario_id","typeLabel":"string\u003cuuid>"},"total_value":{"type":"number","description":"Signed. A portfolio worth zero or less has no percentages, so `trades` is empty and the class percentages are null; the total itself is still reported (ADR-153).","uniqueKey":"rebalance.oneOf.0.total_value","typeLabel":"number"},"price_source":{"type":"string","enum":["overrides"],"description":"Always `overrides` on this surface. `prices` is required and checked to cover every non-cash position before this is computed, except a held option that owns its price (ADR-036, ADR-147).","uniqueKey":"rebalance.oneOf.0.price_source","typeLabel":"enum\u003cstring>"},"trade_count":{"type":"integer","uniqueKey":"rebalance.oneOf.0.trade_count","typeLabel":"integer"},"trades":{"type":"array","description":"Pro rata amounts, ordered largest-dollar-value first. A holding priced at 0 gets no row, since an amount cannot be priced at 0 (ADR-080). A short (negative `shares`) or an option (a holding in the Options class) gets no row; its class's move is spread over the class's long holdings outside Options only (ADR-153, ADR-145).","items":{"type":"object","properties":{"symbol":{"type":"string","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].symbol","typeLabel":"string"},"asset_class":{"type":"string","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].asset_class","typeLabel":"string"},"action":{"type":"string","enum":["BUY","SELL"],"description":"The direction of the amount: BUY adds shares to the holding,\nSELL removes shares. The amount is arithmetic on the user's own\nrules, not a recommendation. It is sized from the class's priced\nholdings only. Allocait's own dashboard shows a per-class\npriced_count/unpriced_count/prices_complete disclosure for a\npartially priced class (ADR-057), never carried here, for the\nsame reason `Violation.status` above states (ADR-036).\n","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].action","typeLabel":"enum\u003cstring>"},"direction":{"type":"string","enum":["ADD","REDUCE"],"description":"Mirrors `action`, in neutral words. ADD for BUY, REDUCE for SELL. Added beside `action`, which keeps its values.","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].direction","typeLabel":"enum\u003cstring>"},"current_pct":{"type":"number","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].current_pct","typeLabel":"number"},"target_pct":{"type":"number","description":"The class's target, the same value as `class_target_pct`. Kept for existing callers.","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].target_pct","typeLabel":"number"},"class_target_pct":{"type":"number","description":"The asset class's target on its total that this amount moves toward -- the rule's own Target % when set, otherwise the midpoint of its allocation band.","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].class_target_pct","typeLabel":"number"},"current_price":{"type":"number","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].current_price","typeLabel":"number"},"shares":{"type":"number","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].shares","typeLabel":"number"},"dollar_value":{"type":"number","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].dollar_value","typeLabel":"number"},"resulting_pct":{"type":"number","uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX].resulting_pct","typeLabel":"number"}},"uniqueKey":"rebalance.oneOf.0.trades.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rebalance.oneOf.0.trades","typeLabel":"object[]"},"resulting_classes":{"type":"array","description":"Each asset class's share of the portfolio after these amounts, Cash included. Proceeds from removed shares stay in Cash. Every `resulting_pct` is null when the portfolio is worth zero or less (ADR-153).","items":{"type":"object","properties":{"asset_class_id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid>"},"asset_class":{"type":"string","uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX].asset_class","typeLabel":"string"},"resulting_pct":{"oneOf":[{"type":"number","uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX].resulting_pct.oneOf.0","typeLabel":"number"},{"type":"null","uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX].resulting_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX].resulting_pct","typeLabel":"number | null"}},"uniqueKey":"rebalance.oneOf.0.resulting_classes.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rebalance.oneOf.0.resulting_classes","typeLabel":"object[]"},"basis":{"type":"string","description":"Pro rata amounts that would move each class toward its aim: the user's target, or the midpoint of their band. Arithmetic on the user's own rules; not a recommendation.","uniqueKey":"rebalance.oneOf.0.basis","typeLabel":"string"},"unresolved":{"type":"array","description":"Classes still outside their band after these amounts, such as a class below its band with no holding to add to, each with the reason. The amounts don't resize holdings, so size_violations stand.","items":{"type":"object","properties":{"asset_class_id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].asset_class_id","typeLabel":"string\u003cuuid>"},"asset_class":{"type":"string","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].asset_class","typeLabel":"string"},"resulting_pct":{"type":"number","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].resulting_pct","typeLabel":"number"},"band_min_pct":{"type":"number","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].band_min_pct","typeLabel":"number"},"band_max_pct":{"type":"number","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].band_max_pct","typeLabel":"number"},"reason":{"type":"string","enum":["no_priced_holdings","zero_price","cash","outside_band_after_trades"],"description":"`no_priced_holdings`: the class has nothing the preview may\ntrade, whatever its prices (a short and an option are not\ntraded).\n`zero_price`: every holding in the class is priced at 0, so\nnone can be traded (ADR-080). `cash`: Cash moves only as\nother amounts settle. `outside_band_after_trades`: rounding\nto share units leaves the class just outside its band.\n","uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX].reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"rebalance.oneOf.0.unresolved.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rebalance.oneOf.0.unresolved","typeLabel":"object[]"},"not_rebalanced":{"type":"array","description":"Every short and every Options class holding the rebalance leaves\nas it is, once each, ordered by symbol (ADR-145). Always present,\nempty when there are none. A holding with zero shares is not\nlisted. An entry carries no price, count or value.\n","items":{"type":"object","required":["symbol","asset_class","reason"],"properties":{"symbol":{"type":"string","isRequired":true,"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX].symbol","typeLabel":"string"},"asset_class":{"oneOf":[{"type":"string","isRequired":true,"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX].asset_class.oneOf.0","typeLabel":"string"},{"type":"null","isRequired":true,"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX].asset_class.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX].asset_class","typeLabel":"string | null"},"reason":{"type":"string","enum":["short","option"],"description":"`short`: a negative share count. `option`: a holding in the Options class.","isRequired":true,"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX].reason","typeLabel":"enum\u003cstring>"}},"uniqueKey":"rebalance.oneOf.0.not_rebalanced.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rebalance.oneOf.0.not_rebalanced","typeLabel":"object[]"}},"uniqueKey":"rebalance.oneOf.0","typeLabel":"object"},{"type":"object","description":"Present only when the request sets `include_rebalance=true`\n(ADR-113); left out otherwise. Same nullability as\n`compliance`: null when any non-cash position is unpriced, an\n`{error}` object when no scenario is set, otherwise the same\nshape POST /rebalance/preview returns, computed from this\nrequest's `prices`.\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"rebalance.oneOf.1.error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"rebalance.oneOf.1.error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"rebalance.oneOf.1.request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"rebalance.oneOf.1.issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"rebalance.oneOf.1.issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"rebalance.oneOf.1.later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"rebalance.oneOf.1.limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"rebalance.oneOf.1.current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"rebalance.oneOf.1.max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"rebalance.oneOf.1.existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.1.duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"rebalance.oneOf.1.duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"rebalance.oneOf.1.would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"rebalance.oneOf.1.would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"rebalance.oneOf.1.would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"rebalance.oneOf.1.valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"rebalance.oneOf.1.valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"rebalance.oneOf.1.input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"rebalance.oneOf.1.short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"rebalance.oneOf.1.symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"rebalance.oneOf.1.symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.1.monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"rebalance.oneOf.1.monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"rebalance.oneOf.1.monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"rebalance.oneOf.1.monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"rebalance.oneOf.1.monitors","typeLabel":"object[]"}},"uniqueKey":"rebalance.oneOf.1","typeLabel":"object"},{"type":"null","description":"Present only when the request sets `include_rebalance=true`\n(ADR-113); left out otherwise. Same nullability as\n`compliance`: null when any non-cash position is unpriced, an\n`{error}` object when no scenario is set, otherwise the same\nshape POST /rebalance/preview returns, computed from this\nrequest's `prices`.\n","uniqueKey":"rebalance.oneOf.2","typeLabel":"null"}],"uniqueKey":"rebalance","typeLabel":"object · object · null"},"monitors":{"type":"array","description":"Each condition monitor measured against the levels and ranges\nthe user recorded, at the price you passed for its symbol (null,\nunmeasured, if you did not). One entry per (monitor, resolved\nsymbol); `[]` when the portfolio has no monitors. See ADR-020\nand ADR-026.\n","items":{"type":"object","description":"One condition monitor's intraday range position for one resolved\nsymbol, as carried inside `PortfolioSnapshot.monitors`.\n\nThis is the VIEW half of ADR-020's monitor model: a measurement, not\nan assertion of a break. Reading it is free, changes nothing, and is\nnever pushed; only a settled daily close is ever treated as a\nconfirmed break, by a separate once-daily mechanism this response\ndoes not report. Every bound and threshold here is a value the user\nrecorded as an Input (ADR-024); Allocait computes none of them.\n\nNarrower than `ConditionMonitorData` from `GET /monitors`, and\nrenamed throughout. Field mapping between the two, for a caller\nholding both responses. The left column names columns of the\n`GET /monitors` row; the `input_1_id` / `input1_name` /\n`input_2_id` / `input2_name` / `conditions` / `condition_values`\ncolumns are present in that response but not itemised in the\n`ConditionMonitorData` schema below.\n\n| `ConditionMonitorData` (`GET /monitors`) | `SnapshotMonitor` (here) |\n| --- | --- |\n| `input_1_id` | `recorded_low_input_id` |\n| `input1_name` | `recorded_low_input_name` |\n| `input1_value` (string) | `recorded_low` (number, or null) |\n| `input1_date` (string) | `recorded_low_date` (string, or null) |\n| `input_2_id` | `recorded_high_input_id` |\n| `input2_name` | `recorded_high_input_name` |\n| `input2_value` (string) | `recorded_high` (number, or null) |\n| `input2_date` (string) | `recorded_high_date` (string, or null) |\n| `conditions`, `condition_values` | not carried; stay on `GET /monitors` |\n\n`GET /monitors` no longer carries `price`, `prev_close`,\n`change_pct`, `position_pct`, `price_status_type`,\n`price_status_label` or `price_status_color` at all: those were\ncomputed from Allocait's own stored quote and are dropped from that\nresponse under ADR-036. The priced reading (`price`,\n`range_position_pct` **or** `distance_from_level_pct`, and\n`price_state`) lives only here, at the price you pass.\n\nBeyond the renames, the values themselves diverge in four documented\nways, all deliberate:\n\n1. An unpriced symbol reports `price: null`, not `0`.\n2. A bound the user never recorded, or recorded as text that is not\n a number, yields `price_state: null` rather than falling through\n to `in_range` or being measured as a level.\n3. `bound_kind` follows the monitor's configuration, so a range with\n one bound still missing stays `range` here while `GET /monitors`\n treats it as level-shaped.\n4. An inverted recorded pair (`recorded_high` below `recorded_low`)\n yields a null measurement and a null `price_state` instead of a\n positional word that points the wrong way.\n","properties":{"monitor_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].monitor_id","typeLabel":"string\u003cuuid>"},"monitor_name":{"type":"string","description":"The user's own name for this monitor","uniqueKey":"monitors.items.[INDEX].monitor_name","typeLabel":"string"},"symbol":{"type":"string","example":"ALFA","uniqueKey":"monitors.items.[INDEX].symbol","typeLabel":"string"},"is_label":{"type":"boolean","description":"True when the symbol is a label (ADR-239). A label is never in `symbols_to_price`; it reads `unpriced` unless a price for it is passed.","uniqueKey":"monitors.items.[INDEX].is_label","typeLabel":"boolean"},"comparison_mode":{"oneOf":[{"type":"string","enum":["ABOVE","BELOW","NEAR","RANGE",null],"description":"The user's own configured mode, passed through unchanged.\nNothing in this object is derived from it: `price_state`\ndescribes where price sits, never whether the mode is satisfied.\nNull when the monitor was created without one: the column is\nnullable and `condition_monitor_create` writes an explicit NULL\nrather than falling back to the column default. Allocait does\nnot invent a mode the user never chose.\n","uniqueKey":"monitors.items.[INDEX].comparison_mode.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["ABOVE","BELOW","NEAR","RANGE",null],"description":"The user's own configured mode, passed through unchanged.\nNothing in this object is derived from it: `price_state`\ndescribes where price sits, never whether the mode is satisfied.\nNull when the monitor was created without one: the column is\nnullable and `condition_monitor_create` writes an explicit NULL\nrather than falling back to the column default. Allocait does\nnot invent a mode the user never chose.\n","uniqueKey":"monitors.items.[INDEX].comparison_mode.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].comparison_mode","typeLabel":"enum\u003cstring> | null"},"bound_kind":{"type":"string","enum":["range","level"],"description":"`range` when the monitor is configured with a second bound Input\n(`recorded_high_input_id` is set), `level` when it has only one.\nDerived from the monitor's configuration, not from\n`comparison_mode` and not from what has been recorded so far.\n\nA `range` monitor whose bounds are not both on record is still\n`range`: `recorded_low` and/or `recorded_high` come back null\nand `range_position_pct` and `price_state` are null with them.\nDo not read `bound_kind: range` as a promise that two numbers\nare present. Check the bounds themselves. The alternative,\nderiving the shape from the recorded values, would re-label a\nhalf-recorded range as a `level` and measure price against the\nuser's floor as though it were a standalone level.\n","uniqueKey":"monitors.items.[INDEX].bound_kind","typeLabel":"enum\u003cstring>"},"recorded_low":{"oneOf":[{"type":"number","description":"The latest value the user recorded against the monitor's first\nbound Input (`recorded_low_input_id`). In `level` shape this is\nthe single recorded level. Null when nothing numeric is on\nrecord for it against this symbol, including when the recorded\nentry is free text that is not a number, since\n`input_entries.value` is untyped.\n\n\"Low\" names the slot and makes no claim about the value: nothing\nconstrains the first Input's value to sit below the second's,\nand Allocait never reorders the pair (ADR-024; it may not\nderive a bound the user did not record). When a caller sees\n`recorded_high` below `recorded_low`, the pair is inverted and\nthe measurement fields are null for that reason.\n","uniqueKey":"monitors.items.[INDEX].recorded_low.oneOf.0","typeLabel":"number"},{"type":"null","description":"The latest value the user recorded against the monitor's first\nbound Input (`recorded_low_input_id`). In `level` shape this is\nthe single recorded level. Null when nothing numeric is on\nrecord for it against this symbol, including when the recorded\nentry is free text that is not a number, since\n`input_entries.value` is untyped.\n\n\"Low\" names the slot and makes no claim about the value: nothing\nconstrains the first Input's value to sit below the second's,\nand Allocait never reorders the pair (ADR-024; it may not\nderive a bound the user did not record). When a caller sees\n`recorded_high` below `recorded_low`, the pair is inverted and\nthe measurement fields are null for that reason.\n","uniqueKey":"monitors.items.[INDEX].recorded_low.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_low","typeLabel":"number | null"},"recorded_high":{"oneOf":[{"type":"number","description":"The latest value recorded against the monitor's second bound\nInput (`recorded_high_input_id`). Always null in `level` shape,\nwhere there is no second Input; also null in `range` shape when\nthe user has not yet recorded a value for it, or recorded one\nthat is not a number.\n","uniqueKey":"monitors.items.[INDEX].recorded_high.oneOf.0","typeLabel":"number"},{"type":"null","description":"The latest value recorded against the monitor's second bound\nInput (`recorded_high_input_id`). Always null in `level` shape,\nwhere there is no second Input; also null in `range` shape when\nthe user has not yet recorded a value for it, or recorded one\nthat is not a number.\n","uniqueKey":"monitors.items.[INDEX].recorded_high.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_high","typeLabel":"number | null"},"recorded_low_date":{"oneOf":[{"type":"string","format":"date","description":"The date (`YYYY-MM-DD`) of the entry `recorded_low` came from: the\nnewest entry the user recorded against the first bound Input for\nthis symbol, whatever its date, so a future-dated entry shows its\nown. Null when no entry exists. Set even when `recorded_low` is\nnull because that newest entry is text that is not a number. A\nfact about the entry, not a judgement of its age: compare it with\nyour own clock.\n","uniqueKey":"monitors.items.[INDEX].recorded_low_date.oneOf.0","typeLabel":"string\u003cdate>"},{"type":"null","format":"date","description":"The date (`YYYY-MM-DD`) of the entry `recorded_low` came from: the\nnewest entry the user recorded against the first bound Input for\nthis symbol, whatever its date, so a future-dated entry shows its\nown. Null when no entry exists. Set even when `recorded_low` is\nnull because that newest entry is text that is not a number. A\nfact about the entry, not a judgement of its age: compare it with\nyour own clock.\n","uniqueKey":"monitors.items.[INDEX].recorded_low_date.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_low_date","typeLabel":"string\u003cdate> | null"},"recorded_high_date":{"oneOf":[{"type":"string","format":"date","description":"The date of the entry `recorded_high` came from. Always null in `level` shape; otherwise as `recorded_low_date`.","uniqueKey":"monitors.items.[INDEX].recorded_high_date.oneOf.0","typeLabel":"string\u003cdate>"},{"type":"null","format":"date","description":"The date of the entry `recorded_high` came from. Always null in `level` shape; otherwise as `recorded_low_date`.","uniqueKey":"monitors.items.[INDEX].recorded_high_date.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_high_date","typeLabel":"string\u003cdate> | null"},"recorded_low_input_id":{"type":"string","format":"uuid","description":"The Input definition `recorded_low` came from","uniqueKey":"monitors.items.[INDEX].recorded_low_input_id","typeLabel":"string\u003cuuid>"},"recorded_low_input_name":{"oneOf":[{"type":"string","uniqueKey":"monitors.items.[INDEX].recorded_low_input_name.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"monitors.items.[INDEX].recorded_low_input_name.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_low_input_name","typeLabel":"string | null"},"recorded_high_input_id":{"oneOf":[{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].recorded_high_input_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","uniqueKey":"monitors.items.[INDEX].recorded_high_input_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_high_input_id","typeLabel":"string\u003cuuid> | null"},"recorded_high_input_name":{"oneOf":[{"type":"string","uniqueKey":"monitors.items.[INDEX].recorded_high_input_name.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"monitors.items.[INDEX].recorded_high_input_name.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].recorded_high_input_name","typeLabel":"string | null"},"threshold_pct":{"oneOf":[{"type":"number","description":"The user's own proximity setting, governing `near_low` /\n`near_high` / `near_level` display only. Unrelated to close\nconfirmation. Without it none of the three appears: a range reads\n`at_low`, `at_high`, `in_range`, `below_range` or `above_range`, a\nlevel reads `at_level`, `above_level` or `below_level`.\n","uniqueKey":"monitors.items.[INDEX].threshold_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"The user's own proximity setting, governing `near_low` /\n`near_high` / `near_level` display only. Unrelated to close\nconfirmation. Without it none of the three appears: a range reads\n`at_low`, `at_high`, `in_range`, `below_range` or `above_range`, a\nlevel reads `at_level`, `above_level` or `below_level`.\n","uniqueKey":"monitors.items.[INDEX].threshold_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].threshold_pct","typeLabel":"number | null"},"price":{"oneOf":[{"type":"number","description":"The price you passed for this symbol. Null otherwise, never 0,\nwhich would read as a break rather than a data gap. Allocait's\nown stored quote never appears here (ADR-036).\n","uniqueKey":"monitors.items.[INDEX].price.oneOf.0","typeLabel":"number"},{"type":"null","description":"The price you passed for this symbol. Null otherwise, never 0,\nwhich would read as a break rather than a data gap. Allocait's\nown stored quote never appears here (ADR-036).\n","uniqueKey":"monitors.items.[INDEX].price.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].price","typeLabel":"number | null"},"price_source":{"type":"string","enum":["overrides","unpriced"],"description":"Per-symbol, unlike the top-level `price_source`. `overrides`\nwhen you priced this symbol, `unpriced` when you did not.\nAllocait's own stored quote (`market_data`) never appears on\nthis surface (ADR-036).\n","uniqueKey":"monitors.items.[INDEX].price_source","typeLabel":"enum\u003cstring>"},"range_position_pct":{"oneOf":[{"type":"number","description":"`range` shape only. Where price sits between the user's two\nrecorded bounds: 0 at `recorded_low`, 100 at `recorded_high`,\nnegative below and above 100 above. Null in `level` shape, when\nthe symbol is unpriced, when either bound is missing or not\nnumeric, when the two bounds are equal, and when the pair is\ninverted (`recorded_high` below `recorded_low`).\n\nTogether with `distance_from_level_pct` these are the two halves\nof what `GET /monitors` used to carry as `position_pct` before\nADR-036 dropped it from that response; the two are never both\nnon-null here. Not to be confused with\n`SnapshotPosition.position_pct` in the same response, which is a\nholding's share of portfolio value.\n","uniqueKey":"monitors.items.[INDEX].range_position_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"`range` shape only. Where price sits between the user's two\nrecorded bounds: 0 at `recorded_low`, 100 at `recorded_high`,\nnegative below and above 100 above. Null in `level` shape, when\nthe symbol is unpriced, when either bound is missing or not\nnumeric, when the two bounds are equal, and when the pair is\ninverted (`recorded_high` below `recorded_low`).\n\nTogether with `distance_from_level_pct` these are the two halves\nof what `GET /monitors` used to carry as `position_pct` before\nADR-036 dropped it from that response; the two are never both\nnon-null here. Not to be confused with\n`SnapshotPosition.position_pct` in the same response, which is a\nholding's share of portfolio value.\n","uniqueKey":"monitors.items.[INDEX].range_position_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].range_position_pct","typeLabel":"number | null"},"distance_from_level_pct":{"oneOf":[{"type":"number","description":"`level` shape only. Signed percent of price away from the single\nrecorded level. Null in `range` shape, when unpriced, when no\nlevel is recorded or the recorded value is not numeric, and when\nthe recorded level is 0.\n\nThe level half of what `GET /monitors` used to carry as\n`position_pct`; see `range_position_pct` for the range half.\n","uniqueKey":"monitors.items.[INDEX].distance_from_level_pct.oneOf.0","typeLabel":"number"},{"type":"null","description":"`level` shape only. Signed percent of price away from the single\nrecorded level. Null in `range` shape, when unpriced, when no\nlevel is recorded or the recorded value is not numeric, and when\nthe recorded level is 0.\n\nThe level half of what `GET /monitors` used to carry as\n`position_pct`; see `range_position_pct` for the range half.\n","uniqueKey":"monitors.items.[INDEX].distance_from_level_pct.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].distance_from_level_pct","typeLabel":"number | null"},"price_state":{"oneOf":[{"type":"string","enum":["below_range","above_range","at_low","at_high","near_low","near_high","in_range","at_level","near_level","above_level","below_level",null],"description":"Where price sits, stated flatly. Same vocabulary as the\n`price_status_type` `GET /monitors` carried before ADR-036\ndropped it from that response. Null whenever the corresponding\nmeasurement is null: no price, a bound that is missing or not\nnumeric, equal bounds, or an inverted pair. Never a verdict: no\nvalue here means a break, a signal, or a confirmation.\n","uniqueKey":"monitors.items.[INDEX].price_state.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["below_range","above_range","at_low","at_high","near_low","near_high","in_range","at_level","near_level","above_level","below_level",null],"description":"Where price sits, stated flatly. Same vocabulary as the\n`price_status_type` `GET /monitors` carried before ADR-036\ndropped it from that response. Null whenever the corresponding\nmeasurement is null: no price, a bound that is missing or not\nnumeric, equal bounds, or an inverted pair. Never a verdict: no\nvalue here means a break, a signal, or a confirmation.\n","uniqueKey":"monitors.items.[INDEX].price_state.oneOf.1","typeLabel":"null"}],"uniqueKey":"monitors.items.[INDEX].price_state","typeLabel":"enum\u003cstring> | null"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"},"playbooks_needing_input":{"type":"array","description":"The portfolio's playbooks with at least one blank cell today\n(US Eastern, or the playbook's pinned date), as the playbook's\n`needs_input` counts them: blank cells of Inputs that are not\noptional. `[]` when none. The user's own recorded data, never\npriced (ADR-204).\n","items":{"type":"object","properties":{"playbook_id":{"type":"string","format":"uuid","uniqueKey":"playbooks_needing_input.items.[INDEX].playbook_id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"playbooks_needing_input.items.[INDEX].name","typeLabel":"string"},"date":{"type":"string","format":"date","uniqueKey":"playbooks_needing_input.items.[INDEX].date","typeLabel":"string\u003cdate>"},"blank_count":{"type":"integer","uniqueKey":"playbooks_needing_input.items.[INDEX].blank_count","typeLabel":"integer"}},"uniqueKey":"playbooks_needing_input.items.[INDEX]","typeLabel":"object"},"uniqueKey":"playbooks_needing_input","typeLabel":"object[]"},"generated_at":{"type":"string","format":"date-time","uniqueKey":"generated_at","typeLabel":"string\u003cdate-time>"}},"uniqueKey":"","typeLabel":"object"},"example":{"scenario_id":"3f2e940e-c6d0-4710-ac50-7d981b4ef2dc","portfolio":{"portfolio_id":"919bbfb9-c2e7-4c4c-9d6d-d20f83330245","name":"Main Portfolio","description":"Your primary investment portfolio","base_currency":"USD","active_scenario_id":"3f2e940e-c6d0-4710-ac50-7d981b4ef2dc","active_scenario_name":"My rules","allow_shorts":false},"total_value":null,"price_source":"unpriced","symbols_to_price":["ALFA","BRAV","GOLF"],"positions":[{"symbol":"ALFA","shares":250,"is_cash":false,"asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","asset_class":"Equities","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"BRAV","shares":200,"is_cash":false,"asset_class_id":"768714f9-2f74-4712-ae2a-a8cff76267b0","asset_class":"Fixed Income","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"GOLF","shares":300,"is_cash":false,"asset_class_id":"a5abe5cf-9a5c-42e4-ad3c-f50ba87186fd","asset_class":"Commodities","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"$CASH","shares":17095,"is_cash":true,"asset_class_id":"38dc3624-7d8b-41d4-83c9-6162c0b99323","asset_class":"Cash","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":1,"position_value":17095,"position_pct":null}],"expired_options":0,"exposure":null,"rules":[{"asset_class_id":"38dc3624-7d8b-41d4-83c9-6162c0b99323","asset_class":"Cash","band_min_pct":6,"band_max_pct":19,"target_allocation_pct":null,"min_position_pct":6,"max_position_pct":19,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":null},{"asset_class_id":"a5abe5cf-9a5c-42e4-ad3c-f50ba87186fd","asset_class":"Commodities","band_min_pct":4,"band_max_pct":13,"target_allocation_pct":9,"min_position_pct":4,"max_position_pct":13,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":9},{"asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","asset_class":"Equities","band_min_pct":38,"band_max_pct":56,"target_allocation_pct":47,"min_position_pct":38,"max_position_pct":56,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":47},{"asset_class_id":"768714f9-2f74-4712-ae2a-a8cff76267b0","asset_class":"Fixed Income","band_min_pct":14,"band_max_pct":29,"target_allocation_pct":21,"min_position_pct":14,"max_position_pct":29,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":21}],"compliance":null,"monitors":[],"generated_at":"2026-10-14T08:58:04.315714+00:00"},"examples":{"Example":{"title":"Example","value":{"scenario_id":"3f2e940e-c6d0-4710-ac50-7d981b4ef2dc","portfolio":{"portfolio_id":"919bbfb9-c2e7-4c4c-9d6d-d20f83330245","name":"Main Portfolio","description":"Your primary investment portfolio","base_currency":"USD","active_scenario_id":"3f2e940e-c6d0-4710-ac50-7d981b4ef2dc","active_scenario_name":"My rules","allow_shorts":false},"total_value":null,"price_source":"unpriced","symbols_to_price":["ALFA","BRAV","GOLF"],"positions":[{"symbol":"ALFA","shares":250,"is_cash":false,"asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","asset_class":"Equities","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"BRAV","shares":200,"is_cash":false,"asset_class_id":"768714f9-2f74-4712-ae2a-a8cff76267b0","asset_class":"Fixed Income","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"GOLF","shares":300,"is_cash":false,"asset_class_id":"a5abe5cf-9a5c-42e4-ad3c-f50ba87186fd","asset_class":"Commodities","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":null,"position_value":null,"position_pct":null},{"symbol":"$CASH","shares":17095,"is_cash":true,"asset_class_id":"38dc3624-7d8b-41d4-83c9-6162c0b99323","asset_class":"Cash","moves":1,"mark":null,"mark_on":null,"expired_on":null,"current_price":1,"position_value":17095,"position_pct":null}],"expired_options":0,"exposure":null,"rules":[{"asset_class_id":"38dc3624-7d8b-41d4-83c9-6162c0b99323","asset_class":"Cash","band_min_pct":6,"band_max_pct":19,"target_allocation_pct":null,"min_position_pct":6,"max_position_pct":19,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":null},{"asset_class_id":"a5abe5cf-9a5c-42e4-ad3c-f50ba87186fd","asset_class":"Commodities","band_min_pct":4,"band_max_pct":13,"target_allocation_pct":9,"min_position_pct":4,"max_position_pct":13,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":9},{"asset_class_id":"d238ab31-0a5f-4a33-99e3-b828f2d4c316","asset_class":"Equities","band_min_pct":38,"band_max_pct":56,"target_allocation_pct":47,"min_position_pct":38,"max_position_pct":56,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":47},{"asset_class_id":"768714f9-2f74-4712-ae2a-a8cff76267b0","asset_class":"Fixed Income","band_min_pct":14,"band_max_pct":29,"target_allocation_pct":21,"min_position_pct":14,"max_position_pct":29,"size_min_pct":null,"size_max_pct":null,"short_size_min_pct":null,"short_size_max_pct":null,"target_pct":21}],"compliance":null,"monitors":[],"generated_at":"2026-10-14T08:58:04.315714+00:00"}}},"exampleType":"examples"}},"exampleType":"examples"},"fc5451e6-8adf-4f62-b392-ae69cfc45c53":{"description":"Missing or malformed `portfolio_id` or `scenario_id`, or an `include_rebalance` that is not `true` or `false`","content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"}}},"exampleType":"generated"}},"exampleType":"generated"},"d3522f3c-a35f-4521-87fa-c0b1baa15ceb":{"description":"Invalid or missing API key","content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"}}},"exampleType":"generated"}},"exampleType":"generated"},"f48a9c89-17a0-432e-8f18-083fb977d05c":{"description":"Key lacks `read` permission, or API access needs an active plan","content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"}}},"exampleType":"generated"}},"exampleType":"generated"},"7451dd6c-fc52-43ff-9339-2842e7b83354":{"description":"Portfolio or scenario not found, or not yours (`NOT_FOUND`)","content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"}}},"exampleType":"generated"}},"exampleType":"generated"},"adf0e1a7-dd9b-4d12-be97-c77d76b177bc":{"description":"Rate limit exceeded: maximum 60 requests per minute per account,\nor 10,000 per UTC day (see the info block's Rate limits section).\nThe per-minute refusal carries `Retry-After: 60` and the\n`X-RateLimit-*` headers; the daily refusal carries `Retry-After`\nset to the seconds until 00:00 UTC and no `X-RateLimit-*` headers.\nNeither has an `error_code`. `POST /support-requests` and\n`POST /agent-feedback` also return `429` with `error_code:\nDAILY_LIMIT_EXCEEDED` past 20 filed per rolling 24 hours; that one\ncarries the `X-RateLimit-*` headers and no `Retry-After`.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying. Sent only on the request budget's own `429`s, never on a per-route cap (`DAILY_LIMIT_EXCEEDED`) or any other status.","schema":{"type":"integer","example":60}},"X-RateLimit-Limit":{"description":"The per-minute request budget, always `60`. Sent on every response that reaches a route and on the per-minute `429`.","schema":{"type":"integer","example":60}},"X-RateLimit-Remaining":{"description":"Requests left in the current one-minute window, after this one. The daily count is not reported until it is reached.","schema":{"type":"integer","example":41}}},"content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"}}},"exampleType":"generated"}},"exampleType":"generated"},"9f31cad5-29e7-4fb4-aaf5-ebebf2039deb":{"description":"Unexpected server error. `error_code` is `INTERNAL_ERROR` and\n`request_id` names this failure: quote it in `POST /agent-feedback`.\nThe body never carries a schema, column or constraint name.\n","content":{"application/json":{"schema":{"type":"object","description":"Uniform error envelope returned by every non-2xx response. `error` is\na human-readable message, safe to show the user. A refusal also\ncarries `error_code`, a stable string from the catalog in the info\nblock's Error codes section, to branch on; the HTTP status follows\nthe code (ADR-134). Only `401`, the no-plan `403`, the `403` for a\nkey without `read` and the `429` for the request budget have none.\nA `500` carries `request_id`. Extra fields by code:\nTIER_LIMIT_EXCEEDED carries `limit_type`, `current_count` and\n`max_allowed`, so a caller can branch on how many it has versus the\ncap without a second call. Its `error` text names no plan. It covers\nthe portfolio and scenario limits and the account caps: 20 webhook endpoints, 50\nwatchlists, 200 symbols on one watchlist and 50 custom symbols on one\nmonitor. Don't retry it. RULES_INVALID (`POST\n/scenarios/{id}/rules`) carries `issues`. ALREADY_EXISTS carries\n`existing_id`, plus `duplicate_ids` where older duplicates exist.\nCONFIRMATION_REQUIRED carries `would_remove`; from `POST /setup/apply` it\ncarries a fresh preview instead (`digest`, `file`, `items` and the rest of\n`SetupPreview`). INVALID_INPUT from the setup routes carries `issues`, and\nIN_USE from `POST /setup/receipts/{id}/undo` carries `later_receipt_id`.\nNOT_FOUND on a name, and\nINVALID_INPUT on a CHOICE value, carry `valid_values`. INVALID_INPUT on a\nmonitor whose level input is not a number type carries `input_id`.\nIN_USE on an input whose type would change while a monitor uses it\ncarries `monitors`. IN_USE on `PATCH /portfolios/{id}` that turns\nAllow shorts off while a short is held carries `short_count` and\n`symbols`. INVALID_INPUT on the holdings writes (`POST\n/positions/{symbol}`, `POST /portfolios/{id}/positions/apply`) that\nrefuses a negative `shares`, a `moves` other than 1 on an Options\nholding, or a `mark` on a holding outside the Options class, carries\n`symbols`, the holdings it refused. (`symbols` also appears on `WOULD_CLOSE_POSITIONS`, MCP\nonly, where it lists the holdings a full list left out.)\n","required":["error"],"example":{"error":"Portfolio not found or access denied","error_code":"NOT_FOUND"},"properties":{"error":{"type":"string","description":"Human-readable error message.","isRequired":true,"uniqueKey":"error","typeLabel":"string"},"error_code":{"type":"string","enum":["INVALID_INPUT","NOT_FOUND","ALREADY_EXISTS","IN_USE","CONFIRMATION_REQUIRED","PRICES_INCOMPLETE","PRICES_INVALID","WOULD_CLOSE_POSITIONS","INSUFFICIENT_CASH","RULES_INVALID","TARGET_OUT_OF_BAND","TIER_LIMIT_EXCEEDED","FEATURE_NOT_AVAILABLE","IDEMPOTENCY_KEY_CONFLICT","DAILY_LIMIT_EXCEEDED","READ_ONLY_KEY","OAUTH_WRITE_NOT_GRANTED","TOOL_REMOVED","INTERNAL_ERROR"],"description":"Stable machine-readable code from the closed catalog. Present on every refusal a route produces; absent on `401`, the no-plan `403`, the `403` for a key without `read`, and the `429` for the request budget.","uniqueKey":"error_code","typeLabel":"enum\u003cstring>"},"request_id":{"type":"string","format":"uuid","description":"Present on a `500` (`INTERNAL_ERROR`). The same id is in Allocait's logs next to the real cause; quote it when you report the failure.","uniqueKey":"request_id","typeLabel":"string\u003cuuid>"},"issues":{"type":"array","items":{"oneOf":[{"type":"object","description":"One problem or note found while reading rules text. A file\ncarrying any `error`-level issue is never applied; `POST\n/scenarios/{id}/rules` 400s with `error_code: RULES_INVALID` and\nthe full `issues` list instead. A file with only `warning`-level\nissues still applies; those ride along on the 200 response.\n","required":["level","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.level","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.0.message","typeLabel":"string"},"class":{"type":"string","description":"The asset class name this issue is about, when it is about one class rather than the whole file.","uniqueKey":"issues.items.[INDEX].oneOf.0.class","typeLabel":"string"}},"uniqueKey":"issues.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"One thing the file's text got wrong (`error`) or one note about it (`warning`, such as a web address in a description).","required":["level","where","message"],"properties":{"level":{"type":"string","enum":["error","warning"],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.level","typeLabel":"enum\u003cstring>"},"where":{"oneOf":[{"type":"string","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.0","typeLabel":"string"},{"type":"null","description":"Where in the file, or null for the file as a whole.","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.where","typeLabel":"string | null"},"message":{"type":"string","isRequired":true,"uniqueKey":"issues.items.[INDEX].oneOf.1.message","typeLabel":"string"},"line":{"type":"integer","description":"The line of the file the issue is on, when it is known.","uniqueKey":"issues.items.[INDEX].oneOf.1.line","typeLabel":"integer"}},"uniqueKey":"issues.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"issues.items.[INDEX]","typeLabel":"object"},"description":"Every error and warning found while reading the rules text, when error_code is RULES_INVALID. From the setup routes (`POST /setup/preview`, `POST /setup/apply`) it is `SetupIssue` rows, on INVALID_INPUT.","uniqueKey":"issues","typeLabel":"object[]"},"later_receipt_id":{"type":"string","format":"uuid","description":"The newer import of the same setup file that blocks this undo. Present on IN_USE from `POST /setup/receipts/{id}/undo`; undo that receipt first.","uniqueKey":"later_receipt_id","typeLabel":"string\u003cuuid>"},"limit_type":{"type":"string","description":"Which cap was hit, e.g. \"portfolios\", \"scenarios\", \"webhook_endpoints\", \"watchlists\", \"asset_classes\", \"input_entries\" or \"input_entries_per_input\". Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"limit_type","typeLabel":"string"},"current_count":{"type":"number","description":"How many of limit_type the caller has right now. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"current_count","typeLabel":"number"},"max_allowed":{"type":"number","description":"The cap for limit_type on this account. Present only when error_code is TIER_LIMIT_EXCEEDED.","uniqueKey":"max_allowed","typeLabel":"number"},"existing_id":{"type":"string","format":"uuid","description":"The record that already has this name. Present only when error_code is ALREADY_EXISTS; change it with that id instead of creating another.","uniqueKey":"existing_id","typeLabel":"string\u003cuuid>"},"duplicate_ids":{"type":"array","items":{"type":"string","format":"uuid","uniqueKey":"duplicate_ids.items.[INDEX]","typeLabel":"string\u003cuuid>"},"description":"Other records with the same name, created before duplicates were refused. Present only on ALREADY_EXISTS, and only when such records exist.","uniqueKey":"duplicate_ids","typeLabel":"string\u003cuuid>[]"},"would_remove":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string","uniqueKey":"would_remove.additionalProperties.items.[INDEX]","typeLabel":"string"},"uniqueKey":"would_remove.additionalProperties","typeLabel":"string[]"},"description":"What the call would drop, keyed by list field, for example the `items` that a watchlist save would remove. Present only when error_code is CONFIRMATION_REQUIRED; resend with those members in `remove`.","uniqueKey":"would_remove","typeLabel":"object"},"valid_values":{"type":"array","items":{"type":"string","uniqueKey":"valid_values.items.[INDEX]","typeLabel":"string"},"description":"The names or options the field accepts. Present on NOT_FOUND for a name, and on INVALID_INPUT for a CHOICE value.","uniqueKey":"valid_values","typeLabel":"string[]"},"input_id":{"type":"string","format":"uuid","description":"The level input that is not a NUMBER, DECIMAL or PERCENTAGE input. Present on INVALID_INPUT from a monitor create or update (`POST /monitors`, `PATCH /monitors/{id}`, MCP `save_monitor`); point the monitor at a number-type input instead.","uniqueKey":"input_id","typeLabel":"string\u003cuuid>"},"short_count":{"type":"integer","description":"How many shorts the portfolio holds. Present on IN_USE from `PATCH /portfolios/{id}` (MCP `save_portfolio`) that turns Allow shorts off while a short is held; close them first.","uniqueKey":"short_count","typeLabel":"integer"},"symbols":{"type":"array","items":{"type":"string","uniqueKey":"symbols.items.[INDEX]","typeLabel":"string"},"description":"Holdings the call names. On IN_USE from `PATCH /portfolios/{id}`, the shorts still held (up to 20, by symbol). On INVALID_INPUT from the holdings writes, the holdings whose negative `shares` was refused (Allow shorts is off, or the holding is in Options), or whose `moves` other than 1 was refused (the holding is in Options). On WOULD_CLOSE_POSITIONS (MCP only), the holdings a full list left out.","uniqueKey":"symbols","typeLabel":"string[]"},"monitors":{"type":"array","description":"The monitors that use this input as a level. Present on IN_USE from an input update (`PATCH /inputs/{id}`, MCP `save_input`) that would change `data_type` to TEXT or CHOICE; move those monitors to another input first.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"type":"string","uniqueKey":"monitors.items.[INDEX].name","typeLabel":"string"},"portfolio_id":{"type":"string","format":"uuid","uniqueKey":"monitors.items.[INDEX].portfolio_id","typeLabel":"string\u003cuuid>"}},"uniqueKey":"monitors.items.[INDEX]","typeLabel":"object"},"uniqueKey":"monitors","typeLabel":"object[]"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":"Internal error","error_code":"INTERNAL_ERROR","request_id":"5b1e7c52-3f4a-4d0e-9a55-2d5cbe6f0a11"},"examples":{"Example":{"title":"Example","value":{"error":"Internal error","error_code":"INTERNAL_ERROR","request_id":"5b1e7c52-3f4a-4d0e-9a55-2d5cbe6f0a11"}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"7fd1832f-5a87-49c5-91d9-dd9065c02713":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-api-key","description":"Raw API key shown once when created in the Allocait app (Settings > API keys). Send it verbatim in this header; the server stores and compares only its SHA-256 hash. Allocait generates every key: `alc_` followed by 64 lowercase hex characters. Keys issued before 2026-10-10 are 64 hex characters with no prefix and keep working. A key may carry an expiry (90 days or 1 year, or never). A malformed, unknown, revoked or expired key gets `401` with no further detail, and a malformed one is refused before any lookup. Keys cannot be created through this API.","scopes":[],"schemeName":"ApiKeyAuth"}}},"servers":{"13120e45-325e-41e1-99fd-a11d6f409d02":{"url":"https://allocait.app/api/v1","description":"Hosted Allocait API"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"apiKey","in":"header","name":"x-api-key","description":"Raw API key shown once when created in the Allocait app (Settings > API keys). Send it verbatim in this header; the server stores and compares only its SHA-256 hash. Allocait generates every key: `alc_` followed by 64 lowercase hex characters. Keys issued before 2026-10-10 are 64 hex characters with no prefix and keep working. A key may carry an expiry (90 days or 1 year, or never). A malformed, unknown, revoked or expired key gets `401` with no further detail, and a malformed one is refused before any lookup. Keys cannot be created through this API.","scopes":[],"schemeName":"ApiKeyAuth"},"schema":{"title":"x-api-key","type":"string","description":"Raw API key shown once when created in the Allocait app (Settings > API keys). Send it verbatim in this header; the server stores and compares only its SHA-256 hash. Allocait generates every key: `alc_` followed by 64 lowercase hex characters. Keys issued before 2026-10-10 are 64 hex characters with no prefix and keep working. A key may carry an expiry (90 days or 1 year, or never). A malformed, unknown, revoked or expired key gets `401` with no further detail, and a malformed one is refused before any lookup. Keys cannot be created through this API.","isRequired":true,"typeLabel":"string","deprecated":false},"schemeName":"ApiKeyAuth","name":"x-api-key"}],"title":"ApiKeyAuth"}]},"originalFileLocation":"openapi.yaml"},"subdomain":"allocait","siteName":"Allocait","title":"Get a portfolio snapshot (unpriced) - Allocait","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-11-09T05:23:21.058Z","originalFileLocation":"api-reference/portfolios/get-a-portfolio-snapshot-unpriced.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"dark\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"This is the discovery call: unpriced. Returns a single denormalized blob with the portfolio, the holdings in shares, the active scenario\u0026#x27;s rules, the recorded levels, and monitor configuration. current_price, position_value and position_pct on every non-cash position, total_value, exposure, compliance, and every monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price lists every symbol you would need to price to see the rest. A held option is the exception: it is priced at its mark, the user\u0026#x27;s own number, so it keeps its current_price and position_value here, and expired_on and expired_options show what has expired (ADR-147). Allocait never fills a symbol from its own market data on this surface (ADR-036). The flow is two calls: GET this to see what\u0026#x27;s held, then POST here with prices for the symbols it listed (or call /compliance/check / /rebalance/preview directly, which require full coverage). The rebalance block (sized amounts) is left out unless you add include_rebalance=true. Ask for it when the person wants to know what it would take to get back inside a band; a check answer comes from compliance (ADR-113). The monitors block reports where each recorded level stands at the prices you pass. It is a reading, not a break. A break is confirmed only by the once-daily close check, which this endpoint does not report. GET /monitors returns each monitor\u0026#x27;s full configuration. If scenario_id is omitted, the portfolio\u0026#x27;s active_scenario_id is used.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Allocait\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Get a portfolio snapshot (unpriced) - Allocait\">\u003cmeta data-mint-head property=\"og:description\" content=\"This is the discovery call: unpriced. Returns a single denormalized blob with the portfolio, the holdings in shares, the active scenario\u0026#x27;s rules, the recorded levels, and monitor configuration. current_price, position_value and position_pct on every non-cash position, total_value, exposure, compliance, and every monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price lists every symbol you would need to price to see the rest. A held option is the exception: it is priced at its mark, the user\u0026#x27;s own number, so it keeps its current_price and position_value here, and expired_on and expired_options show what has expired (ADR-147). Allocait never fills a symbol from its own market data on this surface (ADR-036). The flow is two calls: GET this to see what\u0026#x27;s held, then POST here with prices for the symbols it listed (or call /compliance/check / /rebalance/preview directly, which require full coverage). The rebalance block (sized amounts) is left out unless you add include_rebalance=true. Ask for it when the person wants to know what it would take to get back inside a band; a check answer comes from compliance (ADR-113). The monitors block reports where each recorded level stands at the prices you pass. It is a reading, not a break. A break is confirmed only by the once-daily close check, which this endpoint does not report. GET /monitors returns each monitor\u0026#x27;s full configuration. If scenario_id is omitted, the portfolio\u0026#x27;s active_scenario_id is used.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Allocait\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://allocait.mintlify.site/_mintlify/api/og/v2?division=Portfolios\u0026amp;title=Get+a+portfolio+snapshot+%28unpriced%29\u0026amp;description=This+is+the+discovery+call%3A+unpriced.+Returns+a+single+denormalized%0Ablob+with+the+portfolio%2C+the+holdings+in+shares%2C+the+active%0Ascenario%27s+rules%2C+the+recorded+l\u0026amp;theme=f4ffca4ae92cd96f3d29a15e\u0026amp;signature=2d8687352fb5ff1ec329e544d799b0aee71820372fa7241292e4e97e295d0048\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Get a portfolio snapshot (unpriced) - Allocait\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"This is the discovery call: unpriced. Returns a single denormalized blob with the portfolio, the holdings in shares, the active scenario\u0026#x27;s rules, the recorded levels, and monitor configuration. current_price, position_value and position_pct on every non-cash position, total_value, exposure, compliance, and every monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price lists every symbol you would need to price to see the rest. A held option is the exception: it is priced at its mark, the user\u0026#x27;s own number, so it keeps its current_price and position_value here, and expired_on and expired_options show what has expired (ADR-147). Allocait never fills a symbol from its own market data on this surface (ADR-036). The flow is two calls: GET this to see what\u0026#x27;s held, then POST here with prices for the symbols it listed (or call /compliance/check / /rebalance/preview directly, which require full coverage). The rebalance block (sized amounts) is left out unless you add include_rebalance=true. Ask for it when the person wants to know what it would take to get back inside a band; a check answer comes from compliance (ADR-113). The monitors block reports where each recorded level stands at the prices you pass. It is a reading, not a break. A break is confirmed only by the once-daily close check, which this endpoint does not report. GET /monitors returns each monitor\u0026#x27;s full configuration. If scenario_id is omitted, the portfolio\u0026#x27;s active_scenario_id is used.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://allocait.mintlify.site/_mintlify/api/og/v2?division=Portfolios\u0026amp;title=Get+a+portfolio+snapshot+%28unpriced%29\u0026amp;description=This+is+the+discovery+call%3A+unpriced.+Returns+a+single+denormalized%0Ablob+with+the+portfolio%2C+the+holdings+in+shares%2C+the+active%0Ascenario%27s+rules%2C+the+recorded+l\u0026amp;theme=f4ffca4ae92cd96f3d29a15e\u0026amp;signature=2d8687352fb5ff1ec329e544d799b0aee71820372fa7241292e4e97e295d0048\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/allocait/8WDpZ9h0WNasoRjb/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Allocait\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#0b0b0b\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.allocait.app/#organization\",\"name\":\"Allocait\",\"url\":\"https://docs.allocait.app\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/allocait/N9X8GrpLUSiZAKIm/logo/light.svg?fit=max\u0026auto=format\u0026n=N9X8GrpLUSiZAKIm\u0026q=85\u0026s=37c68a7ac5dc3550d24f484060530ea6\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.allocait.app#website\",\"name\":\"Allocait\",\"url\":\"https://docs.allocait.app\",\"publisher\":{\"@id\":\"https://docs.allocait.app/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced#webpage\",\"url\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced\",\"name\":\"Get a portfolio snapshot (unpriced)\",\"description\":\"This is the discovery call: unpriced. Returns a single denormalized blob with the portfolio, the holdings in shares, the active scenario's rules, the recorded levels, and monitor configuration. current_price, position_value and position_pct on every non-cash position, total_value, exposure, compliance, and every monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price lists every symbol you would need to price to see the rest. A held option is the exception: it is priced at its mark, the user's own number, so it keeps its current_price and position_value here, and expired_on and expired_options show what has expired (ADR-147). Allocait never fills a symbol from its own market data on this surface (ADR-036). The flow is two calls: GET this to see what's held, then POST here with prices for the symbols it listed (or call /compliance/check / /rebalance/preview directly, which require full coverage). The rebalance block (sized amounts) is left out unless you add include_rebalance=true. Ask for it when the person wants to know what it would take to get back inside a band; a check answer comes from compliance (ADR-113). The monitors block reports where each recorded level stands at the prices you pass. It is a reading, not a break. A break is confirmed only by the once-daily close check, which this endpoint does not report. GET /monitors returns each monitor's full configuration. If scenario_id is omitted, the portfolio's active_scenario_id is used.\",\"dateModified\":\"2026-11-09T05:23:21.058Z\",\"isPartOf\":{\"@id\":\"https://docs.allocait.app#website\"},\"breadcrumb\":{\"@id\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Endpoints\",\"item\":\"https://docs.allocait.app/api-reference/checks/check-compliance-with-your-prices\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Portfolios\",\"item\":\"https://docs.allocait.app/api-reference/portfolios/get-portfolio-summary\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Get a portfolio snapshot (unpriced)\",\"item\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced#apireference\",\"headline\":\"Get a portfolio snapshot (unpriced)\",\"name\":\"Get a portfolio snapshot (unpriced)\",\"description\":\"This is the discovery call: unpriced. Returns a single denormalized blob with the portfolio, the holdings in shares, the active scenario's rules, the recorded levels, and monitor configuration. current_price, position_value and position_pct on every non-cash position, total_value, exposure, compliance, and every monitor measurement all come back null (and rebalance, when you ask for it). symbols_to_price lists every symbol you would need to price to see the rest. A held option is the exception: it is priced at its mark, the user's own number, so it keeps its current_price and position_value here, and expired_on and expired_options show what has expired (ADR-147). Allocait never fills a symbol from its own market data on this surface (ADR-036). The flow is two calls: GET this to see what's held, then POST here with prices for the symbols it listed (or call /compliance/check / /rebalance/preview directly, which require full coverage). The rebalance block (sized amounts) is left out unless you add include_rebalance=true. Ask for it when the person wants to know what it would take to get back inside a band; a check answer comes from compliance (ADR-113). The monitors block reports where each recorded level stands at the prices you pass. It is a reading, not a break. A break is confirmed only by the once-daily close check, which this endpoint does not report. GET /monitors returns each monitor's full configuration. If scenario_id is omitted, the portfolio's active_scenario_id is used.\",\"url\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced\",\"mainEntityOfPage\":{\"@id\":\"https://docs.allocait.app/api-reference/portfolios/get-a-portfolio-snapshot-unpriced#webpage\"},\"dateModified\":\"2026-11-09T05:23:21.058Z\",\"publisher\":{\"@id\":\"https://docs.allocait.app/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.allocait.app#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Allocait\",\"publisher\":{\"@type\":\"Organization\",\"name\":\"Allocait\"},\"provider\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","agentPointerHref":"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced.md","siteName":"Allocait","nav":{"global":null,"tabs":[{"tab":"Get started","pages":[{"title":"Get started","href":""}]},{"tab":"Concepts","pages":[{"title":"Concepts","href":"/concepts/allocation-bands"}]},{"tab":"Claude \u0026 MCP","pages":[{"title":"Claude \u0026 MCP","href":"/claude/overview"}]},{"tab":"ChatGPT \u0026 Codex","pages":[{"title":"ChatGPT \u0026 Codex","href":"/chatgpt/connect"}]},{"tab":"Guides","pages":[{"title":"Guides","href":"/guides/write-your-rules"}]},{"tab":"API reference","groups":[{"group":"Start","pages":[{"title":"API overview","sidebarTitle":"Overview","href":"/api/introduction"},{"title":"Endpoints by task","sidebarTitle":"By task","href":"/api/endpoints-by-task"},{"title":"API quickstart","sidebarTitle":"Quickstart","href":"/api/quickstart"},{"title":"Authentication","sidebarTitle":"Authentication","href":"/api/authentication"}]},{"group":"Conventions","pages":[{"title":"Conventions","sidebarTitle":"Conventions","href":"/api/conventions"},{"title":"Rate limits","sidebarTitle":"Rate limits","href":"/api/rate-limits"},{"title":"Idempotency","sidebarTitle":"Idempotency","href":"/api/idempotency"}]},{"group":"Errors","pages":[{"title":"API errors","sidebarTitle":"Errors","href":"/api/errors"},{"title":"Error codes","sidebarTitle":"Error codes","href":"/api/error-codes"}]},{"group":"Webhooks","pages":[{"title":"Webhook events","sidebarTitle":"Webhook events","href":"/api/webhook-events"},{"title":"Verify deliveries","sidebarTitle":"Verify deliveries","href":"/api/webhook-verification"}]},{"group":"Endpoints","pages":[{"group":"Checks","pages":[{"title":"Check compliance with your prices","deprecated":null,"version":null,"openapi":"/openapi.yaml post /compliance/check","href":"/api-reference/checks/check-compliance-with-your-prices"},{"title":"Pre-flight check of a proposed allocation plan","deprecated":null,"version":null,"openapi":"/openapi.yaml post /validate","href":"/api-reference/checks/pre-flight-check-of-a-proposed-allocation-plan"},{"title":"Check a proposed change against the rules","deprecated":null,"version":null,"openapi":"/openapi.yaml post /trades/check","href":"/api-reference/checks/check-a-proposed-change-against-the-rules"},{"title":"Preview rebalance amounts with your prices","deprecated":null,"version":null,"openapi":"/openapi.yaml post /rebalance/preview","href":"/api-reference/checks/preview-rebalance-amounts-with-your-prices"}]},{"group":"Portfolios","pages":[{"title":"Get portfolio summary","deprecated":null,"version":null,"openapi":"/openapi.yaml get /portfolio/summary","href":"/api-reference/portfolios/get-portfolio-summary"},{"title":"List portfolios","deprecated":null,"version":null,"openapi":"/openapi.yaml get /portfolios","href":"/api-reference/portfolios/list-portfolios"},{"title":"Create a portfolio with an initial cash position","deprecated":null,"version":null,"openapi":"/openapi.yaml post /portfolios","href":"/api-reference/portfolios/create-a-portfolio-with-an-initial-cash-position"},{"title":"Delete a portfolio","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /portfolios/{id}","href":"/api-reference/portfolios/delete-a-portfolio"},{"title":"Change a portfolio's name, description, active scenario or Allow shorts","description":"Every field is optional. A field you send replaces the stored value,\nand a field you leave out keeps its value; send `description: null`\nto clear the description. `active_scenario_id` switches the scenario\nthe portfolio is checked against, in the app and on this API alike.\nThe same function backs the MCP server's `save_portfolio`.\n\n`allow_shorts` lets holdings carry a negative `shares` (a short);\n`false` turns it off and `null` is a `400`. It is the person's\nchoice: ask before you turn it on, and never turn it on only to get\na refused write through. Turning it off while a short is held is a\n`409` `IN_USE` that carries `short_count` and `symbols`: close those\nshorts first (ADR-153). Options are held long only whatever this\nsays.\n\n**Requires the API key to have the `write` permission.**\n","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /portfolios/{id}","href":"/api-reference/portfolios/change-a-portfolios-name-description-active-scenario-or-allow-shorts"},{"title":"Get a portfolio snapshot (unpriced)","deprecated":null,"version":null,"openapi":"/openapi.yaml get /portfolio/snapshot","href":"/api-reference/portfolios/get-a-portfolio-snapshot-unpriced"},{"title":"Get a portfolio snapshot with your prices","description":"Same blob as GET /portfolio/snapshot, priced as far as your `prices`\nmap reaches, no further. A position you priced keeps its value; one\nyou did not comes back null. `position_pct`, `total_value`,\n`exposure`, `compliance` (and `rebalance`, when you ask for it) need\nevery non-cash position covered, because one stored quote in the sum\nwould contaminate all of them. A held option with a mark, or one past\nits expiry, counts as covered without an entry in `prices`; a price\nyou pass for an unexpired option replaces its mark for this call only,\nand an expired option counts 0 whatever you pass (ADR-147).\nThe same map is applied to the `monitors` block: a monitor symbol\nyou did not price comes back with `price` null and its measurements\nnull.\n\nA portfolio worth zero or less (shorts that have gone against the\nholder can take it there) has no percentages: `total_value` stays\nsigned, every `position_pct` is null and `compliance` reads\n`unjudged` with no breach listed (ADR-153).\n\n`exposure` says how much of the portfolio gains if prices rise (long,\nshort, net and gross as percents of `total_value`, by asset class and\nper holding). It is a reading, not a rule. It needs a number in\n`prices` for every non-cash holding, even when Allocait holds a quote\nof its own for one you left out, because each percent is a share of the\nwhole book (ADR-036, ADR-142); an option with a mark counts as covered,\nand counts at its premium. It is computed from your prices and the\nuser's marks and never stored. Each position carries its `moves`,\n`mark`, `mark_on` and `expired_on`.\n\n`symbols_to_price` is empty once the payload is entirely your own\nnumbers, and `price_source` is then `overrides`. Allocait never\nfills a symbol you omitted from its own quote (ADR-036). Nothing is\nwritten.\n\nThe `rebalance` block (sized amounts) is left out unless you add the\nquery flag `include_rebalance=true`. Ask for it when the person wants\nto know what it would take to get back inside a band; a check answer\ncomes from `compliance`. `POST /rebalance/preview` returns the same\namounts (ADR-113).\n","deprecated":null,"version":null,"openapi":"/openapi.yaml post /portfolio/snapshot","href":"/api-reference/portfolios/get-a-portfolio-snapshot-with-your-prices"}]},{"group":"Holdings and cash","pages":[{"title":"List positions","deprecated":null,"version":null,"openapi":"/openapi.yaml get /positions","href":"/api-reference/holdings-and-cash/list-positions"},{"title":"Record one holding's new total shares","deprecated":null,"version":null,"openapi":"/openapi.yaml post /positions/{symbol}","href":"/api-reference/holdings-and-cash/record-one-holdings-new-total-shares"},{"title":"Calculate a target share count for a position","deprecated":null,"version":null,"openapi":"/openapi.yaml post /positions/size","href":"/api-reference/holdings-and-cash/calculate-a-target-share-count-for-a-position"},{"title":"Reconcile a portfolio's holdings to an absolute desired state","deprecated":null,"version":null,"openapi":"/openapi.yaml post /portfolios/{id}/positions/apply","href":"/api-reference/holdings-and-cash/reconcile-a-portfolios-holdings-to-an-absolute-desired-state"},{"title":"Deposit or withdraw cash from a portfolio","deprecated":null,"version":null,"openapi":"/openapi.yaml post /portfolios/{id}/cash-movements","href":"/api-reference/holdings-and-cash/deposit-or-withdraw-cash-from-a-portfolio"}]},{"group":"Watchlists","pages":[{"title":"List watchlists","deprecated":null,"version":null,"openapi":"/openapi.yaml get /watchlists","href":"/api-reference/watchlists/list-watchlists"},{"title":"Create a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml post /watchlists","href":"/api-reference/watchlists/create-a-watchlist"},{"title":"Change a watchlist's name and symbols in one call","deprecated":null,"version":null,"openapi":"/openapi.yaml put /watchlists/{id}","href":"/api-reference/watchlists/change-a-watchlists-name-and-symbols-in-one-call"},{"title":"Delete a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /watchlists/{id}","href":"/api-reference/watchlists/delete-a-watchlist"},{"title":"Rename a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /watchlists/{id}","href":"/api-reference/watchlists/rename-a-watchlist"},{"title":"List items in a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml get /watchlists/{id}/items","href":"/api-reference/watchlists/list-items-in-a-watchlist"},{"title":"Add a symbol to a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml post /watchlists/{id}/items","href":"/api-reference/watchlists/add-a-symbol-to-a-watchlist"},{"title":"Reorder a watchlist's items","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /watchlists/{id}/items","href":"/api-reference/watchlists/reorder-a-watchlists-items"},{"title":"Remove a symbol from a watchlist","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /watchlists/{id}/items/{item_id}","href":"/api-reference/watchlists/remove-a-symbol-from-a-watchlist"}]},{"group":"Inputs","pages":[{"title":"List input (tracked-value) definitions","deprecated":null,"version":null,"openapi":"/openapi.yaml get /inputs","href":"/api-reference/inputs/list-input-tracked-value-definitions"},{"title":"Create an Input (tracked-value) definition","deprecated":null,"version":null,"openapi":"/openapi.yaml post /inputs","href":"/api-reference/inputs/create-an-input-tracked-value-definition"},{"title":"Change an Input definition and its options in one call","deprecated":null,"version":null,"openapi":"/openapi.yaml put /inputs/{id}","href":"/api-reference/inputs/change-an-input-definition-and-its-options-in-one-call"},{"title":"Delete an Input definition","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /inputs/{id}","href":"/api-reference/inputs/delete-an-input-definition"},{"title":"Update an Input definition","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /inputs/{id}","href":"/api-reference/inputs/update-an-input-definition"},{"title":"List recorded values for one input","deprecated":null,"version":null,"openapi":"/openapi.yaml get /inputs/{id}/entries","href":"/api-reference/inputs/list-recorded-values-for-one-input"},{"title":"List dropdown options for one CHOICE input","deprecated":null,"version":null,"openapi":"/openapi.yaml get /inputs/{id}/options","href":"/api-reference/inputs/list-dropdown-options-for-one-choice-input"},{"title":"Add a dropdown option","deprecated":null,"version":null,"openapi":"/openapi.yaml post /inputs/{id}/options","href":"/api-reference/inputs/add-a-dropdown-option"},{"title":"Remove a dropdown option","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /inputs/{id}/options/{option_id}","href":"/api-reference/inputs/remove-a-dropdown-option"},{"title":"Rename or reorder a dropdown option","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /inputs/{id}/options/{option_id}","href":"/api-reference/inputs/rename-or-reorder-a-dropdown-option"},{"title":"Record (upsert) one or more custom input values","deprecated":null,"version":null,"openapi":"/openapi.yaml post /inputs/entries","href":"/api-reference/inputs/record-upsert-one-or-more-custom-input-values"},{"title":"Delete one or more recorded input values","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /inputs/entries","href":"/api-reference/inputs/delete-one-or-more-recorded-input-values"}]},{"group":"Playbooks","pages":[{"title":"List playbooks","deprecated":null,"version":null,"openapi":"/openapi.yaml get /playbooks","href":"/api-reference/playbooks/list-playbooks"},{"title":"Create a playbook","deprecated":null,"version":null,"openapi":"/openapi.yaml post /playbooks","href":"/api-reference/playbooks/create-a-playbook"},{"title":"Resolve a playbook's symbols and its input values for a date","deprecated":null,"version":null,"openapi":"/openapi.yaml get /playbooks/{id}","href":"/api-reference/playbooks/resolve-a-playbooks-symbols-and-its-input-values-for-a-date"},{"title":"Delete a playbook","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /playbooks/{id}","href":"/api-reference/playbooks/delete-a-playbook"},{"title":"Update a playbook","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /playbooks/{id}","href":"/api-reference/playbooks/update-a-playbook"}]},{"group":"Monitors","pages":[{"title":"List condition monitors and their recorded levels","deprecated":null,"version":null,"openapi":"/openapi.yaml get /monitors","href":"/api-reference/monitors/list-condition-monitors-and-their-recorded-levels"},{"title":"Create a condition monitor","deprecated":null,"version":null,"openapi":"/openapi.yaml post /monitors","href":"/api-reference/monitors/create-a-condition-monitor"},{"title":"Delete a condition monitor","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /monitors/{id}","href":"/api-reference/monitors/delete-a-condition-monitor"},{"title":"Update a condition monitor","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /monitors/{id}","href":"/api-reference/monitors/update-a-condition-monitor"}]},{"group":"Rules","pages":[{"title":"List scenarios","deprecated":null,"version":null,"openapi":"/openapi.yaml get /scenarios","href":"/api-reference/rules/list-scenarios"},{"title":"Create a scenario","deprecated":null,"version":null,"openapi":"/openapi.yaml post /scenarios","href":"/api-reference/rules/create-a-scenario"},{"title":"Delete a scenario","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /scenarios/{id}","href":"/api-reference/rules/delete-a-scenario"},{"title":"Rename a scenario and/or replace its description","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /scenarios/{id}","href":"/api-reference/rules/rename-a-scenario-andor-replace-its-description"},{"title":"List asset classes","deprecated":null,"version":null,"openapi":"/openapi.yaml get /asset-classes","href":"/api-reference/rules/list-asset-classes"},{"title":"Create a custom asset class","deprecated":null,"version":null,"openapi":"/openapi.yaml post /asset-classes","href":"/api-reference/rules/create-a-custom-asset-class"},{"title":"Delete a custom asset class","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /asset-classes/{id}","href":"/api-reference/rules/delete-a-custom-asset-class"},{"title":"Rename an asset class and/or replace its description","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /asset-classes/{id}","href":"/api-reference/rules/rename-an-asset-class-andor-replace-its-description"},{"title":"List position rules (allocation band and position size per asset class)","deprecated":null,"version":null,"openapi":"/openapi.yaml get /position-rules","href":"/api-reference/rules/list-position-rules-allocation-band-and-position-size-per-asset-class"},{"title":"Set one asset class's rule in a scenario","deprecated":null,"version":null,"openapi":"/openapi.yaml post /scenarios/{id}/position-rules","href":"/api-reference/rules/set-one-asset-classs-rule-in-a-scenario"},{"title":"Reconcile a scenario's position rules to an absolute desired state","deprecated":null,"version":null,"openapi":"/openapi.yaml post /scenarios/{id}/position-rules/apply","href":"/api-reference/rules/reconcile-a-scenarios-position-rules-to-an-absolute-desired-state"},{"title":"Get a scenario's rules as rules text","deprecated":null,"version":null,"openapi":"/openapi.yaml get /scenarios/{id}/rules","href":"/api-reference/rules/get-a-scenarios-rules-as-rules-text"},{"title":"Import rules text into a scenario's rules, or preview it with dry_run","deprecated":null,"version":null,"openapi":"/openapi.yaml post /scenarios/{id}/rules","href":"/api-reference/rules/import-rules-text-into-a-scenarios-rules-or-preview-it-with-dry_run"},{"title":"List rules restore points, newest first","deprecated":null,"version":null,"openapi":"/openapi.yaml get /rules/restore-points","href":"/api-reference/rules/list-rules-restore-points-newest-first"},{"title":"Undo an import or an earlier restore","deprecated":null,"version":null,"openapi":"/openapi.yaml post /rules/restore-points/{id}/restore","href":"/api-reference/rules/undo-an-import-or-an-earlier-restore"},{"title":"Get the rules text format spec, ready-to-import examples, and copy/paste AI prompts","deprecated":null,"version":null,"openapi":"/openapi.yaml get /rules/spec","href":"/api-reference/rules/get-the-rules-text-format-spec-ready-to-import-examples-and-copypaste-ai-prompts"}]},{"group":"Actions","pages":[{"title":"List a portfolio's actions","deprecated":null,"version":null,"openapi":"/openapi.yaml get /actions","href":"/api-reference/actions/list-a-portfolios-actions"},{"title":"Delete one or more actions","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /actions","href":"/api-reference/actions/delete-one-or-more-actions"},{"title":"Edit an action's comment","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /actions/{id}","href":"/api-reference/actions/edit-an-actions-comment"}]},{"group":"Support and feedback","pages":[{"title":"List your support requests, newest first","deprecated":null,"version":null,"openapi":"/openapi.yaml get /support-requests","href":"/api-reference/support-and-feedback/list-your-support-requests-newest-first"},{"title":"File a support request","deprecated":null,"version":null,"openapi":"/openapi.yaml post /support-requests","href":"/api-reference/support-and-feedback/file-a-support-request"},{"title":"List your agent feedback, newest first","deprecated":null,"version":null,"openapi":"/openapi.yaml get /agent-feedback","href":"/api-reference/support-and-feedback/list-your-agent-feedback-newest-first"},{"title":"Report feedback about the agent surface itself","deprecated":null,"version":null,"openapi":"/openapi.yaml post /agent-feedback","href":"/api-reference/support-and-feedback/report-feedback-about-the-agent-surface-itself"}]},{"group":"Charts","pages":[{"title":"List saved charts for a portfolio","deprecated":null,"version":null,"openapi":"/openapi.yaml get /charts","href":"/api-reference/charts/list-saved-charts-for-a-portfolio"},{"title":"Create a saved chart","deprecated":null,"version":null,"openapi":"/openapi.yaml post /charts","href":"/api-reference/charts/create-a-saved-chart"},{"title":"Delete a saved chart","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /charts/{id}","href":"/api-reference/charts/delete-a-saved-chart"},{"title":"Update a saved chart","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /charts/{id}","href":"/api-reference/charts/update-a-saved-chart"}]},{"group":"Preferences","pages":[{"title":"Get what the app opens to, and the theme","deprecated":null,"version":null,"openapi":"/openapi.yaml get /preferences","href":"/api-reference/preferences/get-what-the-app-opens-to-and-the-theme"},{"title":"Set which portfolio/watchlist/chart/playbook/monitor the app shows, or the theme","deprecated":null,"version":null,"openapi":"/openapi.yaml post /preferences","href":"/api-reference/preferences/set-which-portfoliowatchlistchartplaybookmonitor-the-app-shows-or-the-theme"}]},{"group":"Webhooks","pages":[{"title":"List webhook endpoints","deprecated":null,"version":null,"openapi":"/openapi.yaml get /webhooks","href":"/api-reference/webhooks/list-webhook-endpoints"},{"title":"Register a webhook endpoint","deprecated":null,"version":null,"openapi":"/openapi.yaml post /webhooks","href":"/api-reference/webhooks/register-a-webhook-endpoint"},{"title":"Delete a webhook endpoint","deprecated":null,"version":null,"openapi":"/openapi.yaml delete /webhooks/{id}","href":"/api-reference/webhooks/delete-a-webhook-endpoint"},{"title":"Update a webhook endpoint","deprecated":null,"version":null,"openapi":"/openapi.yaml patch /webhooks/{id}","href":"/api-reference/webhooks/update-a-webhook-endpoint"}]},{"group":"Setup file","pages":[{"title":"Export your watchlists, Inputs, playbooks, monitors and saved charts as one JSON document","deprecated":null,"version":null,"openapi":"/openapi.yaml get /setup/export","href":"/api-reference/setup-file/export-your-watchlists-inputs-playbooks-monitors-and-saved-charts-as-one-json-document"},{"title":"Preview an ALLOCAIT.md setup file","deprecated":null,"version":null,"openapi":"/openapi.yaml post /setup/preview","href":"/api-reference/setup-file/preview-an-allocaitmd-setup-file"},{"title":"Apply a previewed ALLOCAIT.md setup file","deprecated":null,"version":null,"openapi":"/openapi.yaml post /setup/apply","href":"/api-reference/setup-file/apply-a-previewed-allocaitmd-setup-file"},{"title":"List the account's setup file receipts","deprecated":null,"version":null,"openapi":"/openapi.yaml get /setup/receipts","href":"/api-reference/setup-file/list-the-accounts-setup-file-receipts"},{"title":"Undo an applied setup file, or preview the undo","deprecated":null,"version":null,"openapi":"/openapi.yaml post /setup/receipts/{id}/undo","href":"/api-reference/setup-file/undo-an-applied-setup-file-or-preview-the-undo"}]}]}]},{"tab":"Support \u0026 trust","pages":[{"title":"Support \u0026 trust","href":"/support"}]}]},"basePath":"","title":"Get a portfolio snapshot (unpriced) - Allocait","buildId":"dpl_596ePT575z4qnAFksq1biRW97aLY","deploymentId":"dpl_596ePT575z4qnAFksq1biRW97aLY","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-C9Wu0MeN.js","utils-jWgu-6Qf.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DBD8f9qn.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-BGuX1ui5.js","snippetPresets-Evy63nQB.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","ApiExamples-BQHO1lnV.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-B6C8m-t_.js","shallow-BG4cT0fH.js","getApiPlaygroundDisplay-CgEPrE-D.js","CodeSnippet-CU8JyZ9N.js","CodeSnippets-BnxHU32T.js","Page-D6S0Yh6q.js","getPastedJson-CwiYOonh.js","icon-DYDpWmDf.js","MethodPill-C-J-l7_c.js","DuplicateIcon-B6ARwg9w.js","createIcon-Dsv4MtDq.js","DynamicMarkdown-CtasenyM.js","SectionHeading-YNcgYwjB.js","axios-vUo_bRtp.js","Markdown-CwLx6PAg.js","clsx-C3kuh_dz.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CmKHfscc.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-U3mI6Ljh.js"]}