Products

Every operation below is generated from the OpenAPI v2 specification and includes parameters, request fields, response fields, errors, and examples.

Documents, lots and physical stock

stocks.physical / stocks.aggregateArrays of warehouse totals: warehouse_id, warehouse_name, stockTotal, stockReserved, stockAvailable. stocks.available_by_warehouse is an object keyed by warehouse ID; these are not identical shapes.
GET /api/v2/products/{id}/stock-lotsPhysically placed quantities by lot and dates. An unassigned reservation cannot be subtracted from an arbitrary lot. Check quantity units and warehouse in the response.
accepted_lotsActual receipt lots. Expected, accepted and placed quantities are distinct measures; a difference does not itself indicate an API error.
requested_lot / fulfillment_lotsOrder requested_lot expresses a requirement; fulfillment_lots records actual picking and picked_quantity the picked amount. Multiple actual lots cannot be reduced to one date.
movement_type / operationPicking can emit a reservation-release and physical-issue pair. Distinguish operation instead of counting two physical issues. Transfers correlate through movement_group_id; transfer_kind specifies the kind.
GET /api/v2/closed-boxesActual sealed boxes with a unique SSCC: balance=1 and balance_unit=box. A packaging-type barcode from products is not a unique SSCC. Opened, shipped and expected-only boxes are excluded.
acceptance_dateFor standard/return creation (type_id=1/2), the current handler assigns server now() even when acceptance_date is supplied. Updating an existing acceptance accepts the date. Type 3 uses a separate cross-dock service. created_at/updated_at are technical timestamps, not the document date.
LifecycleAcceptance cancellation is a separate cancel command with state checks, not deletion. Prefer /lines; deprecated /offers remain for compatibility. See operation-specific constraints.

Products

GET /api/v2/products

List products

operationIdlistProducts
TagProducts
SecuritybearerAuth

Returns products visible to the authenticated account. Use documented query parameters for filtering, sorting, and pagination.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request GET "${NWMS_BASE_URL}/api/v2/products" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}"

Parameters

Name In Required Type Style Explode Constraints Description Example
page query no integer:int64 form true min: 1 Page number. The same filter may also be sent as filter[page] where supported by the Laravel query adapter. 1
per_page query no integer:int64 form true min: 1
max: 250
Number of records per page. Default is 50; maximum is 250. The same filter may also be sent as filter[per_page] where supported by the Laravel query adapter. 50
sort query no string form false pattern: ^-?[A-Za-z0-9_]+(,-?[A-Za-z0-9_]+)*$ Comma-separated sort fields. Prefix with - for descending order. Allowed fields: id, name, article, sku, price, created_at, updated_at, inventory_updated_at. Default: -id. The same filter may also be sent as filter[sort] where supported by the Laravel query adapter. "-id"
id query no integer:int64 form true min: 1 Filter by id using exact matching. The same filter may also be sent as filter[id] where supported by the Laravel query adapter. 1001
external_id query no string form true Filter by external_id using exact matching. The same filter may also be sent as filter[external_id] where supported by the Laravel query adapter. "EXT-10045"
shop_id query no integer:int64 form true min: 1 Filter by shop_id using exact matching. The same filter may also be sent as filter[shop_id] where supported by the Laravel query adapter. 12
status_id query no ProductStatusId form true Filter by status_id using exact matching. The same filter may also be sent as filter[status_id] where supported by the Laravel query adapter.
type_id query no integer:int64 form true min: 1 Filter by type_id using exact matching. The same filter may also be sent as filter[type_id] where supported by the Laravel query adapter. 1
package_kind query no string form true Filter by package_kind using exact matching. The same filter may also be sent as filter[package_kind] where supported by the Laravel query adapter. "unit"
parent_product_id query no integer:int64 form true min: 1 Filter by parent_product_id using exact matching. The same filter may also be sent as filter[parent_product_id] where supported by the Laravel query adapter. 1200
base_product_id query no integer:int64 form true min: 1 Filter by base_product_id using exact matching. The same filter may also be sent as filter[base_product_id] where supported by the Laravel query adapter. 1200
datamatrix_required query no boolean form true Filter by datamatrix_required using exact matching. The same filter may also be sent as filter[datamatrix_required] where supported by the Laravel query adapter. false
expiration_required query no boolean form true Filter by expiration_required using exact matching. The same filter may also be sent as filter[expiration_required] where supported by the Laravel query adapter. false
name query no string form true Filter by name using partial text matching. The same filter may also be sent as filter[name] where supported by the Laravel query adapter. "Coffee"
article query no string form true Filter by article using partial text matching. The same filter may also be sent as filter[article] where supported by the Laravel query adapter. "ART-001245"
sku query no string form true Filter by sku using partial text matching. The same filter may also be sent as filter[sku] where supported by the Laravel query adapter. "SKU-001245"
comment query no string form true Filter by comment using partial text matching. The same filter may also be sent as filter[comment] where supported by the Laravel query adapter. "Priority"
created_at_from query no string:date form true Lower inclusive date boundary for created_at. The same filter may also be sent as filter[created_at_from] where supported by the Laravel query adapter. "2026-07-14"
created_at_to query no string:date form true Upper inclusive date boundary for created_at. The same filter may also be sent as filter[created_at_to] where supported by the Laravel query adapter. "2026-07-14"
updated_at_from query no string:date form true Lower inclusive date boundary for updated_at. The same filter may also be sent as filter[updated_at_from] where supported by the Laravel query adapter. "2026-07-14"
updated_at_to query no string:date form true Upper inclusive date boundary for updated_at. The same filter may also be sent as filter[updated_at_to] where supported by the Laravel query adapter. "2026-07-14"
inventory_updated_at_from query no string:date form true Lower inclusive date boundary for inventory_updated_at. The same filter may also be sent as filter[inventory_updated_at_from] where supported by the Laravel query adapter. "2026-07-14"
inventory_updated_at_to query no string:date form true Upper inclusive date boundary for inventory_updated_at. The same filter may also be sent as filter[inventory_updated_at_to] where supported by the Laravel query adapter. "2026-07-14"
price_from query no number:float form true Lower inclusive numeric boundary for price. The same filter may also be sent as filter[price_from] where supported by the Laravel query adapter. 19.99
price_to query no number:float form true Upper inclusive numeric boundary for price. The same filter may also be sent as filter[price_to] where supported by the Laravel query adapter. 19.99
estimated_price_from query no number:float form true Lower inclusive numeric boundary for estimated_price. The same filter may also be sent as filter[estimated_price_from] where supported by the Laravel query adapter. 19.99
estimated_price_to query no number:float form true Upper inclusive numeric boundary for estimated_price. The same filter may also be sent as filter[estimated_price_to] where supported by the Laravel query adapter. 19.99

