Browse the API reference

Update Portfolio Block

post/extensions/roboinvestor/{graph_id}/operations/update-portfolio-block

Part of Extensions: RoboInvestor.

Patch portfolio fields and apply position deltas (add / update / dispose) atomically. Partial failures roll back.

Idempotency: supply an Idempotency-Key header to make safe retries; replays within 24 hours return the same envelope. Reusing the key with a different body returns HTTP 409 Conflict.

Authentication

Authenticate in any one of these ways — not all of them:

  • API key in the X-API-Key header.
  • Bearer token in the Authorization header.

Path parameters

NameTypeDescription
graph_idrequiredstringGraph Id

Header parameters

NameTypeDescription
Idempotency-KeyoptionalstringIdempotency-Key

Request body

Required, application/json.

FieldTypeDescription
portfolio_idrequiredstring

Target portfolio ID.

portfoliooptionalPortfolioBlockPortfolioPatch

Patch to portfolio core fields. Omit or leave fields unset to leave the portfolio core unchanged.

PortfolioBlockPortfolioPatch fields
FieldTypeDescription
nameoptionalstring

New display name. Unset = unchanged.

descriptionoptionalstring

New description. Unset = unchanged.

strategyoptionalstring

New strategy classification. Unset = unchanged.

inception_dateoptionalstring (date)

New inception date (YYYY-MM-DD). Unset = unchanged.

base_currencyoptionalstring

New ISO 4217 base currency code. Unset = unchanged. Note: changing base currency does not retroactively reprice historical positions.

entity_idoptionalstring

New owning-entity ID. Unset = unchanged.

positionsoptionalPortfolioBlockPositions

Position deltas — additions, in-place updates, and dispositions — applied atomically with the portfolio patch.

PortfolioBlockPositions fields
FieldTypeDescription
addoptionalPortfolioBlockPositionAdd[]

New positions to mint inside this portfolio. Each references an existing `security_id`.

PortfolioBlockPositionAdd fields
FieldTypeDescription
security_idrequiredstring

ID of the existing security this position holds. Securities are minted via `create-security`; the operation returns 404 if the ID is unknown.

quantityrequirednumber

Quantity held, in units defined by `quantity_type` (e.g. share count for `shares`, face value for `principal`).

quantity_typeoptionalstring

Unit basis for `quantity`. Common values: `shares` (equity units), `units` (generic), `principal` (debt face value).

Default: shares

cost_basisoptionalinteger

Total cost basis for this lot, in **cents** of `currency`. Stored as integer cents to avoid float precision drift; $1,250.00 USD is `125000`.

Default: 0

currencyoptionalstring

ISO 4217 currency code for `cost_basis` and `current_value`.

Default: USD

current_valueoptionalinteger

Latest mark-to-market value in **cents** of `currency`, or `null` if unmarked. Pair with `valuation_date` and `valuation_source` when set.

valuation_dateoptionalstring (date)

Date `current_value` was sourced (YYYY-MM-DD).

valuation_sourceoptionalstring

Free-text source attribution for `current_value` (e.g. `manual`, `broker_statement`, vendor name).

acquisition_dateoptionalstring (date)

Date the position was originally acquired (YYYY-MM-DD).

notesoptionalstring

Free-text notes attached to the position.

updateoptionalPortfolioBlockPositionUpdate[]

Patches to existing positions, addressed by position `id`. Unset fields on each entry are left unchanged.

PortfolioBlockPositionUpdate fields
FieldTypeDescription
idrequiredstring

Target position ID. Must belong to the portfolio identified by `portfolio_id` on the parent operation.

quantityoptionalnumber

New quantity in units of `quantity_type`. Unset = unchanged.

quantity_typeoptionalstring

New unit basis (`shares` | `units` | `principal`). Unset = unchanged.

cost_basisoptionalinteger

New cost basis in **cents** of the position's currency. Unset = unchanged.

current_valueoptionalinteger

New mark-to-market value in **cents**. Unset = unchanged. Set alongside `valuation_date` / `valuation_source` to record a fresh valuation event.

valuation_dateoptionalstring (date)

New valuation date (YYYY-MM-DD). Unset = unchanged.

valuation_sourceoptionalstring

New valuation source attribution. Unset = unchanged.

acquisition_dateoptionalstring (date)

New acquisition date (YYYY-MM-DD). Unset = unchanged.

notesoptionalstring

New notes. Unset = unchanged.

disposeoptionalPortfolioBlockPositionDispose[]

