---
title: "Api Portfolio Import Csv Commit"
method: POST
path: "/api/portfolio/import-csv/commit"
tags: ["Portfolio"]
---

# Api Portfolio Import Csv Commit

`POST /api/portfolio/import-csv/commit`

## Request

- Base URL: `https://www.oxfordledge.com` (the document declares no server; this is the origin it was published from)
- URL: `https://www.oxfordledge.com/api/portfolio/import-csv/commit`
- Auth: none declared

Commit a parsed M1 CSV preview to the user's default portfolio.

Phase 2 of the two-phase import flow (M1-1, 2026-05-27). Accepts
the user-confirmed positions list (possibly a subset of what the
preview returned — the M1-2 UI may strip rows before commit) and
bulk-upserts via the existing `upsert_portfolio_position` helper.

Defensive re-validation at the boundary: the request payload is
user-controlled, so we don't trust that it came verbatim from
`/api/portfolio/import-csv`. Every position re-runs through
`positions_payload_to_commit`'s safety checks (ticker shape,
range bounds) before any DB write.

Returns updated portfolio positions so the FE can re-render
without a follow-up GET.

## Response `200`

Successful Response

- PortfolioImportCSVCommitResponse: `POST /api/portfolio/import-csv/commit` — commit response. Returned after the user confirms the parsed-preview positions and the route bulk-upserts them via `upsert_portfolio_position`. Reports counts (imported, skipped) + the updated portfolio positions so the FE can re-render without a follow-up GET.
  - `status` string, required: 'ok' on successful commit. FE treats absence as failure.
  - `imported` integer, required: Number of positions successfully written to portfolio_positions.
  - `skipped` integer, required: Number of positions in the request that were rejected by the commit-time defensive checks.
  - `positions` PortfolioPosition[], required: The portfolio's positions AFTER the import — drives the FE re-render.
    - `ticker` string, nullable
    - `shares` number, nullable
    - `costBasis` number, nullable
    - `currentPrice` number, nullable
    - `marketValue` number, nullable
    - `pnl` number, nullable
    - `pnlPct` number, nullable
  - `error` string, nullable: Set only on partial failure; the import is still atomic but this surfaces operational issues to the user.

---

[API](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api.md) · [All operations](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/llms.txt) · [OpenAPI document](https://skmtc.dev/oxfordledge/apis/oxford-ledge-api/revisions/e832a1260f0b?raw)