Request body

No request body.

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
data yes array<Product>
data[] no Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data[].id yes integer:int64 readOnly min: 1 1001
data[].created_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].external_id no string | null "EXT-10045"
data[].shop_id no integer:int64 | null min: 1 12
data[].domain_id no integer:int64 | null min: 1 3
data[].status_id no integer:int64 | null 1
data[].type_id no integer:int64 | null 1
data[].name yes string "Coffee 250g"
data[].article no string | null "ART-001245"
data[].sku no string | null "SKU-001245"
data[].price no number:float | null 19.99
data[].estimated_price no number:float | null 21.5
data[].image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data[].dimensions no Dimensions
data[].dimensions.x no number:float | null min: 0 105
data[].dimensions.y no number:float | null min: 0 200
data[].dimensions.z no number:float | null min: 0 32
data[].dimensions.unit yes enum enum: mm "mm"
data[].weight no Weight
data[].weight.value no number:float | null min: 0 250
data[].weight.unit yes enum enum: g "g"
data[].datamatrix_required yes boolean false
data[].expiration_required yes boolean true
data[].comment no string | null "Keep dry"
data[].description no string | null "Ground coffee package"
data[].inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].barcodes no array<ProductBarcode>
data[].barcodes[] no ProductBarcode
data[].barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data[].barcodes[].is_main yes boolean true
data[].stocks no ProductStocks
data[].stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data[].stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data[].stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.physical[].stockTotal yes number:float 24.0
data[].stocks.physical[].stockReserved yes number:float 6.0
data[].stocks.physical[].stockAvailable yes number:float 18.0
data[].stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data[].stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.aggregate[].stockTotal yes number:float 24.0
data[].stocks.aggregate[].stockReserved yes number:float 6.0
data[].stocks.aggregate[].stockAvailable yes number:float 18.0
data[].package no object | null
data[].package.kind no string | null "unit"
data[].package.parent_product_id no integer:int64 | null min: 1 1201
data[].package.base_product_id no integer:int64 | null min: 1 1200
data[].package.multiplicity no number:float | null min: 0 6
links yes PaginationLinks
links.first yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=1"
links.last yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=2"
links.prev yes string:uri | null
links.next yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=2"
meta yes PaginationMeta
meta.api_version yes enum enum: v2 "v2"
meta.current_page yes integer:int32 min: 1 1
meta.from yes integer:int32 | null min: 1 1
meta.last_page yes integer:int32 min: 1 2
meta.path yes string:uri "https://betawms.ffcdek.ru/api/v2/orders"
meta.per_page yes integer:int32 min: 1 50
meta.to yes integer:int32 | null min: 1 50
meta.total yes integer:int32 min: 0 73

Response examples

success

