Topolo Docs Topolo Platform
Open workspace

Create Inventory item

Create an active item with zero stock in the granted workspace. Omitted SKU derives from the name, unit defaults to unit and threshold defaults to zero; an existing workspace/SKU uniqueness conflict is not an upsert.

Outcome

Create an active item with zero stock in the granted workspace. Omitted SKU derives from the name, unit defaults to unit and threshold defaults to zero; an existing workspace/SKU uniqueness conflict is not an upsert.

Before you start

  • Verify the authenticated identity, exact environment and pinned approved organization context before preparing an action.
  • The published application permission is workspace:write. Discover a granted Inventory workspace and bind that exact resource. Supplied identifiers do not grant access.
  • Authorize the documented inventory, review, import, notification, metering, privacy or archival effects before CLI --confirm or MCP confirm:true.

Discover the target

topolo whoami --json
topolo actions get app_topolo_inventory.items.create --detail --json
topolo resources topolo-inventory --json
topolo workspaces list topolo-inventory --json
  • Select the exact granted workspace id as INVENTORY_WORKSPACE_ID. Fixture ids authorize no live operation.
  • Discover item ids through items.list or the reviewed items.create response in this workspace.

Request

POST /api/items

Save action input as payload.json. Inspect the plan for the exact path, query and body. Set INVENTORY_WORKSPACE_ID from granted resource discovery.

Inspect and test this action in the signed action console, then perform the verification below.

Input fields

FieldRequiredTypeConstraints
nameRequiredstringNonblank display name; trimmed by the handler.; {"minLength":1}
skuOptionalstringOptional nonblank SKU unique within the workspace; supplied value is trimmed without uppercasing.; {"minLength":1}
descriptionOptionalstringOptional description; trimmed, with blank input stored as an empty string.; {}
unitOptionalstringOptional unit; trimmed, default unit.; {"minLength":1}
lowStockThresholdOptionalnumberNonnegative number; zero is valid and zero stock is at its threshold.; {"minimum":0}

View the complete input schema in the action console. The same schema is available through CLI and MCP action discovery.

Effects

  • Initializes an identity-only mirror for the platform-authorized workspace, then inserts a new UUID item. These writes are sequential.
  • Derived SKU uppercases the ASCII slug of the name and truncates it to 64 characters; supplied nonblank SKU is trimmed and retained. Description defaults empty, unit unit, threshold zero.
  • No stock movement or notification is emitted by item creation. Workspace/SKU uniqueness is enforced by SQLite; replay does not return an existing item.

Interpret the response

Use response path $.item.id for inventory_item. An empty list does not discover a target.

Expect HTTP 201 and retain item.id; verify defaults and quantityOnHand zero through items.get. Check existing SKUs through items.list before an ambiguous retry. A duplicate SQL insert can fail rather than provide an idempotent result.

The success schema was checked against captured handler responses. Delegated Auth profile and canonical widget context fields can vary; exact Inventory projections and all six raw SQL export stores are source-reviewed. Error examples retain their actual refusal shapes.

View the complete success schema in the action console. The worked examples below retain complete captured responses; action discovery supplies the exact schema.

Worked examples

Captured exported Worker responses use both real local SQLite D1 databases with all six committed migrations, synthetic Auth/workspace grants and simulated Notify/Nexus/archive transport. They prove local handler shapes and scoped behavior, not live authorization, notification delivery, metering acceptance or environment deployment. Large 100-row list/capped-dashboard captures are retained in local evidence; committed tests verify those limits while worked guides use smaller complete responses. Refused examples demonstrate boundaries and must not be executed as successful workflows.

Successful request

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Notify/Nexus/archive transport. No live delivery, billing or environment deployment proof. Captured scenario: derived SKU and defaults.

Input · payload.json:

{
  "name": "Kraft mailer 240x320"
}

CLI:

topolo actions validate app_topolo_inventory.items.create --data @payload.json --json
topolo actions plan app_topolo_inventory.items.create --resource-type workspace --resource-id "$INVENTORY_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_inventory.items.create --resource-type workspace --resource-id "$INVENTORY_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_inventory.items.create",
    "input": {
      "name": "Kraft mailer 240x320"
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 201:

{
  "item": {
    "id": "invitem_b29c4494-14e0-43dd-87e6-e33856f732af",
    "workspaceId": "ws_inventory_fixture",
    "sku": "KRAFT-MAILER-240X320",
    "name": "Kraft mailer 240x320",
    "description": "",
    "unit": "unit",
    "status": "active",
    "lowStockThreshold": 0,
    "quantityOnHand": 0,
    "createdByUserId": "usr_inventory_fixture",
    "createdByEmail": "operator@example.test",
    "createdAt": "2026-10-04T05:46:36.190Z",
    "updatedAt": "2026-10-04T05:46:36.190Z"
  }
}

HTTP 201. Expect HTTP 201 and retain item.id; verify defaults and quantityOnHand zero through items.get. Check existing SKUs through items.list before an ambiguous retry. A duplicate SQL insert can fail rather than provide an idempotent result.

Another supported request

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Notify/Nexus/archive transport. No live delivery, billing or environment deployment proof. Captured scenario: items.create.

Input · payload.json:

{
  "name": "Blue widget",
  "sku": "WIDGET-BLUE",
  "lowStockThreshold": 5
}

CLI:

topolo actions validate app_topolo_inventory.items.create --data @payload.json --json
topolo actions plan app_topolo_inventory.items.create --resource-type workspace --resource-id "$INVENTORY_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_inventory.items.create --resource-type workspace --resource-id "$INVENTORY_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_inventory.items.create",
    "input": {
      "name": "Blue widget",
      "sku": "WIDGET-BLUE",
      "lowStockThreshold": 5
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 201:

{
  "item": {
    "id": "invitem_d69d6494-b1f0-472a-8ce6-c2e8e5ddb02d",
    "workspaceId": "ws_inventory_fixture",
    "sku": "WIDGET-BLUE",
    "name": "Blue widget",
    "description": "",
    "unit": "unit",
    "status": "active",
    "lowStockThreshold": 5,
    "quantityOnHand": 0,
    "createdByUserId": "usr_inventory_fixture",
    "createdByEmail": "operator@example.test",
    "createdAt": "2026-10-04T05:46:38.112Z",
    "updatedAt": "2026-10-04T05:46:38.112Z"
  }
}

HTTP 201. Expect HTTP 201 and retain item.id; verify defaults and quantityOnHand zero through items.get. Check existing SKUs through items.list before an ambiguous retry. A duplicate SQL insert can fail rather than provide an idempotent result.

Refused request · HTTP 403

Actual exported Worker response with both local SQLite D1 databases and all committed migrations; synthetic Auth/grants and simulated Notify/Nexus/archive transport. No live delivery, billing or environment deployment proof. Captured scenario: workspace:write missing.

Input · payload.json:

{
  "name": "Denied"
}

CLI:

topolo actions validate app_topolo_inventory.items.create --data @payload.json --json
topolo actions plan app_topolo_inventory.items.create --resource-type workspace --resource-id "$INVENTORY_WORKSPACE_ID" --data @payload.json --json

Captured local response · HTTP 403:

{
  "success": false,
  "error": {
    "code": "action_permission_required",
    "message": "Action \"items.create\" requires permission \"workspace:write\".",
    "action": "items.create"
  }
}

HTTP 403. The handler refused this request. Resolve its exact cause before retrying; input validation can reject an invalid fixture before it reaches the handler.

Verify the result

  • Expect HTTP 201 and retain item.id; verify defaults and quantityOnHand zero through items.get.
  • Check existing SKUs through items.list before an ambiguous retry. A duplicate SQL insert can fail rather than provide an idempotent result.

Errors and recovery

  • invalid_action_input (HTTP 400): Correct only the exact fields reported by the published schema validator. An invalid input can be refused before its handler.
  • action_permission_required (HTTP 403): Stop when the verified credential lacks the published action permission. Resource identifiers and organization ownership do not grant that permission.
  • organization_required (HTTP 403): Use the specifically authorized organization context; personal scope cannot act on organization-owned Inventory data.
  • workspace_required (HTTP 400): Discover an authorized Inventory workspace and pass its exact separate resource binding; bootstrap does not select a workspace.
  • workspaces_unavailable (HTTP 503): Retain the request id and report unavailable canonical workspace discovery; do not invent a default workspace.
  • name_required (HTTP 400): Supply a nonblank name; whitespace-only text can pass a minimum-length schema but fail the trimmed handler check.

Auth, action-input validation and platform resource resolution can refuse a request before its handler. Retain the exact error, request id and context; requesting another context is not a legitimate way to bypass a refusal.

Recovery boundary

Archive an item created in error. Archival preserves the record and movement history; it is not hard deletion. An initialized workspace mirror is not removed by item archival.

  • Get Inventory item: Read one item in the granted workspace with descriptive fields, archive status and quantityOnHand computed from all its movements. Archived items remain readable; missing or foreign items return not_found.
  • List Inventory locations: Read all locations in the granted workspace, default first and then name ascending. There is no pagination, location deletion or default-changing action on this published surface.
  • Record Inventory stock movement: Append one nonzero signed quantity delta against an active item and existing location in the same workspace. Movement type labels do not set the sign, pair a transfer or defer stock while review is pending.
  • Archive Inventory item: Set an existing item to archived and return only an ok acknowledgement. The item and ledger remain readable, disappear from active dashboard counts, and refuse subsequent movement creation.

Evidence

Captured exported Worker responses use both real local SQLite D1 databases with all six committed migrations, synthetic Auth/workspace grants and simulated Notify/Nexus/archive transport. They prove local handler shapes and scoped behavior, not live authorization, notification delivery, metering acceptance or environment deployment. Large 100-row list/capped-dashboard captures are retained in local evidence; committed tests verify those limits while worked guides use smaller complete responses. Capture digests and test scenarios are retained in the source fixture records.