publ betaReference (MCP guide)
Open publ console

commerce_product_control_apply

# commerce_product_control_apply

Change sale status, visibility or tracked inventory for existing X00004 selections. Read the [shop product guide](../guides/commerce-products.md) for the required COMMERCE_V2 configuration, exact installed-store/channel scope, current delegate policy and recovery. These prerequisites apply to reads as well as writes.

First call [commerce_products_get](commerce_products_get.md) with view.kind selection. Supply channelCode, the same 1–100 distinct ids, its expectedRevision, requestId and optional dryRun (default false). Product actions require a product selection; variant-sale and stock require a variant selection. Do not use a list-page revision or product settings revision.

| action | Additional input |
| --- | --- |
| product-sale | saleStatus ACTIVE or DISCONTINUED. |
| product-visibility | visibilityStatus VISIBLE or DISABLED. |
| variant-sale | saleStatus ACTIVE or DISCONTINUED. |
| stock | mode INCREASE/DECREASE/SET, integer quantity 0–99999999, reason and confirmation ADJUST_INVENTORY. |

Stock INCREASE requires a positive quantity and STOCK_IN or RETURNED; DECREASE requires a positive quantity and DAMAGED or LOSS. SET positive uses ADJUSTMENT; SET zero uses SOLDOUT. The quantity is a positive magnitude for DECREASE; the source request converts its sign. The resulting on-hand quantity must be 0–99999999. Purged records and variants without inventory tracking are refused. Existing reservations are preserved, so availableQuantity may become negative; do not interpret this as a reservation release or completed sale.

One source dispatch applies the requested selection, with single-variant or bulk stock routing as appropriate. Readback compares selected records and preserved fields; it does not verify every unselected product. Partial bulk results remain unresolved and are never retried automatically. There is no order, payment, fulfillment, shipping or refund effect.

Dry run returns COMMERCE_OPERATION_PLAN. A no-op skips dispatch; confirmed stored state returns COMMERCE_OPERATION_COMPLETE. Keep taskType `commerce-product-control` and the original input. Central status is historical; resume only observes sent effects, while prepared work requires identical apply. Sent operations never replay. Completed replay has no current verification/link. See the guide for errors, uncertain acknowledgements and parent destinations.

## Example

```json
{"channelCode":"selected-channel","requestId":"product-visibility-001","expectedRevision":"0000000000000000000000000000000000000000000000000000000000000000","ids":["observed-product"],"action":"product-visibility","visibilityStatus":"DISABLED","dryRun":true}
```

Replace the revision with the fresh selection revision and confirm the intended selection before an actual change. This example is not a live result.

## Inputs

| Field | Required here | Contract |
| --- | --- | --- |
| `action` | Yes | one of: `product-sale`, `product-visibility`, `variant-sale`, `stock` |
| `channelCode` | Yes | When `action` is `product-sale`: string; min length 1; max length 512; The exact channelCode selected through channel discovery. Do not supply a URL, channel numeric ID, account ID or credentials. |
| `requestId` | Yes | When `action` is `product-sale`: string; pattern `^[A-Za-z0-9_-]{8,80}$`; Reuse this requestId and the exact original input after interruption. Never change requestId to retry an uncertain write. |
| `expectedRevision` | Yes | When `action` is `product-sale`: string; pattern `^[a-f0-9]{64}$`; Exact revision returned by the matching read for this channel, installed pApp and resource. |
| `ids` | Yes | When `action` is `product-sale`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `dryRun` | No | When `action` is `product-sale`: boolean; default `false` |
| `saleStatus` | Yes | When `action` is `product-sale`: `ACTIVE`, `DISCONTINUED` |
| `channelCode` | Yes | When `action` is `product-visibility`: string; min length 1; max length 512; The exact channelCode selected through channel discovery. Do not supply a URL, channel numeric ID, account ID or credentials. |
| `requestId` | Yes | When `action` is `product-visibility`: string; pattern `^[A-Za-z0-9_-]{8,80}$`; Reuse this requestId and the exact original input after interruption. Never change requestId to retry an uncertain write. |
| `expectedRevision` | Yes | When `action` is `product-visibility`: string; pattern `^[a-f0-9]{64}$`; Exact revision returned by the matching read for this channel, installed pApp and resource. |
| `ids` | Yes | When `action` is `product-visibility`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `dryRun` | No | When `action` is `product-visibility`: boolean; default `false` |
| `visibilityStatus` | Yes | When `action` is `product-visibility`: `VISIBLE`, `DISABLED` |
| `channelCode` | Yes | When `action` is `variant-sale`: string; min length 1; max length 512; The exact channelCode selected through channel discovery. Do not supply a URL, channel numeric ID, account ID or credentials. |
| `requestId` | Yes | When `action` is `variant-sale`: string; pattern `^[A-Za-z0-9_-]{8,80}$`; Reuse this requestId and the exact original input after interruption. Never change requestId to retry an uncertain write. |
| `expectedRevision` | Yes | When `action` is `variant-sale`: string; pattern `^[a-f0-9]{64}$`; Exact revision returned by the matching read for this channel, installed pApp and resource. |
| `ids` | Yes | When `action` is `variant-sale`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `dryRun` | No | When `action` is `variant-sale`: boolean; default `false` |
| `saleStatus` | Yes | When `action` is `variant-sale`: `ACTIVE`, `DISCONTINUED` |
| `channelCode` | Yes | When `action` is `stock`: string; min length 1; max length 512; The exact channelCode selected through channel discovery. Do not supply a URL, channel numeric ID, account ID or credentials. |
| `requestId` | Yes | When `action` is `stock`: string; pattern `^[A-Za-z0-9_-]{8,80}$`; Reuse this requestId and the exact original input after interruption. Never change requestId to retry an uncertain write. |
| `expectedRevision` | Yes | When `action` is `stock`: string; pattern `^[a-f0-9]{64}$`; Exact revision returned by the matching read for this channel, installed pApp and resource. |
| `ids` | Yes | When `action` is `stock`: array; items: string; min length 1; max length 160; pattern `^[A-Za-z0-9_-]+$`; Exact resource identifier returned by this operation, never a title, unrelated row ID or URL.; min items 1; max items 100 |
| `dryRun` | No | When `action` is `stock`: boolean; default `false` |
| `mode` | Yes | When `action` is `stock`: `INCREASE`, `DECREASE`, `SET` |
| `quantity` | Yes | When `action` is `stock`: integer; minimum 0; maximum 99999999 |
| `reason` | Yes | When `action` is `stock`: `ADJUSTMENT`, `STOCK_IN`, `DAMAGED`, `RETURNED`, `LOSS`, `SOLDOUT` |
| `confirmation` | Yes | When `action` is `stock`: `ADJUST_INVENTORY` |