{
  "data": [
    {
      "id": 1201,
      "external_id": "EXT-10045",
      "shop_id": 12,
      "domain_id": 3,
      "status_id": 1,
      "type_id": 1,
      "name": "Coffee 250g",
      "article": "ART-001245",
      "sku": "SKU-001245",
      "price": 19.99,
      "estimated_price": 21.5,
      "image_url": "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg",
      "dimensions": {
        "x": 105,
        "y": 200,
        "z": 32,
        "unit": "mm"
      },
      "weight": {
        "value": 250,
        "unit": "g"
      },
      "datamatrix_required": false,
      "expiration_required": true,
      "comment": "Keep dry",
      "description": "Ground coffee package",
      "inventory_updated_at": "2026-07-14T08:30:00Z",
      "barcodes": [
        {
          "barcode": "4601234567890",
          "is_main": true
        }
      ],
      "stocks": {
        "available_by_warehouse": {
          "42": 18
        },
        "physical": [
          {
            "warehouse_id": 42,
            "warehouse_name": "Warehouse Sofia",
            "stockTotal": 24,
            "stockReserved": 6,
            "stockAvailable": 18
          }
        ],
        "aggregate": [
          {
            "warehouse_id": 42,
            "warehouse_name": "Warehouse Sofia",
            "stockTotal": 30,
            "stockReserved": 7,
            "stockAvailable": 23
          }
        ]
      },
      "package": {
        "kind": "unit",
        "parent_product_id": null,
        "base_product_id": null,
        "multiplicity": null
      },
      "created_at": "2026-07-14T09:00:00Z",
      "updated_at": "2026-07-14T09:30:00Z"
    }
  ],
  "links": {
    "first": "https://betawms.ffcdek.ru/api/v2/products?page=1",
    "last": "https://betawms.ffcdek.ru/api/v2/products?page=2",
    "prev": null,
    "next": "https://betawms.ffcdek.ru/api/v2/products?page=2"
  },
  "meta": {
    "api_version": "v2",
    "current_page": 1,
    "from": 1,
    "last_page": 2,
    "path": "https://betawms.ffcdek.ru/api/v2/products",
    "per_page": 50,
    "to": 50,
    "total": 73
  }
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
POST /api/v2/products

Create product

operationIdcreateProducts
TagProducts
SecuritybearerAuth

Creates one product or imports multiple products. Barcodes, dimensions, weights, marking requirements, expiration requirements, and package metadata are accepted in public v2 field names.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Optional type_id accepts integer codes 1 ordinary, 2 composite, 3 component, 4 consumable, 5 packaging. Omission preserves the existing/default type; explicit null, empty, fractional or unknown values are rejected. Types 2/3 require composites enabled in the shop and permission to manage composition, in addition to product create/update rights. Quant packaging and links, existing composition links and dependent warehouse documents can prevent a type transition. This field does not create or replace a composition. Product and component prices are independent. Each item commits separately: a later rule failure may leave earlier items applied. Read back affected products before retrying a failed bulk request.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request POST "${NWMS_BASE_URL}/api/v2/products" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header "Idempotency-Key: ${NWMS_REQUEST_KEY}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json

Parameters

Name In Required Type Style Explode Constraints Description Example
Idempotency-Key header no string maxLength: 191 Optional idempotency key for API v2 write requests. Successful 2xx/3xx responses are replayed for the same key and identical payload for one day. The same key with a different payload returns 409. "ord-create-20260714-001"

Request body

BulkCreateProductsRequest required

Field Required Type Flags Constraints Description Example
data yes CreateProductPayload
data yes array<CreateProductPayload> minItems: 1

Request examples

default

{
  "data": [
    {
      "external_id": "EXT-10045",
      "shop_id": 12,
      "name": "Coffee 250g",
      "barcodes": [
        {
          "barcode": "4601234567890",
          "is_main": true
        }
      ],
      "type_id": 3
    }
  ]
}

Responses

201 Created.

Created.

Field Required Type Flags Constraints Description Example
(root) no ProductMutationResponse Single-object product writes return ProductResponse; array product writes return ProductCollectionResponse in the same input order for successfully processed items.
data yes Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data.id yes integer:int64 readOnly min: 1 1001
data.created_at no string:date-time | null "2026-07-14T10:30:00Z"
data.updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.external_id no string | null "EXT-10045"
data.shop_id no integer:int64 | null min: 1 12
data.domain_id no integer:int64 | null min: 1 3
data.status_id no integer:int64 | null 1
data.type_id no integer:int64 | null 1
data.name yes string "Coffee 250g"
data.article no string | null "ART-001245"
data.sku no string | null "SKU-001245"
data.price no number:float | null 19.99
data.estimated_price no number:float | null 21.5
data.image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data.dimensions no Dimensions
data.dimensions.x no number:float | null min: 0 105
data.dimensions.y no number:float | null min: 0 200
data.dimensions.z no number:float | null min: 0 32
data.dimensions.unit yes enum enum: mm "mm"
data.weight no Weight
data.weight.value no number:float | null min: 0 250
data.weight.unit yes enum enum: g "g"
data.datamatrix_required yes boolean false
data.expiration_required yes boolean true
data.comment no string | null "Keep dry"
data.description no string | null "Ground coffee package"
data.inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.barcodes no array<ProductBarcode>
data.barcodes[] no ProductBarcode
data.barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data.barcodes[].is_main yes boolean true
data.stocks no ProductStocks
data.stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data.stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data.stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data.stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.physical[].stockTotal yes number:float 24.0
data.stocks.physical[].stockReserved yes number:float 6.0
data.stocks.physical[].stockAvailable yes number:float 18.0
data.stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data.stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data.stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.aggregate[].stockTotal yes number:float 24.0
data.stocks.aggregate[].stockReserved yes number:float 6.0
data.stocks.aggregate[].stockAvailable yes number:float 18.0
data.package no object | null
data.package.kind no string | null "unit"
data.package.parent_product_id no integer:int64 | null min: 1 1201
data.package.base_product_id no integer:int64 | null min: 1 1200
data.package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"
data yes array<Product>
data[] no Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data[].id yes integer:int64 readOnly min: 1 1001
data[].created_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].external_id no string | null "EXT-10045"
data[].shop_id no integer:int64 | null min: 1 12
data[].domain_id no integer:int64 | null min: 1 3
data[].status_id no integer:int64 | null 1
data[].type_id no integer:int64 | null 1
data[].name yes string "Coffee 250g"
data[].article no string | null "ART-001245"
data[].sku no string | null "SKU-001245"
data[].price no number:float | null 19.99
data[].estimated_price no number:float | null 21.5
data[].image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data[].dimensions no Dimensions
data[].dimensions.x no number:float | null min: 0 105
data[].dimensions.y no number:float | null min: 0 200
data[].dimensions.z no number:float | null min: 0 32
data[].dimensions.unit yes enum enum: mm "mm"
data[].weight no Weight
data[].weight.value no number:float | null min: 0 250
data[].weight.unit yes enum enum: g "g"
data[].datamatrix_required yes boolean false
data[].expiration_required yes boolean true
data[].comment no string | null "Keep dry"
data[].description no string | null "Ground coffee package"
data[].inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].barcodes no array<ProductBarcode>
data[].barcodes[] no ProductBarcode
data[].barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data[].barcodes[].is_main yes boolean true
data[].stocks no ProductStocks
data[].stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data[].stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data[].stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.physical[].stockTotal yes number:float 24.0
data[].stocks.physical[].stockReserved yes number:float 6.0
data[].stocks.physical[].stockAvailable yes number:float 18.0
data[].stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data[].stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.aggregate[].stockTotal yes number:float 24.0
data[].stocks.aggregate[].stockReserved yes number:float 6.0
data[].stocks.aggregate[].stockAvailable yes number:float 18.0
data[].package no object | null
data[].package.kind no string | null "unit"
data[].package.parent_product_id no integer:int64 | null min: 1 1201
data[].package.base_product_id no integer:int64 | null min: 1 1200
data[].package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"

Response examples

success

{
  "data": {
    "id": 1201,
    "external_id": "EXT-10045",
    "shop_id": 12,
    "domain_id": 3,
    "status_id": 1,
    "type_id": 1,
    "name": "Coffee 250g",
    "article": "ART-001245",
    "sku": "SKU-001245",
    "price": 19.99,
    "estimated_price": 21.5,
    "image_url": "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg",
    "dimensions": {
      "x": 105,
      "y": 200,
      "z": 32,
      "unit": "mm"
    },
    "weight": {
      "value": 250,
      "unit": "g"
    },
    "datamatrix_required": false,
    "expiration_required": true,
    "comment": "Keep dry",
    "description": "Ground coffee package",
    "inventory_updated_at": "2026-07-14T08:30:00Z",
    "barcodes": [
      {
        "barcode": "4601234567890",
        "is_main": true
      }
    ],
    "stocks": {
      "available_by_warehouse": {
        "42": 18
      },
      "physical": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 24,
          "stockReserved": 6,
          "stockAvailable": 18
        }
      ],
      "aggregate": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 30,
          "stockReserved": 7,
          "stockAvailable": 23
        }
      ]
    },
    "package": {
      "kind": "unit",
      "parent_product_id": null,
      "base_product_id": null,
      "multiplicity": null
    },
    "created_at": "2026-07-14T09:00:00Z",
    "updated_at": "2026-07-14T09:30:00Z"
  },
  "meta": {
    "api_version": "v2"
  }
}

400 Bad request

BadRequest

Bad request.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

BAD_REQUEST