Positions to soft-dispose, addressed by position `id`. Status flips to `disposed` and `disposition_date` is stamped.

PortfolioBlockPositionDispose fields
FieldTypeDescription
idrequiredstring

Target position ID to dispose. Must belong to the portfolio identified by `portfolio_id` on the parent operation.

disposition_reasonoptionalstring

Optional free-text reason recorded under `metadata.disposition_reason` on the disposed position.

Example request

curl
curl -X POST "https://api.robosystems.ai/extensions/roboinvestor/{graph_id}/operations/update-portfolio-block" \
  -H "X-API-Key: $ROBOSYSTEMS_API_KEY" \
  -H "Idempotency-Key: <Idempotency-Key>" \
  -H "Content-Type: application/json" \
  -d '{
  "portfolio": {
    "description": "Pivoted toward defensive holdings"
  },
  "portfolio_id": "port_q1_growth_2026",
  "positions": {
    "add": [],
    "dispose": [
      {
        "disposition_reason": "Liquidated; rotated capital",
        "id": "pos_oldcorp_lot_3"
      }
    ],
    "update": [
      {
        "current_value": 1980000,
        "id": "pos_aapl_lot_1",
        "valuation_date": "2026-05-06",
        "valuation_source": "broker_statement"
      },
      {
        "current_value": 2310000,
        "id": "pos_msft_lot_1",
        "valuation_date": "2026-05-06",
        "valuation_source": "broker_statement"
      }
    ]
  }
}'

Responses

200 Successful Response

FieldTypeDescription
operationrequiredstring

Kebab-case operation name

operationIdrequiredstring

op_-prefixed ULID for audit and SSE correlation

statusrequiredstring

Operation lifecycle state

One of: completed, pending, failed

resultoptionalPortfolioBlockEnvelope

Command-specific result payload

PortfolioBlockEnvelope fields
FieldTypeDescription
idrequiredstring

Portfolio ID (`port_*` ULID).

namerequiredstring

Display name.

descriptionoptionalstring

Free-text description.

strategyoptionalstring

Free-text strategy classification.

inception_dateoptionalstring (date)

Date the portfolio was established.

base_currencyrequiredstring

ISO 4217 currency code for portfolio aggregates.

owneroptionalEntityLite

Embedded owning entity, when set. `null` for unattributed portfolios.

EntityLite fields
FieldTypeDescription
idrequiredstring

Entity ID (`ent_*` ULID).

namerequiredstring

Display name of the entity.

source_graph_idoptionalstring

Tenant graph this entity is anchored to, when known. `null` for entities not yet linked to a graph.

positionsrequiredPositionBlock[]

All positions in this portfolio, including disposed ones (filter by `status` for active-only display).

PositionBlock fields
FieldTypeDescription
idrequiredstring

Position ID (`pos_*` ULID).

quantityrequirednumber

Quantity held in `quantity_type` units.

quantity_typerequiredstring

Unit basis (`shares`, `units`, `principal`).

cost_basis_dollarsrequirednumber

Cost basis in dollars (pre-converted from cents).

current_value_dollarsoptionalnumber

Latest mark-to-market value in dollars. `null` when the position has not been marked.

valuation_dateoptionalstring (date)

Date the current value was sourced.

valuation_sourceoptionalstring

Free-text source attribution for the valuation.

acquisition_dateoptionalstring (date)

Date the position was acquired.

statusrequiredstring

Lifecycle state (`active`, `disposed`, `archived`). See `PositionResponse.status` for the full vocabulary.

notesoptionalstring

Free-text notes attached to the position.

securityrequiredSecurityLite

Embedded security details — name, type, issuer.

total_cost_basis_dollarsrequirednumber

Sum of `cost_basis_dollars` across every position.

total_current_value_dollarsoptionalnumber

Sum of `current_value_dollars` across every position. `null` when any active position lacks a mark.

active_position_countrequiredinteger

Count of positions with `status='active'`.

created_atrequiredstring (date-time)

Row creation timestamp (UTC).

updated_atrequiredstring (date-time)

Last-modified timestamp (UTC).

atrequiredstring

ISO-8601 UTC timestamp

createdByoptionalstring

User ID that initiated the operation (null for legacy callers)

idempotentReplayoptionalboolean

True when this envelope came from the idempotency cache — the underlying command did not execute again. False on fresh executions.

Default: false

StatusMeaning
400Invalid request
401Authentication required
403Access denied
404Resource not found
409Idempotency-Key conflict — key reused with different body
422Validation error
429Rate limit exceeded
500Internal server error