# ShelfCycle Public API v1.47.0

Source of truth: https://app.shelfcycle.com/api/v1/openapi.json
Interactive reference: https://developer.shelfcycle.com/reference
Agent guidance: https://developer.shelfcycle.com/llms.txt

## POST /api/v1/products/{id}/archive

Archive a product

Archives or restores one product. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current Product archive permission. The request may omit a body or use an empty JSON object. Product safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/products/{id}/unarchive

Restore a product

Archives or restores one product. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current Product archive permission. The request may omit a body or use an empty JSON object. Product safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/customers/{id}/archive

Archive a customer

Archives or restores one customer. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current customer archive permission. The request may omit a body or use an empty JSON object. Customer safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/customers/{id}/unarchive

Restore a customer

Archives or restores one customer. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current customer archive permission. The request may omit a body or use an empty JSON object. Customer safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/suppliers/{id}/archive

Archive a supplier

Archives or restores one supplier. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current supplier archive permission. The request may omit a body or use an empty JSON object. Supplier safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/suppliers/{id}/unarchive

Restore a supplier

Archives or restores one supplier. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current supplier archive permission. The request may omit a body or use an empty JSON object. Supplier safeguards are reported as clear categories and counts.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/contacts/{id}/archive

Archive a customer or supplier contact

Archives or restores one selected customer or supplier contact. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current archive permission for the contact's customer or supplier. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: contacts:update
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/contacts/{id}/unarchive

Restore a customer or supplier contact

Archives or restores one selected customer or supplier contact. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current archive permission for the contact's customer or supplier. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: contacts:update
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/customers/{id}/locations/{locationId}/addresses/{addressId}/archive

Archive a customer address

Archives or restores one customer address under its selected customer and location. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current customer archive permission. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); addressId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/customers/{id}/locations/{locationId}/addresses/{addressId}/unarchive

Restore a customer address

Archives or restores one customer address under its selected customer and location. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current customer archive permission. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); addressId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/suppliers/{id}/ship-from-locations/{locationId}/archive

Archive a supplier ship-from location

Archives or restores one ship-from location under its selected supplier. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current supplier archive permission. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/suppliers/{id}/ship-from-locations/{locationId}/unarchive

Restore a supplier ship-from location

Archives or restores one ship-from location under its selected supplier. Preview with dryRun=true to review readiness and retrieve the current updatedAt value, then send it in If-Match to apply the action. The acting person must have current supplier archive permission. The request may omit a body or use an empty JSON object.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or dry-run readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/openapi.json

Get the generated OpenAPI specification

Returns the public, CORS-open OpenAPI 3.1 document for the ShelfCycle public API.

- Auth: Public
- Required scope: Live key and user permissions
- Success responses: 200: Generated OpenAPI 3.1 document. application/json object with openapi, info
- Common errors: 405: Method not allowed. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/me

Inspect the authenticated API key

Returns org, key, acting user, documentation links, and effective capabilities derived from key scopes plus current ShelfCycle access. Use dryRun=true on write endpoints for target-specific visibility, archived state, idempotency, duplicate, concurrency, and shape checks.

- Auth: Bearer API key
- Required scope: Live key and user permissions
- Success responses: 200: Authenticated API key, acting user, documentation, and effective capabilities. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/search

Search public API records

Resolves customers, suppliers, contacts, products, sales orders, purchase orders, and locations visible to the acting user. Cards are resolver hints only and never include money, line items, costs, documents, inventory, or margin fields.

- Auth: Bearer API key
- Required scope: search:read
- Parameters: q (query, required, string); types (query, optional, string); limit (query, optional, string)
- Success responses: 200: Search result cards and request metadata. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/entity-resolution

Resolve wording to an authorized entity

Binds human wording to one customer, supplier, product, product family, sales order, or purchase order class using the same matching behavior as ShelfCycle Assistant. Unique, ambiguous, and missing outcomes all return HTTP 200. A class=product request can select a product family when the wording identifies the family more clearly than one product; check selectedCandidate.matchedClass before using the returned ID. Matching considers only the first 12 whitespace- or punctuation-separated tokens of q. relatedTags is included only when the key also grants tags:read and the acting person has current Tags access.

- Auth: Bearer API key
- Required scope: search:read
- Parameters: q (query, required, string); class (query, required, enum: customer, supplier, product, product_family, sales_order, purchase_order, salesperson, warehouse)
- Success responses: 200: Entity Resolution candidates and selection status. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/warehouses

List warehouses

Returns the warehouse directory. Active physical warehouses are included by default; includeArchived and includeDirectShip add those locations when needed. Continue a list with the returned cursor by itself, or read one warehouse by ID.

- Auth: Bearer API key
- Required scope: warehouses:read
- Parameters: q (query, optional, string); externalId (query, optional, string); includeArchived (query, optional, enum: true, false); includeDirectShip (query, optional, enum: true, false); limit (query, optional, integer); cursor (query, optional, string)
- Success responses: 200: Warehouse directory and continuation details. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/warehouses

Create a warehouse

Creates a physical warehouse with its name, address, contact details, and optional unique source ID. Repeating the same source ID and fields returns the warehouse unchanged. When externalId is omitted, use Idempotency-Key for safe retries. Use dryRun=true to preview the request without saving it.

- Auth: Bearer API key
- Required scope: warehouses:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: optional application/json object with name
- Success responses: 200: Existing option returned unchanged, or preview result. application/json body; 201: Created warehouse. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/warehouses/{id}

Get a warehouse

Returns the warehouse directory. Active physical warehouses are included by default; includeArchived and includeDirectShip add those locations when needed. Continue a list with the returned cursor by itself, or read one warehouse by ID.

- Auth: Bearer API key
- Required scope: warehouses:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Warehouse details with the current updatedAt value. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/warehouses/{id}

Update a warehouse

Updates a physical warehouse's name, address, contact details, or source ID. Send the latest updatedAt value in If-Match, or use dryRun=true to preview the change.

- Auth: Bearer API key
- Required scope: warehouses:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object with name, street1, street2, city, country, state, zip, phone
- Success responses: 200: Updated warehouse, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/warehouses/{id}/archive

Archive a warehouse

Archives or restores a physical warehouse while preserving its identity and existing inventory history. Send an empty body with the latest updatedAt value in If-Match, or use dryRun=true to preview the action.

- Auth: Bearer API key
- Required scope: warehouses:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/warehouses/{id}/unarchive

Restore a warehouse

Archives or restores a physical warehouse while preserving its identity and existing inventory history. Send an empty body with the latest updatedAt value in If-Match, or use dryRun=true to preview the action.

- Auth: Bearer API key
- Required scope: warehouses:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/shipping-options

List shipping options

Returns the organization's Shipping Options vocabulary across sales and purchase freight terms, sales shipping carriers, FOB terms, freight methods, and border crossing points. Use type to select one vocabulary, includeArchived to review retired choices, or read one option by ID. Archiving preserves the option's identity and existing document history.

- Auth: Bearer API key
- Required scope: shipping-options:read
- Parameters: type (query, optional, enum: SO_FREIGHT_TERMS, PO_FREIGHT_TERMS, SO_SHIPPING_CARRIER, SO_SHIPPING_FOB, SO_FREIGHT_METHOD, BORDER_CROSSING_POINT); q (query, optional, string); externalId (query, optional, string); includeArchived (query, optional, enum: true, false); limit (query, optional, integer)
- Success responses: 200: Shipping Options directory and complete result coverage. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/shipping-options

Create a shipping option

Creates one Shipping Option with its type, value, and optional source ID. Source identity belongs to the selected type. Repeating the same source identity or type and value returns the existing option unchanged when it matches. Use Idempotency-Key for a new option, or dryRun=true to preview the request.

- Auth: Bearer API key
- Required scope: shipping-options:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: optional application/json object with type, value
- Success responses: 200: Existing option returned unchanged, or preview result. application/json body; 201: Created Shipping Option. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/shipping-options/{id}

Read shipping option identity

Returns the organization's Shipping Options vocabulary across sales and purchase freight terms, sales shipping carriers, FOB terms, freight methods, and border crossing points. Use type to select one vocabulary, includeArchived to review retired choices, or read one option by ID. Archiving preserves the option's identity and existing document history.

- Auth: Bearer API key
- Required scope: shipping-options:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Shipping Option details with the current updatedAt value. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/shipping-options/{id}

Update a shipping option

Updates one Shipping Option's value or source ID. Send the latest updatedAt value in If-Match, or use dryRun=true to preview the change. Restore an archived option before updating it; the option type remains fixed.

- Auth: Bearer API key
- Required scope: shipping-options:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object with value, externalId
- Success responses: 200: Updated Shipping Option, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/shipping-options/{id}/archive

archive shipping option

Archives or restores one Shipping Option while preserving its identity. Send an empty body with the latest updatedAt value in If-Match, or use dryRun=true to preview the action.

- Auth: Bearer API key
- Required scope: shipping-options:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/shipping-options/{id}/unarchive

unarchive shipping option