{
  "message": "Bad request.",
  "error": "BAD_REQUEST"
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

409 Conflict

Conflict

The request conflicts with the current resource state or idempotency key state.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

idempotencyConflict

{
  "message": "The idempotency key is already used with a different payload.",
  "error": "IDEMPOTENCY_KEY_CONFLICT"
}

422 Validation error

ValidationError

Validation failed.

Field Required Type Flags Constraints Description Example
message yes string "The given data was invalid."
error no string "VALIDATION_ERROR"
errors yes object {"warehouse_id":["The selected warehouse is invalid."]}

Response examples

validationError

{
  "message": "The given data was invalid.",
  "error": "VALIDATION_ERROR",
  "errors": {
    "warehouse_id": [
      "The selected warehouse is invalid."
    ]
  }
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
PUT /api/v2/products

Update product

operationIdreplaceProducts
TagProducts
SecuritybearerAuth

Bulk updates products identified by id or by external_id plus shop_id. When barcodes are supplied, the barcode set is replaced according to existing product rules.
Current backend behavior is legacy partial-update semantics: omitted fields are left unchanged.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Optional type_id accepts integer codes 1 ordinary, 2 composite, 3 component, 4 consumable, 5 packaging. Omission preserves the existing/default type; explicit null, empty, fractional or unknown values are rejected. Types 2/3 require composites enabled in the shop and permission to manage composition, in addition to product create/update rights. Quant packaging and links, existing composition links and dependent warehouse documents can prevent a type transition. This field does not create or replace a composition. Product and component prices are independent. Each item commits separately: a later rule failure may leave earlier items applied. Read back affected products before retrying a failed bulk request.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request PUT "${NWMS_BASE_URL}/api/v2/products" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header "Idempotency-Key: ${NWMS_REQUEST_KEY}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json

Parameters

Name In Required Type Style Explode Constraints Description Example
Idempotency-Key header no string maxLength: 191 Optional idempotency key for API v2 write requests. Successful 2xx/3xx responses are replayed for the same key and identical payload for one day. The same key with a different payload returns 409. "ord-create-20260714-001"

Request body

BulkReplaceProductsRequest required

Field Required Type Flags Constraints Description Example
data yes ReplaceProductPayload
data yes array<ReplaceProductPayload> minItems: 1

Request examples

default

{
  "data": [
    {
      "id": 1201,
      "name": "Coffee 250g",
      "price": 19.99,
      "type_id": 3
    }
  ]
}

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
(root) no ProductMutationResponse Single-object product writes return ProductResponse; array product writes return ProductCollectionResponse in the same input order for successfully processed items.
data yes Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data.id yes integer:int64 readOnly min: 1 1001
data.created_at no string:date-time | null "2026-07-14T10:30:00Z"
data.updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.external_id no string | null "EXT-10045"
data.shop_id no integer:int64 | null min: 1 12
data.domain_id no integer:int64 | null min: 1 3
data.status_id no integer:int64 | null 1
data.type_id no integer:int64 | null 1
data.name yes string "Coffee 250g"
data.article no string | null "ART-001245"
data.sku no string | null "SKU-001245"
data.price no number:float | null 19.99
data.estimated_price no number:float | null 21.5
data.image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data.dimensions no Dimensions
data.dimensions.x no number:float | null min: 0 105
data.dimensions.y no number:float | null min: 0 200
data.dimensions.z no number:float | null min: 0 32
data.dimensions.unit yes enum enum: mm "mm"
data.weight no Weight
data.weight.value no number:float | null min: 0 250
data.weight.unit yes enum enum: g "g"
data.datamatrix_required yes boolean false
data.expiration_required yes boolean true
data.comment no string | null "Keep dry"
data.description no string | null "Ground coffee package"
data.inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.barcodes no array<ProductBarcode>
data.barcodes[] no ProductBarcode
data.barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data.barcodes[].is_main yes boolean true
data.stocks no ProductStocks
data.stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data.stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data.stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data.stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.physical[].stockTotal yes number:float 24.0
data.stocks.physical[].stockReserved yes number:float 6.0
data.stocks.physical[].stockAvailable yes number:float 18.0
data.stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data.stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data.stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.aggregate[].stockTotal yes number:float 24.0
data.stocks.aggregate[].stockReserved yes number:float 6.0
data.stocks.aggregate[].stockAvailable yes number:float 18.0
data.package no object | null
data.package.kind no string | null "unit"
data.package.parent_product_id no integer:int64 | null min: 1 1201
data.package.base_product_id no integer:int64 | null min: 1 1200
data.package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"
data yes array<Product>
data[] no Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data[].id yes integer:int64 readOnly min: 1 1001
data[].created_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].external_id no string | null "EXT-10045"
data[].shop_id no integer:int64 | null min: 1 12
data[].domain_id no integer:int64 | null min: 1 3
data[].status_id no integer:int64 | null 1
data[].type_id no integer:int64 | null 1
data[].name yes string "Coffee 250g"
data[].article no string | null "ART-001245"
data[].sku no string | null "SKU-001245"
data[].price no number:float | null 19.99
data[].estimated_price no number:float | null 21.5
data[].image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data[].dimensions no Dimensions
data[].dimensions.x no number:float | null min: 0 105
data[].dimensions.y no number:float | null min: 0 200
data[].dimensions.z no number:float | null min: 0 32
data[].dimensions.unit yes enum enum: mm "mm"
data[].weight no Weight
data[].weight.value no number:float | null min: 0 250
data[].weight.unit yes enum enum: g "g"
data[].datamatrix_required yes boolean false
data[].expiration_required yes boolean true
data[].comment no string | null "Keep dry"
data[].description no string | null "Ground coffee package"
data[].inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].barcodes no array<ProductBarcode>
data[].barcodes[] no ProductBarcode
data[].barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data[].barcodes[].is_main yes boolean true
data[].stocks no ProductStocks
data[].stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data[].stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data[].stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.physical[].stockTotal yes number:float 24.0
data[].stocks.physical[].stockReserved yes number:float 6.0
data[].stocks.physical[].stockAvailable yes number:float 18.0
data[].stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data[].stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.aggregate[].stockTotal yes number:float 24.0
data[].stocks.aggregate[].stockReserved yes number:float 6.0
data[].stocks.aggregate[].stockAvailable yes number:float 18.0
data[].package no object | null
data[].package.kind no string | null "unit"
data[].package.parent_product_id no integer:int64 | null min: 1 1201
data[].package.base_product_id no integer:int64 | null min: 1 1200
data[].package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"

