---
title: "Bulk-upsert item <b>base</b> prices from the base price sheet — every item's own company-agnostic
price, across the whole catalogue. Each row's `itemCode` selects the item and every row is
written as `relation=Item, relationId=0`; the price type comes from `type`. Returns the
count upserted.
            
<br><b>Tenant-primary only</b>, and that is the substantive difference from the other two bulk
imports rather than an incidental one. A base price is what every company without an override of its
own resolves to, so writing them across the catalogue is a tenant-level act, not an ownership-scoped
one — there is no R2 ownership branch on this endpoint because the primary gate subsumes it. Checked
here, before M:IO.Admin.BulkExportOptionsExtensions.RouteImport(IO.Admin.BulkExportOptions,System.Int32), so the inline and queued paths are
covered by one statement; re-checked in the handler and in the worker's validation, the same
belt-and-braces the `PRICELISTS` feature gate gets.<br>Deliberately stricter than `POST /v1/Items/{itemId}/prices/bulk`, where a non-primary owner
may still write their own item's base row via an empty `companyCode`. One item at a time is an
ownership act; the whole catalogue is not.<br>The third sheet, and the only one that pins neither axis by route — which is why the queued
job needs an explicit IO.Domain.Shared.Enums.PriceSheetScope rather than inferring the sheet from whichever
id the config carries.<br><b>Import only.</b> There is deliberately no matching export: the other two sheets are a round
trip and their export doubles as the template, whereas this one ships a static template. Note base
prices are already readable per item — `GET /v1/Items/{itemId}/prices` returns the base row
whenever `relationId` is omitted, and the item sheet exports it with an empty
`companyCode` — so what is missing is only the catalogue-wide axis this endpoint writes on."
method: POST
path: "/v1/Items/prices/base/bulk"
tags: ["ItemPrices"]
---

# Bulk-upsert item <b>base</b> prices from the base price sheet — every item's own company-agnostic
price, across the whole catalogue. Each row's `itemCode` selects the item and every row is
written as `relation=Item, relationId=0`; the price type comes from `type`. Returns the
count upserted.
            
<br><b>Tenant-primary only</b>, and that is the substantive difference from the other two bulk
imports rather than an incidental one. A base price is what every company without an override of its
own resolves to, so writing them across the catalogue is a tenant-level act, not an ownership-scoped
one — there is no R2 ownership branch on this endpoint because the primary gate subsumes it. Checked
here, before M:IO.Admin.BulkExportOptionsExtensions.RouteImport(IO.Admin.BulkExportOptions,System.Int32), so the inline and queued paths are
covered by one statement; re-checked in the handler and in the worker's validation, the same
belt-and-braces the `PRICELISTS` feature gate gets.<br>Deliberately stricter than `POST /v1/Items/{itemId}/prices/bulk`, where a non-primary owner
may still write their own item's base row via an empty `companyCode`. One item at a time is an
ownership act; the whole catalogue is not.<br>The third sheet, and the only one that pins neither axis by route — which is why the queued
job needs an explicit IO.Domain.Shared.Enums.PriceSheetScope rather than inferring the sheet from whichever
id the config carries.<br><b>Import only.</b> There is deliberately no matching export: the other two sheets are a round
trip and their export doubles as the template, whereas this one ships a static template. Note base
prices are already readable per item — `GET /v1/Items/{itemId}/prices` returns the base row
whenever `relationId` is omitted, and the item sheet exports it with an empty
`companyCode` — so what is missing is only the catalogue-wide axis this endpoint writes on.

`POST /v1/Items/prices/base/bulk`

## Query parameters

- `type` 0 | 1, required
- `Account` unknown

## Response `200`

Success

- integer

## Other responses

- `202` — Accepted
- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `404` — Not Found
- `409` — Conflict

## Changes

- **2026-08-27** `61263b2302a0` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/invendor/apis/io-commonapi/changes/v1/Items/prices/base/bulk/post.md)

---

[API](https://skmtc.dev/invendor/apis/io-commonapi.md) · [All operations](https://skmtc.dev/invendor/apis/io-commonapi/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/invendor/io-commonapi/revisions/61263b2302a0/schema)