Archives or restores one Shipping Option while preserving its identity. Send an empty body with the latest updatedAt value in If-Match, or use dryRun=true to preview the action.

- Auth: Bearer API key
- Required scope: shipping-options:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Lifecycle receipt or readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/reorder-points

Set or clear reorder points

Sets or clears integer reorder points for 1 to 50 product-and-warehouse positions together. Use base units for variable products and package counts for fixed products. Zero or below clears a threshold, repeated values return changed:false, and dryRun=true previews the complete request. Review saved thresholds through GET /reorder-status.

- Auth: Bearer API key
- Required scope: reorder:write
- Parameters: dryRun (query, optional, enum: true)
- Request body: optional application/json object with items
- Success responses: 200: Reorder-point results for each selected position, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/tags

List organization tags

Returns stable tag IDs, untruncated labels, descriptions, and the public entity classes each tag applies to. The directory contains no assignment counts. Keep the original filters and limit unchanged, then continue with the exact returned nextCursor value; traversal is current-state and is not snapshot-isolated across requests.

- Auth: Bearer API key
- Required scope: tags:read
- Parameters: entityType (query, optional, enum: supplier, customer, product, product_family, contact, opportunity, sales_order, purchase_order); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Available organization tags and continuation details. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/tags

Create an organization tag

Creates an organization tag. Repeating the same tag leaves it unchanged, and dryRun=true previews the request without saving it. applicableEntityTypes uses the same vocabulary as GET /api/v1/tags: the full class roster means unrestricted.

- Auth: Bearer API key
- Required scope: tags:write
- Parameters: dryRun (query, optional, enum: true)
- Request body: optional application/json object with label
- Success responses: 200: Existing tag returned unchanged, or preview result. application/json body; 201: Created tag. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/tags/{id}

Update an organization tag

Updates label, description, or applicableEntityTypes; dryRun=true writes nothing. Unrestricted tags list every class; sending that full roster keeps the tag unrestricted.

- Auth: Bearer API key
- Required scope: tags:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true)
- Request body: optional application/json object with label, description, applicableEntityTypes
- Success responses: 200: Updated or unchanged tag, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: Tag not found. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/tag-assignments

Read tags assigned to one record

Returns the tags currently assigned to one available record. Use the customer- or supplier-contact ID for contact, and the customer address ID for ship_to_address.

- Auth: Bearer API key
- Required scope: tags:read
- Parameters: entityType (query, required, enum: supplier, customer, product, product_family, contact, opportunity, sales_order, purchase_order); entityId (query, required, string uuid)
- Success responses: 200: Current tag assignments. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/tag-assignments

Assign one tag to records

Assigns or removes one tag for up to 50 records together. Repeating the same request leaves completed assignments unchanged. contact IDs are Contact.id or SupplierContact.id; opportunity IDs are Opportunity.id; ship_to_address IDs are CustomerLocationAddress.id, not the customer location id; ship_from_address IDs are ShipFromLocation.id.

- Auth: Bearer API key
- Required scope: tags:write
- Parameters: dryRun (query, optional, enum: true)
- Request body: optional application/json object with tagId, entityType, entityIds
- Success responses: 200: Assignment results for every selected record, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: Tag or target not found or not visible. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## DELETE /api/v1/tag-assignments

Remove one tag from records

Assigns or removes one tag for up to 50 records together. Repeating the same request leaves completed assignments unchanged. contact IDs are Contact.id or SupplierContact.id; opportunity IDs are Opportunity.id; ship_to_address IDs are CustomerLocationAddress.id, not the customer location id; ship_from_address IDs are ShipFromLocation.id.

- Auth: Bearer API key
- Required scope: tags:write
- Parameters: dryRun (query, optional, enum: true)
- Request body: optional application/json object with tagId, entityType, entityIds
- Success responses: 200: Assignment results for every selected record, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: Tag or target not found or not visible. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/tagged-records

List records carrying an exact tag

Requires one entityType and exactly one tagId or case-normalized label. Returns identity-only rows under live tag and entity-class view permissions; fuzzy tagQuery is not accepted. Keep the original filters and limit unchanged, then continue with the exact returned nextCursor value.

- Auth: Bearer API key
- Required scope: tags:read
- Parameters: tagId (query, optional, string uuid); label (query, optional, string); entityType (query, required, enum: supplier, customer, product, product_family, contact, opportunity, sales_order, purchase_order); nameQuery (query, optional, string); includeArchived (query, optional, enum: true, false); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Tag details and matching available records. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/product-directory

Find products by regulatory identity or name

Returns the certified product and product-family population matching UN/NA number, CAS, hazard class, packing group, or all raw name tokens. nameQueries batches up to 50 printed names, mutually exclusive with nameQuery; rows carry matchedQueries and metadata gives complete per-name counts and unmatched names. Ordinary lookup searches organization names only; supplier names stay in supplier-history. Keep the original filters and limit unchanged, then continue with the exact returned nextCursor value; each page reflects current data when requested

- Auth: Bearer API key
- Required scope: products:read
- Parameters: unNumber (query, optional, string); casNumber (query, optional, string); hazardClass (query, optional, string); packingGroup (query, optional, string); nameQuery (query, optional, string); nameQueries (query, optional, array of string); includeArchived (query, optional, enum: true, false); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Certified product-directory page and searched identifier spaces. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/supplier-history

Read supplier product and cost history

Returns the active products connected to each selected supplier through supplier setup, purchasing, or the Cost Book. Include 1 to 25 supplierIds, and optionally narrow the result with up to 50 nameQueries or 200 productIds. Each supplier reports coverage, supplier-specific product names, ship-from locations, recent purchase evidence, saved arrangements, and latest saved costs. Amounts include their currency, unit, and comparison basis. Requires both cost-book-entries:read and suppliers:read plus the acting person's current Cost Book and Supplier access.

- Auth: Bearer API key
- Required scope: cost-book-entries:read
- Parameters: supplierIds (query, required, array of string uuid); productIds (query, optional, array of string uuid); nameQueries (query, optional, array of string)
- Success responses: 200: Supplier histories with per-supplier completeness and latest saved costs. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/document-uploads

Create a private document upload grant

Creates a 10-minute, single-object PUT grant for one private file up to 15 MiB. Send every returned upload.headers value verbatim to the returned upload.url. A successful S3 PUT has no ShelfCycle JSON envelope. The returned document descriptor can then be submitted to a Product, Customer, or Supplier document route, or to the Product SDS route. The grant does not attach, scan, parse, or make the file public; extension/MIME policy and SHA-256 transfer integrity are verified before a new association. PDF and raster images may be dedicated SDS files; DOCX, XLSX, and PPTX are general attachments only. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: documents:upload
- Request body: required application/json object with fileName, contentType, sizeBytes, checksumSha256
- Success responses: 201: Private document upload grant and reusable document descriptor. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/cost-book-entries/{id}

Correct one Cost Book event while preserving its history

Creates a corrected replacement for the selected Cost Book event while preserving the original event and its supporting history. The correction remains in the same commercial lane. Use dryRun=true to review it before applying with expectedCurrentEntryId and Idempotency-Key.

- Auth: Bearer API key
- Required scope: cost-book-entries:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with expectedCurrentEntryId
- Success responses: 200: Immutable edit receipt, idempotent replay, or dry-run prediction. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: Cost Book entry was not found or is not visible to this organization. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## DELETE /api/v1/cost-book-entries/{id}

Delete one mistaken Cost Book entry

Removes one selected direct, Landed, or Built from Cost Book entry and its corrections. A ready preview identifies the entry to remove, the preceding version that will return, its added costs, any surviving starting price, and a confirmation sentence. Saved Price Book decisions keep their original figures. Send expectedCurrentEntryId and Idempotency-Key; an exact retry returns the completed receipt.

- Auth: Bearer API key
- Required scope: cost-book-entries:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with expectedCurrentEntryId
- Success responses: 200: Removal receipt, exact retry receipt, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: Cost Book entry was not found or is not visible to this organization. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/cost-book-entries/batch

Apply up to 50 Cost Book updates or corrections

Applies Cost Book updates and corrections in submitted order. A batch accepts at most 50 items, 500 total rates or components, and 2 MB. Rate limits count each submitted item. Item-level failures do not undo successful items, and an interrupted request can continue pending items when retried with the same key and body.

- Auth: Bearer API key
- Required scope: cost-book-entries:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with items
- Success responses: 200: Ordered batch outcomes, completed replay, or dry-run item readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: Idempotency identity conflicts with another payload or is actively claimed. application/json object with error; 413: Batch body exceeds 2 MB. application/json object with error; 422: Batch envelope, child budget, lane identity, or command validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error

## GET /api/v1/reports

List available reports

Returns the report catalog available to the current key and user. Reports require reports:read plus current ShelfCycle access on the acting user; allowedForThisKey tells the caller whether the current key and actor can run each report.

- Auth: Bearer API key
- Required scope: reports:read
- Success responses: 200: Report catalog. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/reports/{reportKey}

Run a report