Response examples

success

{
  "data": {
    "id": 1201,
    "external_id": "EXT-10045",
    "shop_id": 12,
    "domain_id": 3,
    "status_id": 1,
    "type_id": 1,
    "name": "Coffee 250g",
    "article": "ART-001245",
    "sku": "SKU-001245",
    "price": 19.99,
    "estimated_price": 21.5,
    "image_url": "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg",
    "dimensions": {
      "x": 105,
      "y": 200,
      "z": 32,
      "unit": "mm"
    },
    "weight": {
      "value": 250,
      "unit": "g"
    },
    "datamatrix_required": false,
    "expiration_required": true,
    "comment": "Keep dry",
    "description": "Ground coffee package",
    "inventory_updated_at": "2026-07-14T08:30:00Z",
    "barcodes": [
      {
        "barcode": "4601234567890",
        "is_main": true
      }
    ],
    "stocks": {
      "available_by_warehouse": {
        "42": 18
      },
      "physical": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 24,
          "stockReserved": 6,
          "stockAvailable": 18
        }
      ],
      "aggregate": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 30,
          "stockReserved": 7,
          "stockAvailable": 23
        }
      ]
    },
    "package": {
      "kind": "unit",
      "parent_product_id": null,
      "base_product_id": null,
      "multiplicity": null
    },
    "created_at": "2026-07-14T09:00:00Z",
    "updated_at": "2026-07-14T09:30:00Z"
  },
  "meta": {
    "api_version": "v2"
  }
}

400 Bad request

BadRequest

Bad request.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

BAD_REQUEST

{
  "message": "Bad request.",
  "error": "BAD_REQUEST"
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

409 Conflict

Conflict

The request conflicts with the current resource state or idempotency key state.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

idempotencyConflict

{
  "message": "The idempotency key is already used with a different payload.",
  "error": "IDEMPOTENCY_KEY_CONFLICT"
}

422 Validation error

ValidationError

Validation failed.

Field Required Type Flags Constraints Description Example
message yes string "The given data was invalid."
error no string "VALIDATION_ERROR"
errors yes object {"warehouse_id":["The selected warehouse is invalid."]}

Response examples

validationError

{
  "message": "The given data was invalid.",
  "error": "VALIDATION_ERROR",
  "errors": {
    "warehouse_id": [
      "The selected warehouse is invalid."
    ]
  }
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
PATCH /api/v2/products

Update product

operationIdpatchProducts
TagProducts
SecuritybearerAuth

Partially bulk updates products. Only supplied product fields are changed.
Current backend behavior is legacy partial-update semantics: omitted fields are left unchanged.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
For unplaced consumable usage, stockTotal does not include a permanent physical write-off and must not be used as available packaging inventory. Addressed consumable write-offs remain the existing warehouse process.
Optional type_id accepts integer codes 1 ordinary, 2 composite, 3 component, 4 consumable, 5 packaging. Omission preserves the existing/default type; explicit null, empty, fractional or unknown values are rejected. Types 2/3 require composites enabled in the shop and permission to manage composition, in addition to product create/update rights. Quant packaging and links, existing composition links and dependent warehouse documents can prevent a type transition. This field does not create or replace a composition. Product and component prices are independent. Each item commits separately: a later rule failure may leave earlier items applied. Read back affected products before retrying a failed bulk request.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request PATCH "${NWMS_BASE_URL}/api/v2/products" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header "Idempotency-Key: ${NWMS_REQUEST_KEY}" \
  --header "Content-Type: application/json" \
  --data-binary @request.json

Parameters

Name In Required Type Style Explode Constraints Description Example
Idempotency-Key header no string maxLength: 191 Optional idempotency key for API v2 write requests. Successful 2xx/3xx responses are replayed for the same key and identical payload for one day. The same key with a different payload returns 409. "ord-create-20260714-001"

Request body

BulkPatchProductsRequest required

Field Required Type Flags Constraints Description Example
data yes PatchProductPayload
data yes array<PatchProductPayload> minItems: 1

Request examples

default

{
  "data": [
    {
      "external_id": "EXT-10045",
      "shop_id": 12,
      "price": 18.99,
      "type_id": 3
    }
  ]
}

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
(root) no ProductMutationResponse Single-object product writes return ProductResponse; array product writes return ProductCollectionResponse in the same input order for successfully processed items.
data yes Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data.id yes integer:int64 readOnly min: 1 1001
data.created_at no string:date-time | null "2026-07-14T10:30:00Z"
data.updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.external_id no string | null "EXT-10045"
data.shop_id no integer:int64 | null min: 1 12
data.domain_id no integer:int64 | null min: 1 3
data.status_id no integer:int64 | null 1
data.type_id no integer:int64 | null 1
data.name yes string "Coffee 250g"
data.article no string | null "ART-001245"
data.sku no string | null "SKU-001245"
data.price no number:float | null 19.99
data.estimated_price no number:float | null 21.5
data.image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data.dimensions no Dimensions
data.dimensions.x no number:float | null min: 0 105
data.dimensions.y no number:float | null min: 0 200
data.dimensions.z no number:float | null min: 0 32
data.dimensions.unit yes enum enum: mm "mm"
data.weight no Weight
data.weight.value no number:float | null min: 0 250
data.weight.unit yes enum enum: g "g"
data.datamatrix_required yes boolean false
data.expiration_required yes boolean true
data.comment no string | null "Keep dry"
data.description no string | null "Ground coffee package"
data.inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.barcodes no array<ProductBarcode>
data.barcodes[] no ProductBarcode
data.barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data.barcodes[].is_main yes boolean true
data.stocks no ProductStocks
data.stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data.stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data.stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data.stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.physical[].stockTotal yes number:float 24.0
data.stocks.physical[].stockReserved yes number:float 6.0
data.stocks.physical[].stockAvailable yes number:float 18.0
data.stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data.stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data.stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.aggregate[].stockTotal yes number:float 24.0
data.stocks.aggregate[].stockReserved yes number:float 6.0
data.stocks.aggregate[].stockAvailable yes number:float 18.0
data.package no object | null
data.package.kind no string | null "unit"
data.package.parent_product_id no integer:int64 | null min: 1 1201
data.package.base_product_id no integer:int64 | null min: 1 1200
data.package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"
data yes array<Product>
data[] no Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data[].id yes integer:int64 readOnly min: 1 1001
data[].created_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].external_id no string | null "EXT-10045"
data[].shop_id no integer:int64 | null min: 1 12
data[].domain_id no integer:int64 | null min: 1 3
data[].status_id no integer:int64 | null 1
data[].type_id no integer:int64 | null 1
data[].name yes string "Coffee 250g"
data[].article no string | null "ART-001245"
data[].sku no string | null "SKU-001245"
data[].price no number:float | null 19.99
data[].estimated_price no number:float | null 21.5
data[].image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data[].dimensions no Dimensions
data[].dimensions.x no number:float | null min: 0 105
data[].dimensions.y no number:float | null min: 0 200
data[].dimensions.z no number:float | null min: 0 32
data[].dimensions.unit yes enum enum: mm "mm"
data[].weight no Weight
data[].weight.value no number:float | null min: 0 250
data[].weight.unit yes enum enum: g "g"
data[].datamatrix_required yes boolean false
data[].expiration_required yes boolean true
data[].comment no string | null "Keep dry"
data[].description no string | null "Ground coffee package"
data[].inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data[].barcodes no array<ProductBarcode>
data[].barcodes[] no ProductBarcode
data[].barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data[].barcodes[].is_main yes boolean true
data[].stocks no ProductStocks
data[].stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data[].stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data[].stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.physical[].stockTotal yes number:float 24.0
data[].stocks.physical[].stockReserved yes number:float 6.0
data[].stocks.physical[].stockAvailable yes number:float 18.0
data[].stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data[].stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data[].stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data[].stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data[].stocks.aggregate[].stockTotal yes number:float 24.0
data[].stocks.aggregate[].stockReserved yes number:float 6.0
data[].stocks.aggregate[].stockAvailable yes number:float 18.0
data[].package no object | null
data[].package.kind no string | null "unit"
data[].package.parent_product_id no integer:int64 | null min: 1 1201
data[].package.base_product_id no integer:int64 | null min: 1 1200
data[].package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"

Response examples

success

{
  "data": {
    "id": 1201,
    "external_id": "EXT-10045",
    "shop_id": 12,
    "domain_id": 3,
    "status_id": 1,
    "type_id": 1,
    "name": "Coffee 250g",
    "article": "ART-001245",
    "sku": "SKU-001245",
    "price": 19.99,
    "estimated_price": 21.5,
    "image_url": "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg",
    "dimensions": {
      "x": 105,
      "y": 200,
      "z": 32,
      "unit": "mm"
    },
    "weight": {
      "value": 250,
      "unit": "g"
    },
    "datamatrix_required": false,
    "expiration_required": true,
    "comment": "Keep dry",
    "description": "Ground coffee package",
    "inventory_updated_at": "2026-07-14T08:30:00Z",
    "barcodes": [
      {
        "barcode": "4601234567890",
        "is_main": true
      }
    ],
    "stocks": {
      "available_by_warehouse": {
        "42": 18
      },
      "physical": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 24,
          "stockReserved": 6,
          "stockAvailable": 18
        }
      ],
      "aggregate": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 30,
          "stockReserved": 7,
          "stockAvailable": 23
        }
      ]
    },
    "package": {
      "kind": "unit",
      "parent_product_id": null,
      "base_product_id": null,
      "multiplicity": null
    },
    "created_at": "2026-07-14T09:00:00Z",
    "updated_at": "2026-07-14T09:30:00Z"
  },
  "meta": {
    "api_version": "v2"
  }
}