Runs a read-only report. Money fields are cents-as-string: commercial reports use org base currency, while AR/AP aging keep transaction-currency lanes, signed open balances, credits, due-through and opening amounts. ap-aging requires reports:read AND bills:read; payments-received requires reports:read AND customer-payments:read; payments-made requires reports:read AND supplier-payments:read. Every catalog entry lists all required scopes. sales-summary reconciles to Sales Performance semantics and accepts groupBy values customer, productFamily, productCode, salesOrder, salesPerson, supplier, createdBy, month and dateField values invoiceDate, shipDate, orderDate, and enteredDate; purchase-summary is PO material spend, not cash payments; open-sales-orders returns current open sell value only. customer-invoice-settlement-behavior reports recorded final-settlement timing; customer-credit-exposure reports current posted plus committed exposure; customer-invoice-charges reports matched posted charges and independently matched credits.

- Auth: Bearer API key
- Required scope: reports:read
- Parameters: reportKey (path, required, enum: sales-summary, purchase-summary, open-sales-orders, ap-aging, payments-received, payments-made, ar-aging, pipeline-summary); includeOpeningDocuments (query, optional, enum: true, false); dueBy (query, optional, string); counterpartyId (query, optional, string uuid); groupBy (query, optional, string); dateField (query, optional, enum: invoiceDate, shipDate, orderDate, enteredDate); startDate (query, optional, string); endDate (query, optional, string); includeStatuses (query, optional, string); comparisonStartDate (query, optional, string); comparisonEndDate (query, optional, string); comparisonClassification (query, optional, enum: new, lost, retained); sortBy (query, optional, enum: sales, comparisonSales, salesDelta, grossProfit, comparisonGrossProfit, grossProfitDelta, grossMarginDeltaPoints, spend); sortDirection (query, optional, enum: asc, desc); flags (query, optional, string); customerId (query, optional, string uuid); from (query, optional, string); to (query, optional, string); costCategoryId (query, optional, string uuid); query (query, optional, string); transactionCurrencyCode (query, optional, string); salesPersonId (query, optional, string uuid); productFamilyId (query, optional, string uuid); supplierId (query, optional, string uuid); productCode (query, optional, string); includeDraft (query, optional, enum: true, false); status (query, optional, string); aspect (query, optional, enum: customer, supplier); assignedToId (query, optional, string); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); limit (query, optional, string); offset (query, optional, string)
- Success responses: 200: Report rows, basis, and pagination metadata. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/notes

List notes for a visible subject

Returns metadata-only CRM notes for one visible customer, supplier, or product subject. Optional happenedAtFrom/happenedAtTo organization-calendar days and noteType narrow the list. This is not a global note search.

- Auth: Bearer API key
- Required scope: notes:read
- Parameters: primarySubjectType (query, required, enum: customer, supplier, product); primarySubjectId (query, required, string uuid); happenedAtFrom (query, optional, string); happenedAtTo (query, optional, string); noteType (query, optional, enum: PHONE_MEETING, PHYSICAL_MEETING, VIRTUAL_MEETING, NOTE, EMAIL, SAMPLE_REQUEST, OPPORTUNITY, QUOTE); externalId (query, optional, string); limit (query, optional, string)
- Success responses: 200: Subject-scoped note summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/notes

Create a public API note

Creates a note on a customer, supplier, or product and links any supported related records, including organization users, who are notified. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: notes:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with primarySubject, noteType, title, body, happenedAt
- Success responses: 200: Idempotent replay returned the existing note, or dryRun returned write readiness. application/json body; 201: Note created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/opportunities

List authorized opportunities

Returns customer- and supplier-side opportunities visible to the acting user under deny-by-default aspect authorization. Estimates are exact stored values with explicit currency labels, not revenue, probability, forecast, or accounting truth. The closed sort is updatedAt asc or desc with id ascending as the tie-breaker. Signed cursors bind the organization, API key, normalized filters, sort, and page size.

- Auth: Bearer API key
- Required scope: opportunities:read
- Parameters: query (query, optional, string); status (query, optional, array,null); customerId (query, optional, string uuid); supplierId (query, optional, string uuid); assignedToId (query, optional, array,null); productId (query, optional, string uuid); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); sortBy (query, optional, enum: updatedAt); sortDirection (query, optional, enum: asc, desc); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Authorized opportunity summaries and signed continuation metadata. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/opportunities

Create an opportunity

Creates an opportunity for exactly one existing customer or supplier. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The server stamps PUBLIC_API provenance, the API key id, and the organization's base currency as immutable estimate denomination. Product and assignee references must be active, organization-scoped, and visible to the actor.

- Auth: Bearer API key
- Required scope: opportunities:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with title
- Success responses: 200: Idempotent replay returned the durable prior opportunity, or dryRun returned write readiness. application/json body; 201: Opportunity created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/opportunities/{id}

Get opportunity detail

Returns one visible opportunity with metadata, products, and the newest 100 typed timeline events. Event text is never exposed. An invisible opportunity is indistinguishable from an absent record.

- Auth: Bearer API key
- Required scope: opportunities:read or opportunities:write
- Parameters: id (path, required, string uuid)
- Success responses: 200: Authorized opportunity detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/opportunities/{id}

Update an open opportunity

Updates an open opportunity. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. Execute requires current updatedAt in If-Match. PATCH may set LEAD or IN_PROGRESS, cannot close or reopen, and cannot change estimate currency.

- Auth: Bearer API key
- Required scope: opportunities:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with title, description, estimatedValue, assignedToId, status
- Success responses: 200: Updated opportunity detail, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/opportunities/{id}/close

Close an in-progress opportunity

Closes only an IN_PROGRESS opportunity as WON or LOST. Concurrent close attempts cannot double-emit. WON preserves the existing atomic prospect-customer promotion and cross-organization outbox behavior. dryRun=true reports workflow readiness.

- Auth: Bearer API key
- Required scope: opportunities:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true)
- Request body: required application/json object with successStatus
- Success responses: 200: Closed opportunity detail, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## PUT /api/v1/opportunities/{id}/meta

Upsert opportunity metadata

Creates or replaces one opportunity metadata value by key. The target must be visible under the same deny-by-default aspect authority. dryRun=true reports target visibility and write readiness.

- Auth: Bearer API key
- Required scope: opportunities:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true)
- Request body: required application/json object with key, value
- Success responses: 200: Opportunity detail after metadata upsert, or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/note-activity

Count or list CRM note activity

Returns exact organization-wide CRM note counts grouped by one dimension or a newest-first excerpt list. Calendar windows use the organization timezone and may span up to 50 years, or at most 366 days when a contains filter is applied. List continuations use an opaque signed cursor that must be sent without any other query parameter. Access requires notes:read as an additional credential gate plus live Notes read authority. That authority is broad note.view, or the complete scoped Notes bundle of note.view:salesperson together with a customer read lane and an order read lane. Incomplete custom roles are denied. Organization-wide results do not require a subject filter; a supplied subject filter must independently be readable.

- Auth: Bearer API key
- Required scope: notes:read
- Parameters: view (query, optional, string); groupBy (query, optional, string); happenedAtFrom (query, optional, string); happenedAtTo (query, optional, string); noteType (query, optional, string); createdById (query, optional, string); subjectType (query, optional, string); subjectId (query, optional, string); contains (query, optional, string); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Note activity rows with exact population and continuation metadata. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/email-activity

Count or list emails ShelfCycle sent

Counts emails ShelfCycle sent and email notes the actor can open, lists them, or lists customers with no email in the window. Requires sent-emails:read plus the read scope for each record kind. Notes require notes:read. Sent means handed to the mail provider.

- Auth: Bearer API key
- Required scope: sent-emails:read
- Parameters: view (query, optional, string); groupBy (query, optional, string); from (query, optional, string); to (query, optional, string); sentKind (query, optional, array of enum: INVOICE, SALES_ORDER, PURCHASE_ORDER, SUPPLIER_PAYMENT, CREDIT_NOTE, PRICE_LETTER, AR_STATEMENT); noteType (query, optional, array of enum: PHONE_MEETING, PHYSICAL_MEETING, VIRTUAL_MEETING, NOTE, EMAIL, SAMPLE_REQUEST, OPPORTUNITY, QUOTE); senderId (query, optional, string); subjectType (query, optional, string); subjectId (query, optional, string); salesPersonId (query, optional, string); salesOwnership (query, optional, string); limit (query, optional, string)
- Success responses: 200: Email activity for the requested view. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/sent-emails/{id}

Read one email ShelfCycle sent

Returns one sent email the actor can open. File rows are 900-second signed links and contain no extracted text. Requires sent-emails:read plus the read scope for that email's record kind.

- Auth: Bearer API key
- Required scope: sent-emails:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: One sent email. application/json object with emailId, kindLabel, sentAt, senderName, to, cc, bcc, subject
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/notes/{id}

Get a public API note

Returns a visible CRM note with body. notes:read can read visible human or API notes; notes:write can read API-created notes for v1 compatibility.

- Auth: Bearer API key
- Required scope: notes:read or notes:write
- Parameters: id (path, required, string uuid)
- Success responses: 200: Note detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/notes/{id}

Update a public API note

Updates a note created through the public API. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: notes:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with linkedRecords, noteType, title, body, happenedAt, externalId
- Success responses: 200: Updated note detail, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/contacts

List contacts under one parent

Returns contact summaries scoped to one visible customer or supplier parent. This is not a broad contact export.

- Auth: Bearer API key
- Required scope: contacts:read
- Parameters: parentType (query, required, enum: customer, supplier); parentId (query, required, string uuid); q (query, optional, string); externalId (query, optional, string); limit (query, optional, string); includeArchived (query, optional, enum: true, false)
- Success responses: 200: Parent-scoped contact summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/contacts

Create a customer or supplier contact

Creates a contact under an active customer or supplier parent. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: contacts:create
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with parent, name
- Success responses: 200: Idempotent replay returned the existing contact, or dryRun returned write readiness. application/json body; 201: Contact created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/contacts/{id}

Get a contact

Returns a customer or supplier contact visible to the acting user.

- Auth: Bearer API key
- Required scope: contacts:read or contacts:update or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Contact detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/contacts/{id}

Update a contact

Updates a customer or supplier contact. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: contacts:update
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, title, email, phone, mobilePhone, faxNumber, isEmergency, documentTypes
- Success responses: 200: Updated contact detail, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers

Find customers

Finds customer accounts by familiar identity, commercial setup, activity, creator, or created time. When creator or created-time filters are used without pipelineStatus, every pipeline status is included.

- Auth: Bearer API key
- Required scope: customers:read
- Parameters: q (query, optional, string); externalId (query, optional, string); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); pipelineStatus (query, optional, enum: ACTIVE, PROSPECT); limit (query, optional, string); includeArchived (query, optional, string); salesPersonId (query, optional, string uuid); salesOwnership (query, optional, enum: all, mine, unassigned); setupIssues (query, optional, body); salesActivity (query, optional, enum: any, none); salesFrom (query, optional, string); salesTo (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Customer finder summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/customers

Create a customer profile

Creates a bounded customer profile with one primary location and one billing/shipping address bundle. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name
- Success responses: 200: Idempotent replay returned the existing customer profile, or dryRun returned write readiness. application/json body; 201: Customer profile created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers/{id}

Get a customer

Returns a safe read-only customer detail DTO visible to the acting user.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Customer detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/customers/{id}

Update a customer profile

Updates bounded customer profile fields. Omitted fields are preserved. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, externalId, pipelineStatus, primaryLocation
- Success responses: 200: Updated customer profile, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers/{id}/documents

List customer documents

Returns attached documents on one visible customer, omitting dismissed rows. Document files are user-attached files and may contain sensitive commercial or tax data; ShelfCycle bucket files are returned as 15-minute signed read URLs.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Customer attached documents. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/customers/{id}/documents

Attach a customer document

Creates an attached document on a visible active customer. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The body may be an existing external/legacy link or data.document from the upload-grant route. New API-upload descriptors are HEAD-verified only after replay and duplicate checks. This creates one Document row and one idempotency identity only. It does not transport binary files through the application, mutate the customer, delete documents, or touch tax, payment, ledger, order, inventory, or accounting records. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with fileName, url
- Success responses: 200: Idempotent replay returned the existing customer document, or dryRun returned write readiness. application/json body; 201: Customer document created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/reference/customers

Page active customer references

Pages active customer matching hints for local agent caches. This is not a customer detail export, contact export, incremental sync, archived export, or write authorization surface. Clients must fetch exact detail endpoints before writes.

- Auth: Bearer API key
- Required scope: company-reference:read
- Parameters: limit (query, optional, string); cursor (query, optional, string); includeArchived (query, optional, enum: false)
- Success responses: 200: Active customer reference rows and cursor metadata. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/customers/{id}/locations

List customer locations

Pages active customer locations under one visible active customer. This is parent scoped and not a broad location export.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Parent-scoped active customer locations. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/customers/{id}/locations

Create a customer location

Creates an active customer location with its initial billing or shipping address under a visible active customer. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name, address
- Success responses: 200: Idempotent replay returned the existing customer location, or dryRun returned write readiness. application/json body; 201: Customer location created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers/{id}/locations/{locationId}

Get a customer location

Returns one customer location only when it belongs to the visible customer parent.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid)
- Success responses: 200: Customer location detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/customers/{id}/locations/{locationId}

Update a customer location

Updates safe customer location fields. Primary switching is intentionally unsupported. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, email, website, phone, accountOwnerId, paymentTermsId, customerServiceRepresentativeId, creditLimit
- Success responses: 200: Updated customer location, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers/{id}/locations/{locationId}/addresses

List customer location addresses

Pages active customer addresses under one visible active customer location. This is parent scoped and not a broad address export.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Parent-scoped active customer addresses. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/customers/{id}/locations/{locationId}/addresses

Create a customer address

Creates a billing or shipping address under a visible active customer location. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name
- Success responses: 200: Idempotent replay returned the existing customer address, or dryRun returned write readiness. application/json body; 201: Customer address created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/customers/{id}/locations/{locationId}/addresses/{addressId}

Get a customer address

Returns one customer address only when it belongs to the visible customer and location parents.

- Auth: Bearer API key
- Required scope: customers:read or search:read
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); addressId (path, required, string uuid)
- Success responses: 200: Customer address detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/customers/{id}/locations/{locationId}/addresses/{addressId}

Update a customer address

Updates safe customer address fields. The address must remain billing or shipping eligible. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: customers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); addressId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with street1, street2, city, state, zip, country, name, externalId
- Success responses: 200: Updated customer address, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/product-families

Find product families

Finds existing product family references for product setup. Requires q or exact externalId; this route does not create families.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: q (query, optional, string); externalId (query, optional, string); limit (query, optional, string)
- Success responses: 200: Product family reference summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/product-families

Create a product family

Creates a product family from public-safe identity and regulatory fields. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. Product-family writes are bounded by products:write, live ProductPermission.create, duplicate checks, idempotency, and readback verification. They never create products, suppliers, documents, product family attributes, superfund/tax fields, inventory, orders, costs, prices, or accounting records.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name
- Success responses: 200: Idempotent replay returned the existing product family, or dryRun returned write readiness. application/json body; 201: Product family created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/product-families/{id}

Get a product family reference

Returns one existing product family reference for product setup. This route does not expose SDS files or create families.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Product family reference detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/product-families/{id}

Update a product family

Updates public-safe product-family identity and regulatory fields. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. Family updates require products:write plus live ProductPermission.update and return impactAnalysis with attached product counts. They never rewrite product rows, orders, documents, product family attributes, superfund/tax fields, inventory, costs, prices, or accounting records.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, externalId, casNumber, molecularFormula, unNumbers, ghsSignalWord, hazardSymbols
- Success responses: 200: Updated product family, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/reference/product-packaging

List product packaging references

Lists active product packaging references for product setup. This route does not create packaging or expose inventory.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: q (query, optional, string); name (query, optional, string); unitOfMeasure (query, optional, string); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product packaging reference summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/product-packaging

Create product packaging

Creates an explicit product-packaging reference. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. Execute requires Idempotency-Key.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name, unitOfMeasure
- Success responses: 200: Idempotent replay returned product packaging, or dryRun returned write readiness. application/json body; 201: Product packaging created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/product-packaging/{id}

Get product packaging

Returns one product-packaging reference in the current organization, including its archived state.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Product packaging detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/product-code-attributes

List product code attributes

Lists the product code attributes available for Product setup.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: limit (query, optional, string); cursor (query, optional, string); id (query, optional, string uuid); name (query, optional, string); type (query, optional, enum: SELECT, MULTISELECT, FREE_TEXT, BOOLEAN)
- Success responses: 200: Product code attribute page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/product-code-attributes/{attributeId}/values

List product code attribute values

Lists the available values for one product code attribute in the current organization.

- Auth: Bearer API key
- Required scope: products:read or products:write or search:read
- Parameters: attributeId (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string); id (query, optional, string uuid); value (query, optional, string)
- Success responses: 200: Product code attribute value page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/products/{id}/attribute-assignments

List product attribute assignments

Returns a product's typed code-attribute assignments with their saved value identities and cursor pagination.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product attribute assignment page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/products/{id}/suppliers

List product suppliers

Returns a product's supplier relationships and identifies the selected Current Source when present.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product supplier page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/products/{id}/suppliers

Add a product supplier

Updates one ordinary supplier association. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. Exact repeats are unchanged; this never selects Current Source.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with supplierId
- Success responses: 200: Product supplier receipt or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## DELETE /api/v1/products/{id}/suppliers/{supplierId}

Remove a product supplier

Updates one ordinary supplier association. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. The selected Current Source link cannot be removed.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); supplierId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Success responses: 200: Product supplier receipt or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}/aliases

List product aliases

Returns the aliases available to the acting person, including their organization-wide, customer, or supplier context.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product alias page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/products/{id}/aliases