400 Bad request

BadRequest

Bad request.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

BAD_REQUEST

{
  "message": "Bad request.",
  "error": "BAD_REQUEST"
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

409 Conflict

Conflict

The request conflicts with the current resource state or idempotency key state.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

idempotencyConflict

{
  "message": "The idempotency key is already used with a different payload.",
  "error": "IDEMPOTENCY_KEY_CONFLICT"
}

422 Validation error

ValidationError

Validation failed.

Field Required Type Flags Constraints Description Example
message yes string "The given data was invalid."
error no string "VALIDATION_ERROR"
errors yes object {"warehouse_id":["The selected warehouse is invalid."]}

Response examples

validationError

{
  "message": "The given data was invalid.",
  "error": "VALIDATION_ERROR",
  "errors": {
    "warehouse_id": [
      "The selected warehouse is invalid."
    ]
  }
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
GET /api/v2/products/{id}

Get product

operationIdgetProducts
TagProducts
SecuritybearerAuth

Returns one product when it exists and is visible to the authenticated account.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request GET "${NWMS_BASE_URL}/api/v2/products/1001" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}"

Parameters

Name In Required Type Style Explode Constraints Description Example
id path yes integer:int64 min: 1 Product ID. 1001

Request body

No request body.

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
data yes Product Product catalog item exposed by API v2. Product barcodes identify a product or package type and are not unique SSCC values. Use /api/v2/closed-boxes to read individual sealed boxes and their current box balance.
data.id yes integer:int64 readOnly min: 1 1001
data.created_at no string:date-time | null "2026-07-14T10:30:00Z"
data.updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.external_id no string | null "EXT-10045"
data.shop_id no integer:int64 | null min: 1 12
data.domain_id no integer:int64 | null min: 1 3
data.status_id no integer:int64 | null 1
data.type_id no integer:int64 | null 1
data.name yes string "Coffee 250g"
data.article no string | null "ART-001245"
data.sku no string | null "SKU-001245"
data.price no number:float | null 19.99
data.estimated_price no number:float | null 21.5
data.image_url no string:uri | null "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg"
data.dimensions no Dimensions
data.dimensions.x no number:float | null min: 0 105
data.dimensions.y no number:float | null min: 0 200
data.dimensions.z no number:float | null min: 0 32
data.dimensions.unit yes enum enum: mm "mm"
data.weight no Weight
data.weight.value no number:float | null min: 0 250
data.weight.unit yes enum enum: g "g"
data.datamatrix_required yes boolean false
data.expiration_required yes boolean true
data.comment no string | null "Keep dry"
data.description no string | null "Ground coffee package"
data.inventory_updated_at no string:date-time | null "2026-07-14T10:30:00Z"
data.barcodes no array<ProductBarcode>
data.barcodes[] no ProductBarcode
data.barcodes[].barcode yes string minLength: 1
maxLength: 64
"4601234567890"
data.barcodes[].is_main yes boolean true
data.stocks no ProductStocks
data.stocks.available_by_warehouse no object Map keyed by warehouse ID. Values are quantities. {"42":18.0,"43":3.0}
data.stocks.physical no array<ProductStockSummary> Physical stock rows for the product itself.
data.stocks.physical[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.physical[].warehouse_id yes integer:int64 min: 1 42
data.stocks.physical[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.physical[].stockTotal yes number:float 24.0
data.stocks.physical[].stockReserved yes number:float 6.0
data.stocks.physical[].stockAvailable yes number:float 18.0
data.stocks.aggregate no array<ProductStockSummary> Aggregated base-unit stock rows for the product and its descendant quants.
data.stocks.aggregate[] no ProductStockSummary Stock totals for one warehouse. Quantities may be negative when reservations exceed physical stock.
data.stocks.aggregate[].warehouse_id yes integer:int64 min: 1 42
data.stocks.aggregate[].warehouse_name yes string | null "Warehouse Sofia"
data.stocks.aggregate[].stockTotal yes number:float 24.0
data.stocks.aggregate[].stockReserved yes number:float 6.0
data.stocks.aggregate[].stockAvailable yes number:float 18.0
data.package no object | null
data.package.kind no string | null "unit"
data.package.parent_product_id no integer:int64 | null min: 1 1201
data.package.base_product_id no integer:int64 | null min: 1 1200
data.package.multiplicity no number:float | null min: 0 6
meta yes ResponseMeta
meta.api_version yes enum enum: v2 "v2"
meta.deleted no boolean true
meta.id no integer:int64 | null min: 1 1001
meta.command_replayed no boolean True when an idempotent cross-dock command returned the original successful result. false
meta.crossdock_configuration no object | null
meta.crossdock_configuration.physical_warehouse_id yes integer:int64 min: 1 42
meta.crossdock_configuration.enabled yes boolean true
meta.crossdock_configuration.process_version yes string "direct_order_v1"

Response examples

success

{
  "data": {
    "id": 1201,
    "external_id": "EXT-10045",
    "shop_id": 12,
    "domain_id": 3,
    "status_id": 1,
    "type_id": 1,
    "name": "Coffee 250g",
    "article": "ART-001245",
    "sku": "SKU-001245",
    "price": 19.99,
    "estimated_price": 21.5,
    "image_url": "https://betawms.ffcdek.ru/offer-images/products/coffee-250g.jpg",
    "dimensions": {
      "x": 105,
      "y": 200,
      "z": 32,
      "unit": "mm"
    },
    "weight": {
      "value": 250,
      "unit": "g"
    },
    "datamatrix_required": false,
    "expiration_required": true,
    "comment": "Keep dry",
    "description": "Ground coffee package",
    "inventory_updated_at": "2026-07-14T08:30:00Z",
    "barcodes": [
      {
        "barcode": "4601234567890",
        "is_main": true
      }
    ],
    "stocks": {
      "available_by_warehouse": {
        "42": 18
      },
      "physical": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 24,
          "stockReserved": 6,
          "stockAvailable": 18
        }
      ],
      "aggregate": [
        {
          "warehouse_id": 42,
          "warehouse_name": "Warehouse Sofia",
          "stockTotal": 30,
          "stockReserved": 7,
          "stockAvailable": 23
        }
      ]
    },
    "package": {
      "kind": "unit",
      "parent_product_id": null,
      "base_product_id": null,
      "multiplicity": null
    },
    "created_at": "2026-07-14T09:00:00Z",
    "updated_at": "2026-07-14T09:30:00Z"
  },
  "meta": {
    "api_version": "v2"
  }
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

404 Not found

NotFound

The requested resource was not found or is outside the authenticated account scope.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

NOT_FOUND

{
  "message": "The requested resource was not found or is outside the authenticated account scope.",
  "error": "NOT_FOUND"
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
DELETE /api/v2/products/{id}

Delete product

operationIddeleteProducts
TagProducts
SecuritybearerAuth

Deletes the resource when the authenticated account has permission and the current lifecycle state allows deletion. If deletion is blocked by related records or document state, the API returns a validation error.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request DELETE "${NWMS_BASE_URL}/api/v2/products/1001" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}" \
  --header "Idempotency-Key: ${NWMS_REQUEST_KEY}"

Parameters

Name In Required Type Style Explode Constraints Description Example
id path yes integer:int64 min: 1 Product ID. 1001
Idempotency-Key header no string maxLength: 191 Optional idempotency key for API v2 write requests. Successful 2xx/3xx responses are replayed for the same key and identical payload for one day. The same key with a different payload returns 409. "ord-create-20260714-001"

Request body

No request body.

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
data yes object | null
meta yes object
meta.api_version yes enum enum: v2 "v2"
meta.deleted yes boolean true
meta.id yes integer:int64 min: 1 1001

Response examples

success

{
  "data": null,
  "meta": {
    "api_version": "v2",
    "deleted": true,
    "id": 1001
  }
}

400 Bad request

BadRequest

Bad request.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

BAD_REQUEST

{
  "message": "Bad request.",
  "error": "BAD_REQUEST"
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

404 Not found

NotFound

The requested resource was not found or is outside the authenticated account scope.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

NOT_FOUND

{
  "message": "The requested resource was not found or is outside the authenticated account scope.",
  "error": "NOT_FOUND"
}

409 Conflict

Conflict

The request conflicts with the current resource state or idempotency key state.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

idempotencyConflict

{
  "message": "The idempotency key is already used with a different payload.",
  "error": "IDEMPOTENCY_KEY_CONFLICT"
}

422 Validation error

ValidationError

Validation failed.

Field Required Type Flags Constraints Description Example
message yes string "The given data was invalid."
error no string "VALIDATION_ERROR"
errors yes object {"warehouse_id":["The selected warehouse is invalid."]}

Response examples

validationError

{
  "message": "The given data was invalid.",
  "error": "VALIDATION_ERROR",
  "errors": {
    "warehouse_id": [
      "The selected warehouse is invalid."
    ]
  }
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}
GET /api/v2/products/{id}/stock-lots

List physical stock lots

operationIdgetProductStockLots
TagProducts
SecuritybearerAuth

Read physical placed stock per warehouse, place and lot in this product's units. Unplaced reservations are excluded because they have no actual lot yet. Aggregate physical_quantity by warehouse and lot for reconciliation. Results use current product visibility and container rules, standard pagination (maximum 500) and no snapshot isolation.
Unknown read parameters are ignored. per_page is silently capped; use meta.per_page. Date-only boundaries follow the installation's stored calendar dates; ISO timestamps are serialized in UTC. The default general API limit is 600/minute; a user-specific override may apply. Its bucket is shared by authenticated user, not by shop/domain; Retry-After is returned on throttling.

HTTP request example (cURL)

Set your server and token. Replace sample IDs with accessible IDs. For requests with a body, save the applicable JSON example below as request.json and replace sample values before sending. Idempotency-Key identifies one logical operation.

curl --globoff --request GET "${NWMS_BASE_URL}/api/v2/products/1001/stock-lots" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer ${NWMS_TOKEN}"

Parameters

Name In Required Type Style Explode Constraints Description Example
id path yes integer:int64 min: 1 Product ID. 1001
page query no integer:int64 form true min: 1 Page number. The same filter may also be sent as filter[page] where supported by the Laravel query adapter. 1
per_page query no integer:int64 form true min: 1
max: 500
Number of records per page. Default is 100; maximum is 500. The same filter may also be sent as filter[per_page] where supported by the Laravel query adapter. 100
sort query no string form false pattern: ^-?[A-Za-z0-9_]+(,-?[A-Za-z0-9_]+)*$ Comma-separated sort fields. Prefix with - for descending order. Allowed fields: id, warehouse_id, expiration_date. Default: id. The same filter may also be sent as filter[sort] where supported by the Laravel query adapter. "id"
warehouse_id query no integer:int64 form true min: 1 Filter by warehouse_id using exact matching. The same filter may also be sent as filter[warehouse_id] where supported by the Laravel query adapter. 42
batch query no string form true Filter by batch using partial text matching. The same filter may also be sent as filter[batch] where supported by the Laravel query adapter. "LOT-2026"
production_date_from query no string:date form true Lower inclusive date boundary for production_date. The same filter may also be sent as filter[production_date_from] where supported by the Laravel query adapter. "2026-07-14"
production_date_to query no string:date form true Upper inclusive date boundary for production_date. The same filter may also be sent as filter[production_date_to] where supported by the Laravel query adapter. "2026-07-14"
expiration_date_from query no string:date form true Lower inclusive date boundary for expiration_date. The same filter may also be sent as filter[expiration_date_from] where supported by the Laravel query adapter. "2026-07-14"
expiration_date_to query no string:date form true Upper inclusive date boundary for expiration_date. The same filter may also be sent as filter[expiration_date_to] where supported by the Laravel query adapter. "2026-07-14"

Request body

No request body.

Responses

200 Successful response.

Successful response.

Field Required Type Flags Constraints Description Example
data yes array<StockLot>
data[] no StockLot One active positive placed stock slice in product units, using the same container visibility rules as product stock. Does not allocate unplaced reservations to lots. Not a snapshot cursor or append-only feed.
data[].batch yes string | null "LOT-2026"
data[].production_date yes string:date | null "2026-01-15"
data[].expiration_date yes string:date | null "2027-01-15"
data[].id yes integer:int64 min: 1 5001
data[].product_id yes integer:int64 min: 1 1201
data[].warehouse_id yes integer:int64 min: 1 734
data[].place_id yes integer:int64 min: 1 501
data[].physical_quantity yes number:float min: 0 12
links yes PaginationLinks
links.first yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=1"
links.last yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=2"
links.prev yes string:uri | null
links.next yes string:uri | null "https://betawms.ffcdek.ru/api/v2/orders?page=2"
meta yes PaginationMeta
meta.api_version yes enum enum: v2 "v2"
meta.current_page yes integer:int32 min: 1 1
meta.from yes integer:int32 | null min: 1 1
meta.last_page yes integer:int32 min: 1 2
meta.path yes string:uri "https://betawms.ffcdek.ru/api/v2/orders"
meta.per_page yes integer:int32 min: 1 50
meta.to yes integer:int32 | null min: 1 50
meta.total yes integer:int32 min: 0 73

Response examples

success

{
  "data": [
    {
      "batch": "LOT-2026",
      "production_date": "2026-01-15",
      "expiration_date": "2027-01-15",
      "id": 5001,
      "product_id": 1201,
      "warehouse_id": 734,
      "place_id": 501,
      "physical_quantity": 12
    }
  ],
  "links": {
    "first": "https://betawms.ffcdek.ru/api/v2/products/5101/stock-lots?page=1",
    "last": "https://betawms.ffcdek.ru/api/v2/products/5101/stock-lots?page=2",
    "prev": null,
    "next": "https://betawms.ffcdek.ru/api/v2/products/5101/stock-lots?page=2"
  },
  "meta": {
    "api_version": "v2",
    "current_page": 1,
    "from": 1,
    "last_page": 2,
    "path": "https://betawms.ffcdek.ru/api/v2/products/5101/stock-lots",
    "per_page": 100,
    "to": 100,
    "total": 123
  }
}

401 Authentication required

Unauthorized

Authentication is required.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

AUTH_REQUIRED

{
  "message": "Authentication is required.",
  "error": "AUTH_REQUIRED"
}

403 Forbidden

Forbidden

The authenticated account is not allowed to perform this action.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

FORBIDDEN

{
  "message": "The authenticated account is not allowed to perform this action.",
  "error": "FORBIDDEN"
}

404 Not found

NotFound

The requested resource was not found or is outside the authenticated account scope.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

NOT_FOUND

{
  "message": "The requested resource was not found or is outside the authenticated account scope.",
  "error": "NOT_FOUND"
}

429 Rate limit exceeded

TooManyRequests

Rate limit exceeded.

Field Required Type Flags Constraints Description Example
message yes string "Too Many Attempts."
error yes string "RATE_LIMITED"

500 Internal server error

InternalServerError

An unexpected server error occurred.

Field Required Type Flags Constraints Description Example
message yes string "The request could not be processed."
error yes string "BAD_REQUEST"

Response examples

INTERNAL_SERVER_ERROR

{
  "message": "An unexpected server error occurred.",
  "error": "INTERNAL_SERVER_ERROR"
}