Create a product alias

Creates one organization-wide, customer-specific, or supplier-specific alias. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The alias keeps the owner and context selected when it was created.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string); If-Match (header, optional, string)
- Request body: required application/json object with value, context
- Success responses: 200: Product alias replay or dryRun readiness. application/json body; 201: Product alias created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## PATCH /api/v1/products/{id}/aliases/{aliasId}

Update a product alias

Updates the alias display value; the owner and context stay as created. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); aliasId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with value
- Success responses: 200: Product alias or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## DELETE /api/v1/products/{id}/aliases/{aliasId}

Remove a product alias

Removes the alias relationship. Execute requests require If-Match; dryRun=true may omit it and returns a blocked check when it is missing. After access, archive-state, and version checks pass, removing an alias that is not attached to the selected owner returns changed:false and leaves the owner timestamp unchanged.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); aliasId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Success responses: 200: Product alias receipt or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/product-families/{id}/aliases

List product family aliases

Returns the aliases available to the acting person, including their organization-wide, customer, or supplier context.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product family alias page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/product-families/{id}/aliases

Create a product family alias

Creates one organization-wide, customer-specific, or supplier-specific alias. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The alias keeps the owner and context selected when it was created.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string); If-Match (header, optional, string)
- Request body: required application/json object with value, context
- Success responses: 200: Product family alias replay or dryRun readiness. application/json body; 201: Product family alias created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## PATCH /api/v1/product-families/{id}/aliases/{aliasId}

Update a product family alias

Updates the alias display value; the owner and context stay as created. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); aliasId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with value
- Success responses: 200: Product family alias or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## DELETE /api/v1/product-families/{id}/aliases/{aliasId}

Remove a product family alias

Removes the alias relationship. Execute requests require If-Match; dryRun=true may omit it and returns a blocked check when it is missing. After access, archive-state, and version checks pass, removing an alias that is not attached to the selected owner returns changed:false and leaves the owner timestamp unchanged.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); aliasId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Success responses: 200: Product family alias receipt or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}/customer-part-numbers

List product customer part numbers

Returns customer part numbers for customers available to the acting person.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Product customer part-number page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/products/{id}/customer-part-numbers

Create a product customer part number

Creates or confirms one customer part number for the selected product. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. Exact repeats are unchanged; a different value requires PATCH.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with customerId, partNo
- Success responses: 200: Product customer part number or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## PATCH /api/v1/products/{id}/customer-part-numbers/{customerId}

Update a product customer part number

Updates the part number for the exact customer relationship. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); customerId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with partNo
- Success responses: 200: Product customer part number or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## DELETE /api/v1/products/{id}/customer-part-numbers/{customerId}

Remove a product customer part number

Removes the selected customer part number. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); customerId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Success responses: 200: Product customer part-number receipt or dryRun readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products

Find products

Bounded product finder. Requires q, exact code, exact externalId, or supplierId. Pass finder inputs only as URL query parameters; do not send a request body.

- Auth: Bearer API key
- Required scope: products:read
- Parameters: q (query, optional, string); code (query, optional, string); externalId (query, optional, string); supplierId (query, optional, string uuid); limit (query, optional, string); includeArchived (query, optional, string)
- Success responses: 200: Product finder summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Product finder validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/products

Create a product

Creates a bounded product catalog record from existing product family, packaging, and optional supplier references. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. Product writes are bounded by products:write, live ProductPermission checks, dry-run readiness, idempotency, duplicate checks, and readback verification. They never create packaging, suppliers, documents, inventory, costs, prices, orders, lots, or accounting records.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with code, productFamilyId, packagingId, qty
- Success responses: 200: Idempotent replay returned the existing product, or dryRun returned write readiness. application/json body; 201: Product created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}

Get a product

The product id is supplied in the path. This operation accepts no query filters and no request body. Returns a safe read-only product detail DTO visible to the acting user.

- Auth: Bearer API key
- Required scope: products:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Product detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/products/{id}

Update a product

Updates product identity, packaging, supplier details, metadata, and hazmat fields. A unique product code can be renamed while connected sales, purchasing, inventory, pricing, cost, and accounting history remains attached to the same product. Send the latest updatedAt value in If-Match, or use dryRun=true to preview readiness. Other structural product changes continue to follow their existing readiness checks.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with code, externalId, productFamilyId, packagingId, supplierId, packagingType, supplierType, qty
- Success responses: 200: Updated product, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}/documents

List product documents

Returns attached documents on one visible product, omitting dismissed rows, plus the product SDS file when present. The SDS entry may point at the same URL as a document row; it answers the product SDS question while documents are the audit trail. ShelfCycle bucket files are returned as 15-minute signed read URLs.

- Auth: Bearer API key
- Required scope: products:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Product attached documents and optional SDS entry. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/products/{id}/documents

Attach a product document

Creates an attached document on a visible active product. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The body may be an existing external/legacy link or data.document from the upload-grant route. New API-upload descriptors are HEAD-verified only after replay and duplicate checks. This creates one Document row and one idempotency identity only. It does not transport binary files through the application, mutate Product.sdsFile, change hazmat fields, delete documents, or touch inventory, lots, pricing, costs, orders, or accounting records. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with fileName, url
- Success responses: 200: Idempotent replay returned the existing product document, or dryRun returned write readiness. application/json body; 201: Product document created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## PUT /api/v1/products/{id}/sds

Assign a current Product SDS

Updates one uploaded PDF or raster image as the Product's current SDS. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. The body must be the document descriptor from POST /api/v1/document-uploads. Exact converged retries return 200 without depending on S3 availability. A prospective assign, repair, rename, or replacement requires current If-Match and verifies the private object's size, declared type, and grant-bound checksum before opening the database transaction. The transaction updates only Product.sdsFile and ensures one Product Document row; prior documents remain evidence history and hazmat fields are unchanged. GET /api/v1/products/{id}/documents verifies both data.sds and sidebar documents. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: products:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with fileName, url
- Success responses: 200: Product SDS updated, repaired, replayed, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/suppliers

Find suppliers

Finds suppliers by familiar wording, source identity, creator, or created time. Continue matching pages with the exact returned cursor.

- Auth: Bearer API key
- Required scope: suppliers:read
- Parameters: q (query, optional, string); externalId (query, optional, string); limit (query, optional, string); includeArchived (query, optional, string); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); cursor (query, optional, string)
- Success responses: 200: Supplier finder summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/suppliers

Create a supplier profile

Creates a bounded supplier profile and optional ship-from address. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name
- Success responses: 200: Idempotent replay returned the existing supplier profile, or dryRun returned write readiness. application/json body; 201: Supplier profile created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/suppliers/{id}

Get a supplier

Returns a safe read-only supplier detail DTO visible to the acting user.

- Auth: Bearer API key
- Required scope: suppliers:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Supplier detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/suppliers/{id}

Update a supplier profile

Updates bounded supplier profile fields. Omitted fields are preserved. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, externalId, phone, email, website, street1, street2, city
- Success responses: 200: Updated supplier profile, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/suppliers/{id}/documents

List supplier documents

Returns attached documents on one visible supplier, omitting dismissed rows. Document files are user-attached files and may contain sensitive commercial or tax data; ShelfCycle bucket files are returned as 15-minute signed read URLs.

- Auth: Bearer API key
- Required scope: suppliers:read or search:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Supplier attached documents. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/suppliers/{id}/documents

Attach a supplier document

Creates an attached document on a visible active supplier. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. The body may be an existing external/legacy link or data.document from the upload-grant route. New API-upload descriptors are HEAD-verified only after replay and duplicate checks. This creates one Document row and one idempotency identity only. It does not transport binary files through the application, mutate the supplier, delete documents, or touch tax, payment, ledger, order, inventory, or accounting records. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with fileName, url
- Success responses: 200: Idempotent replay returned the existing supplier document, or dryRun returned write readiness. application/json body; 201: Supplier document created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/reference/suppliers

Page active supplier references

Pages active supplier matching hints for local agent caches. This is not a supplier detail export, contact export, incremental sync, archived export, or write authorization surface. Clients must fetch exact detail endpoints before writes.

- Auth: Bearer API key
- Required scope: company-reference:read
- Parameters: limit (query, optional, string); cursor (query, optional, string); includeArchived (query, optional, enum: false)
- Success responses: 200: Active supplier reference rows and cursor metadata. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/suppliers/{id}/ship-from-locations

List supplier ship-from locations

Pages active ship-from locations under one visible active supplier. This is parent scoped and not a broad supplier address export.

- Auth: Bearer API key
- Required scope: suppliers:read or search:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Parent-scoped active supplier ship-from locations. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/suppliers/{id}/ship-from-locations

Create a supplier ship-from location

Creates a ship-from location under a visible active supplier. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name
- Success responses: 200: Idempotent replay returned the existing supplier ship-from location, or dryRun returned write readiness. application/json body; 201: Supplier ship-from location created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/suppliers/{id}/ship-from-locations/{locationId}

Get a supplier ship-from location

Returns one ship-from location only when it belongs to the visible supplier parent.

- Auth: Bearer API key
- Required scope: suppliers:read or search:read
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid)
- Success responses: 200: Supplier ship-from location detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/suppliers/{id}/ship-from-locations/{locationId}

Update a supplier ship-from location

Updates safe supplier ship-from location fields. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: suppliers:write
- Parameters: id (path, required, string uuid); locationId (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with street1, street2, city, state, zip, country, name, externalId
- Success responses: 200: Updated supplier ship-from location, or dryRun returned write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/orders

Find sales orders

Bounded sales-order finder with exact identifiers, status, customer, product, linked-order, business-date, changed-record, and creator filters. orderNo, customerOrderNo, and externalId accept up to 25 comma-separated exact tokens; for example, GET /api/v1/orders?customerOrderNo=A,B,C&limit=5. Send finder inputs as query parameters. After the first page, continue with only the exact returned meta.nextCursor value in cursor; do not repeat filters or limit. Changed traversal keeps one fixed snapshot.

- Auth: Bearer API key
- Required scope: orders:read
- Parameters: createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); orderNo (query, optional, string); customerOrderNo (query, optional, string); externalId (query, optional, string); customerId (query, optional, string uuid); productId (query, optional, string uuid); productFamilyId (query, optional, string uuid); linkedPurchaseOrderId (query, optional, string uuid); fromDate (query, optional, string); toDate (query, optional, string); changedFrom (query, optional, string date-time); changedTo (query, optional, string date-time); status (query, optional, enum: DRAFT, CONFIRMED, SHIPPED, DELIVERED, COMPLETED, VOID); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Sales-order finder summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Sales-order finder validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/orders/{id}

Get sales-order detail

Returns the read-only sales-order header, stable line page, explicit fulfillment evidence, and exact stored totals with resolved document currency. No mutation, inventory write, or cost cascade occurs.

- Auth: Bearer API key
- Required scope: orders:read
- Parameters: id (path, required, string uuid); lineLimit (query, optional, string); lineCursor (query, optional, string)
- Success responses: 200: Sales-order detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/purchase-orders

Find purchase orders

Bounded purchase-order finder with exact identifiers, status, supplier, product, linked-order, business-date, changed-record, and creator filters. orderNo and externalId accept up to 25 comma-separated exact tokens. Send finder inputs as query parameters. After the first page, continue with only the exact returned meta.nextCursor value in cursor; do not repeat filters or limit. Changed traversal keeps one fixed snapshot.

- Auth: Bearer API key
- Required scope: purchase-orders:read
- Parameters: createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); orderNo (query, optional, string); externalId (query, optional, string); supplierId (query, optional, string uuid); productId (query, optional, string uuid); productFamilyId (query, optional, string uuid); linkedSalesOrderId (query, optional, string uuid); fromDate (query, optional, string); toDate (query, optional, string); changedFrom (query, optional, string date-time); changedTo (query, optional, string date-time); status (query, optional, enum: DRAFT, CONFIRMED, COMPLETED, VOID); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Purchase-order finder summaries. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 405: Method not allowed. application/json object with error; 422: Purchase-order finder validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/purchase-orders/{id}

Get purchase-order detail

Returns the read-only purchase-order header, stable line page, explicit receipt evidence, exact stored totals, and classified supplier document costs. No receiving, AP, GL, or mutation occurs.

- Auth: Bearer API key
- Required scope: purchase-orders:read
- Parameters: id (path, required, string uuid); lineLimit (query, optional, string); lineCursor (query, optional, string)
- Success responses: 200: Purchase-order detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/purchase-order-execution

Find purchase execution

Returns current open purchase-order lines with deterministic receipt-progress classification and explicit quantity evidence. warehouseId filters the purchase-order header warehouse; null headers do not match, while every row returns nullable warehouse identity. executionChangedAt is the newest included Purchase Order, line, or receipt audit timestamp and is a conservative refetch hint: it may advance for non-projected row changes and does not cover documents, referenced labels, or deleted-receipt discovery. Send finder inputs as query parameters. After the first page, continue with only the exact returned meta.nextCursor value in cursor; do not repeat filters or limit. Each page reflects current data when requested.

- Auth: Bearer API key
- Required scope: purchase-order-execution:read
- Parameters: supplierId (query, optional, string uuid); productId (query, optional, string uuid); productFamilyId (query, optional, string uuid); warehouseId (query, optional, string uuid); includeDraft (query, optional, enum: true, false); dueFrom (query, optional, string); dueTo (query, optional, string); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Current purchase-order execution lines. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Purchase-execution finder validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/purchase-order-lines/{id}/receipt-events

Get purchase receipt events

Returns stable raw receipt-event evidence for one authorized purchase-order line, including planned rows and explicit basis quality.

- Auth: Bearer API key
- Required scope: purchase-order-execution:read
- Parameters: id (path, required, string uuid); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Purchase receipt events. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/inventory-balances

Find inventory balances

Returns current physical inventory balances and complete stock-out counts across products and warehouses before availability filtering. Continue with the signed cursor alone. Each page reflects current data when requested.

- Auth: Bearer API key
- Required scope: inventory:read
- Parameters: productId (query, optional, string uuid); productFamilyId (query, optional, string uuid); warehouseId (query, optional, string uuid); availabilityState (query, optional, enum: zero_on_hand, fully_allocated, positive_available); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Current physical inventory balances. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/invoices

Find invoices

Finds stored financial documents or payments by identity, counterparty, currency, date, or exact amount in integer cents. The default page size is 25; continue with nextCursor by itself. Connected documents and payments are included when the key and acting person can read both resource families. Receivables follow the acting person's current customer and salesperson access.

- Auth: Bearer API key
- Required scope: invoices:read
- Parameters: id (query, optional, string uuid); number (query, optional, string); counterpartyId (query, optional, string uuid); transactionCurrencyCode (query, optional, string); from (query, optional, string); to (query, optional, string); amountCents (query, optional, string); amountMinCents (query, optional, string); amountMaxCents (query, optional, string); limit (query, optional, string); cursor (query, optional, string); kind (query, optional, enum: invoice, credit_note, bill, supplier_credit); amountBasis (query, optional, enum: total, open); openOnly (query, optional, enum: true, false)
- Success responses: 200: Current authorized financial facts. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/invoices/{id}

Get invoices detail

Returns one selected financial document or payment by ID. Connected financial details are included when the key and acting person can read the matching resource family.

- Auth: Bearer API key
- Required scope: invoices:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Exact authorized financial detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/bills

Find bills

Finds stored financial documents or payments by identity, counterparty, currency, date, or exact amount in integer cents. The default page size is 25; continue with nextCursor by itself. Connected documents and payments are included when the key and acting person can read both resource families. Receivables follow the acting person's current customer and salesperson access.

- Auth: Bearer API key
- Required scope: bills:read
- Parameters: id (query, optional, string uuid); number (query, optional, string); counterpartyId (query, optional, string uuid); transactionCurrencyCode (query, optional, string); from (query, optional, string); to (query, optional, string); amountCents (query, optional, string); amountMinCents (query, optional, string); amountMaxCents (query, optional, string); limit (query, optional, string); cursor (query, optional, string); kind (query, optional, enum: invoice, credit_note, bill, supplier_credit); amountBasis (query, optional, enum: total, open); openOnly (query, optional, enum: true, false)
- Success responses: 200: Current authorized financial facts. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/bills/{id}

Get bills detail

Returns one selected financial document or payment by ID. Connected financial details are included when the key and acting person can read the matching resource family.

- Auth: Bearer API key
- Required scope: bills:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Exact authorized financial detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/customer-payments

Find customer payments

Finds stored financial documents or payments by identity, counterparty, currency, date, or exact amount in integer cents. The default page size is 25; continue with nextCursor by itself. Connected documents and payments are included when the key and acting person can read both resource families. Receivables follow the acting person's current customer and salesperson access.

- Auth: Bearer API key
- Required scope: customer-payments:read
- Parameters: id (query, optional, string uuid); number (query, optional, string); counterpartyId (query, optional, string uuid); transactionCurrencyCode (query, optional, string); from (query, optional, string); to (query, optional, string); amountCents (query, optional, string); amountMinCents (query, optional, string); amountMaxCents (query, optional, string); limit (query, optional, string); cursor (query, optional, string); groupId (query, optional, string uuid)
- Success responses: 200: Current authorized financial facts. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/customer-payments/{id}

Get customer payments detail

Returns one selected financial document or payment by ID. Connected financial details are included when the key and acting person can read the matching resource family.

- Auth: Bearer API key
- Required scope: customer-payments:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Exact authorized financial detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/supplier-payments

Find supplier payments

Finds stored financial documents or payments by identity, counterparty, currency, date, or exact amount in integer cents. The default page size is 25; continue with nextCursor by itself. Connected documents and payments are included when the key and acting person can read both resource families. Receivables follow the acting person's current customer and salesperson access.

- Auth: Bearer API key
- Required scope: supplier-payments:read
- Parameters: id (query, optional, string uuid); number (query, optional, string); counterpartyId (query, optional, string uuid); transactionCurrencyCode (query, optional, string); from (query, optional, string); to (query, optional, string); amountCents (query, optional, string); amountMinCents (query, optional, string); amountMaxCents (query, optional, string); limit (query, optional, string); cursor (query, optional, string); groupId (query, optional, string uuid)
- Success responses: 200: Current authorized financial facts. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/supplier-payments/{id}

Get supplier payments detail

Returns one selected financial document or payment by ID. Connected financial details are included when the key and acting person can read the matching resource family.

- Auth: Bearer API key
- Required scope: supplier-payments:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Exact authorized financial detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/lots

Find lots

Finds named lots with exact stored quantities in each row's stated quantity basis. Each row includes lot state, product, warehouse, available dates, COA readiness, and remaining-stock age. coaAttached is true when that lot has its own usable COA attachment. Continue with the exact returned cursor.

- Auth: Bearer API key
- Required scope: lots:read
- Parameters: search (query, optional, string); lotNumber (query, optional, string); productId (query, optional, string uuid); packagingId (query, optional, string uuid); warehouseId (query, optional, string uuid); supplierId (query, optional, string uuid); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time); lotStateCode (query, optional, enum: AVAILABLE, QUARANTINED); quantityField (query, optional, enum: qtyOnOrder, qtyOnHand, qtyAllocated, qtyAvailable); minimumQuantity (query, optional, string); maximumQuantity (query, optional, string); oldestOnHandAddedBefore (query, optional, string); includeOnOrder (query, optional, enum: true, false); includeDepleted (query, optional, enum: true, false); includePlaceholders (query, optional, enum: true, false); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Named lots with current quantities and remaining-stock age. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/lots/{id}

Get lot detail

Returns one selected lot with its quantities, state, COA readiness, recorded stock age, and the oldest remaining inventory additions that explain that age. coaAttached is true when that lot has its own usable COA attachment.

- Auth: Bearer API key
- Required scope: lots:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Exact lot detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/reorder-status

Find reorder status

Returns configured reorder thresholds, current quantities, allocated and committed demand, projected availability, the gap to each threshold, status counts, and configured-product coverage. Projected deficit shows the gap to the configured threshold in the row's quantity basis. Projected availability reflects current stock after allocated and committed demand. Continue with the signed cursor alone.

- Auth: Bearer API key
- Required scope: reorder:read
- Parameters: productId (query, optional, string uuid); productFamilyId (query, optional, string uuid); warehouseId (query, optional, string uuid); status (query, optional, enum: below_on_hand, below_projected, ok); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Current configured reorder status. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/certification-types

List certification types

Lists the certification types available to the current connection, including expiration-notice settings. Warehouse types also require warehouses:read. Add includeDisabled=true when historical type configuration is needed. Continue with the returned meta.nextCursor by itself.

- Auth: Bearer API key
- Required scope: certifications:read
- Parameters: subjectType (query, optional, enum: supplier, customer, product, customer_address, warehouse, supplier_combination); includeDisabled (query, optional, enum: true, false); limit (query, optional, integer); cursor (query, optional, string)
- Success responses: 200: Certification type page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Certification-type finder validation failed. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/certification-records

Find stored certification records

Finds stored certification records for available suppliers, customers, products, customer addresses, warehouses, and supplier-product combinations. Results include effective and renewal states, days left, type notice settings, dates, and recorded evidence filenames. Warehouse results also require warehouses:read. Continue with the returned cursor by itself.

- Auth: Bearer API key
- Required scope: certifications:read
- Parameters: typeId (query, optional, string uuid); typeQuery (query, optional, string); evidenceFileNameQuery (query, optional, string); subjectTypes (query, optional, array,null); subjectId (query, optional, string uuid); recordedStatuses (query, optional, array,null); effectiveStates (query, optional, array,null); expiresAtOrAfter (query, optional, string date-time); expiresAtOrBefore (query, optional, string date-time); evidenceRecordedState (query, optional, enum: recorded, not_recorded, invalid_metadata); includePlaceholders (query, optional, enum: true, false); includeArchived (query, optional, enum: true, false); limit (query, optional, string); cursor (query, optional, string); renewalStates (query, optional, array,null); createdById (query, optional, string uuid); createdFrom (query, optional, string date-time); createdTo (query, optional, string date-time)
- Success responses: 200: Stored certification record page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/certification-subjects

Find subjects with matching certification records

Returns deduplicated authorized subjects with exact matching-record counts. Warehouse subjects also require warehouses:read. It reports records stored in ShelfCycle, not external certification or compliance truth. Current records and non-placeholder rows are the default.

- Auth: Bearer API key
- Required scope: certifications:read
- Parameters: typeId (query, optional, string uuid); typeQuery (query, optional, string); evidenceFileNameQuery (query, optional, string); subjectTypes (query, optional, array,null); subjectId (query, optional, string uuid); recordedStatuses (query, optional, array,null); effectiveStates (query, optional, array,null); expiresAtOrAfter (query, optional, string date-time); expiresAtOrBefore (query, optional, string date-time); evidenceRecordedState (query, optional, enum: recorded, not_recorded, invalid_metadata); includePlaceholders (query, optional, enum: true, false); includeArchived (query, optional, enum: true, false); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Certification subject page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/certification-records/{recordId}

Get one stored certification record

Returns one authorized stored certification row and metadata-only evidence recordedState and fileName. A warehouse record also requires warehouses:read. Hidden, foreign, deleted, and missing records are indistinguishable.

- Auth: Bearer API key
- Required scope: certifications:read
- Parameters: recordId (path, required, string uuid)
- Success responses: 200: Stored certification record detail. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/purchase-orders/{id}/documents

List purchase-order documents

Returns all attached documents attached to one visible purchase order. ShelfCycle bucket files use short-lived signed read URLs.

- Auth: Bearer API key
- Required scope: purchase-order-execution:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Purchase-order documents. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/purchase-orders/{id}/documents

Attach a purchase-order document

Creates an attached document on a visible purchase order. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing. This creates one Document row and one idempotency identity. It does not transport binary files through the application, mutate the purchase order, receive inventory, or post AP or GL entries. A valid API-upload descriptor may be passed between keys in the same organization. documents:upload is required only to mint the grant; association and SDS routes require their documented target write scope and current ShelfCycle access. Descriptor possession grants no read access. API-upload association create and replay responses omit signed access unless the calling key also has the target read scope and live view permission.

- Auth: Bearer API key
- Required scope: purchase-order-documents:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with fileName, url
- Success responses: 200: Idempotent replay returned the existing purchase-order document, or dryRun returned write readiness. application/json body; 201: Purchase-order document created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}/current-cost-source

Get product Current Source authority

Returns the product's exact cost-source authority, eligible Cost Book supplier lanes, and selection provenance. Fixed-supplier products remain authoritative to their fixed supplier. Variable-supplier products return a persisted Current Source when configured; an unavailable persisted source fails closed and is never silently replaced by another lane.

- Auth: Bearer API key
- Required scope: current-cost-sources:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Current Source authority and eligible lanes. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PUT /api/v1/products/{id}/current-cost-source

Set, replace, or clear product Current Source authority

Sets, replaces, or clears the Current Source for a variable-supplier product. expectedCurrentSupplierId is required in the strict body and provides optimistic concurrency; a true no-op succeeds before stale-state rejection. dryRun=true returns eligibility and consequence without writing. Execute records API actor and organization provenance.

- Auth: Bearer API key
- Required scope: current-cost-sources:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true)
- Request body: required application/json object with supplierId, expectedCurrentSupplierId
- Success responses: 200: Current Source write receipt, or dryRun eligibility and consequence. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: Current Source changed after it was read. Re-read authority and retry with the returned expected supplier. application/json object with error; 422: The product or requested supplier lane cannot accept this Current Source change. application/json body; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/products/{id}/cost-context

Get governed product cost context

Returns authoritative current and prior Cost Book entries plus separately labeled completed and pending purchase evidence. supplierId is optional: without it the endpoint follows fixed-supplier or persisted Current Source authority, selects the only eligible lane, or returns a conflict with candidates when multiple unconfigured lanes exist. Explicit supplierId retains exact-lane behavior. Comparisons are emitted only when currency, base unit, cost basis, and evidence timing are compatible. The endpoint requires live Pricing Engine view permission and does not consult the Pricing Engine feature flag.

- Auth: Bearer API key
- Required scope: cost-book-entries:read
- Parameters: id (path, required, string uuid); supplierId (query, optional, string uuid); asOf (query, optional, string)
- Success responses: 200: Governed product and supplier cost context with source-selection metadata. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: Source selection is ambiguous or the persisted Current Source is unavailable. The error code is cost_source_ambiguous or current_cost_source_unavailable; ambiguity includes the complete candidate set in error.example.candidates. application/json body; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/cost-book-entries

Read current or historical Cost Book entries

Returns current Cost Book entries or the history for one product and supplier. Amounts preserve their decimal precision, and every result follows the current user's Cost Book access.

- Auth: Bearer API key
- Required scope: cost-book-entries:read
- Parameters: createdById (query, optional, string); createdFrom (query, optional, string); createdTo (query, optional, string); view (query, optional, string); asOf (query, optional, string); productId (query, optional, string); supplierId (query, optional, string); shipFromLocationId (query, optional, string); entryType (query, optional, string); effectiveState (query, optional, string); versionState (query, optional, string); claimRole (query, optional, string); disposition (query, optional, string); completeness (query, optional, string); includeArchivedEntities (query, optional, enum: true, false); limit (query, optional, string); cursor (query, optional, string)
- Success responses: 200: Current or historical Cost Book entries and signed cursor metadata. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/cost-book-entries

Create the next Cost Book version

Creates one complete direct or constructed Cost Book entry. Use dryRun=true to review readiness without saving, then send expectedCurrentEntryId and Idempotency-Key to apply the update.

- Auth: Bearer API key
- Required scope: cost-book-entries:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json body
- Success responses: 200: Idempotent replay receipt, or dryRun returned write readiness. application/json body; 201: Created or superseded Cost Book entry receipt. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API actor lacks Cost Book write access. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The Cost Book write conflicted with current lane state. application/json object with error; 422: Cost Book domain validation failed with typed repair metadata. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/price-book-entries

Read stored Price Book claims and exact lane history

Returns every authorized stored sell-price claim without selecting a winner. Views cover active, scheduled, expired, all, and lane-anchored history; exact stored Float values are emitted as resubmittable plain decimals. Converted FIXED writes add writeValue evidence for the submitted value and conversion. Normalization, basis evidence, reference packaging, overlap state, invalid windows, and warning codes are explicit. No FX conversion occurs.

- Auth: Bearer API key
- Required scope: price-book-entries:read
- Parameters: createdById (query, optional, string); createdFrom (query, optional, string); createdTo (query, optional, string); view (query, optional, string); asOf (query, optional, string); laneEntryId (query, optional, string); productId (query, optional, string); customerId (query, optional, string); listPrice (query, optional, enum: true, false); currencyCode (query, optional, string); shipToAddressId (query, optional, string); warehouseId (query, optional, string); terms (query, optional, string); sourceRef (query, optional, string); limit (query, optional, body); cursor (query, optional, string)
- Success responses: 200: Authorized Price Book claim population and signed cursor metadata. application/json object with object, data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/price-book-entries

Dry-run or create one exact base-currency Price Book claim

dryRun=true requires Idempotency-Key and returns the complete affected-entry set, signed plan token, exact predicted value, basis snapshot, and warnings. Execute reuses that stable Idempotency-Key with the returned state, revalidates after sorted locks, closes every overlapping claim, and inserts exactly one successor and receipt atomically. Writes use organization base currency only. Unknown outcomes must replay the identical method, path, key, and body; never mint a replacement key.

- Auth: Bearer API key
- Required scope: price-book-entries:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, required, string)
- Request body: required application/json body
- Success responses: 200: Dry-run write readiness or an idempotent replay receipt. application/json body; 201: Created or superseded Price Book entry receipt. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request or Price Book domain validation failed with typed repair metadata. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/representatives

List account representatives

Lists available salesperson, customer-service, and supplier representatives by kind and source ID, including current or archived status and cursor pagination.

- Auth: Bearer API key
- Required scope: company-reference:read
- Parameters: q (query, optional, string); externalId (query, optional, string); includeArchived (query, optional, enum: true, false); limit (query, optional, integer); cursor (query, optional, string); kind (query, optional, enum: salesperson, customer_service, supplier)
- Success responses: 200: Representative directory page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/representatives

Dry-run or create an account representative

Creates an account representative of the selected kind without changing ShelfCycle user links. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with kind, firstName
- Success responses: 200: Idempotent replay or write readiness. application/json body; 201: Representative created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/representatives/{kind}/{id}

Get one representative by kind and id

Returns one representative in the current organization, including archived records. Keys with representative write access can use this response to resume an interrupted workflow.

- Auth: Bearer API key
- Required scope: company-reference:read or company-reference:write
- Parameters: kind (path, required, enum: salesperson, customer_service, supplier); id (path, required, string uuid)
- Success responses: 200: Representative detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/representatives/{kind}/{id}

Dry-run or update representative metadata

Updates representative metadata while preserving linked-user identity. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: kind (path, required, enum: salesperson, customer_service, supplier); id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with firstName, lastName, externalId, email, phone
- Success responses: 200: Representative detail or write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/representatives/{kind}/{id}/archive

Dry-run or archive a representative

Requires current If-Match. Existing account assignments remain intact and no account is reassigned.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: kind (path, required, enum: salesperson, customer_service, supplier); id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Representative lifecycle receipt or write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## POST /api/v1/representatives/{kind}/{id}/unarchive

Dry-run or restore a representative

Requires current If-Match. Existing account assignments remain intact and no account is reassigned.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: kind (path, required, enum: salesperson, customer_service, supplier); id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: optional application/json object
- Success responses: 200: Representative lifecycle receipt or write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/payment-terms

List payment terms

Lists payment terms with their exact financial values, source IDs, and cursor pagination.

- Auth: Bearer API key
- Required scope: company-reference:read
- Parameters: q (query, optional, string); externalId (query, optional, string); includeArchived (query, optional, enum: true, false); limit (query, optional, integer); cursor (query, optional, string)
- Success responses: 200: Payment-term directory page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/payment-terms

Dry-run or create payment terms

Creates payment terms with exact discount values and a source ID. Execute requests require Idempotency-Key. dryRun=true may omit Idempotency-Key and returns a blocked readiness check instead of writing.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name, description, netDays, discountDays, discountPercentage
- Success responses: 200: Idempotent replay or write readiness. application/json body; 201: Payment term created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/payment-terms/{id}

Get one payment term

Returns the payment term's exact financial and descriptive fields. Keys with payment-term write access can use this response to resume an interrupted workflow.

- Auth: Bearer API key
- Required scope: company-reference:read or company-reference:write
- Parameters: id (path, required, string uuid)
- Success responses: 200: Payment-term detail. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/payment-terms/{id}

Dry-run or update payment-term metadata

PATCH accepts name, description, and externalId. Net and discount values remain as set when the payment term was created.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, description, externalId
- Success responses: 200: Payment-term detail or write readiness. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/reference/ledger-accounts

List ledger-account metadata

Returns Chart of Accounts records available for connected supplier and finance setup, including names, source IDs, account types, reporting flags, and current update times.

- Auth: Bearer API key
- Required scope: company-reference:read
- Parameters: q (query, optional, string); externalId (query, optional, string); accountType (query, optional, enum: ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE); limit (query, optional, integer); cursor (query, optional, string)
- Success responses: 200: Ledger-account metadata directory page. application/json object with data, meta
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## POST /api/v1/reference/ledger-accounts

Dry-run or create a ledger account

Creates one Chart of Accounts record with its name, account type, optional source ID, reporting category, report inclusion, and income-statement classification. Use Idempotency-Key when no source ID is available, or dryRun=true to preview the request.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: dryRun (query, optional, enum: true); Idempotency-Key (header, optional, string)
- Request body: required application/json object with name, accountType
- Success responses: 200: Existing account returned unchanged, or preview result. application/json body; 201: Chart of Accounts record created. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error

## GET /api/v1/reference/ledger-accounts/{id}

Get one ledger account

Returns one selected Chart of Accounts record with its current reporting details and updatedAt value for a later update.

- Auth: Bearer API key
- Required scope: company-reference:read or company-reference:write
- Parameters: id (path, required, string uuid)
- Success responses: 200: Chart of Accounts details. application/json object with data
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error; 503: A required dependent service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## PATCH /api/v1/reference/ledger-accounts/{id}

Dry-run or update a ledger account

Updates one Chart of Accounts record's name, source ID, category, report inclusion, account type, or income-statement classification. Classification changes are available while the account has no financial activity or connected assignments. Send the latest updatedAt value in If-Match, or use dryRun=true to preview the change.

- Auth: Bearer API key
- Required scope: company-reference:write
- Parameters: id (path, required, string uuid); dryRun (query, optional, enum: true); If-Match (header, optional, string)
- Request body: required application/json object with name, accountType, externalId, categoryId, excludeFromReports, incomeStatementType
- Success responses: 200: Updated account details, or preview result. application/json body
- Common errors: 401: Bearer API key is missing, invalid, expired, revoked, or issued to an inactive actor. application/json object with error; 403: The API key is missing a required scope or the acting user lacks current ShelfCycle access permission. application/json object with error; 404: The requested parent or record was not found in the authenticated org. application/json object with error; 405: Method not allowed. application/json object with error; 409: The write conflicted with an existing record, idempotency payload, or stale If-Match value. application/json object with error; 422: Request validation failed. Validation responses include param and errors[]. application/json object with error; 429: The API key exceeded its rate limit. application/json object with error; 500: An unexpected server error occurred. application/json object with error
