# ShelfCycle Public API v1.21

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

## 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 coarse effective capabilities derived from key scopes plus live RBAC. 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/reports

List governed reports

Returns the governed report catalog. Reports require reports:read plus live RBAC 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Run a governed report

Runs a governed read-only report. Money fields are cents-as-string in org base currency. sales-summary reconciles to Sales Performance semantics; purchase-summary is PO material spend, not cash payments; open-sales-orders returns current open sell value only.

- Auth: Bearer API key
- Required scope: reports:read
- Parameters: reportKey (path, required, enum: sales-summary, purchase-summary, open-sales-orders); groupBy (query, optional, string); dateField (query, optional, enum: invoiceDate, shipDate, orderDate); 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); customerId (query, optional, string uuid); 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); 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 live RBAC 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: The fail-closed rate limit 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. 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); 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 live RBAC 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: The fail-closed rate limit 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. 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 live RBAC 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/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 live RBAC 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: The fail-closed rate limit 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
- 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 live RBAC 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); 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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

Bounded customer finder. Requires q or exact externalId and does not support broad sync or updatedSince.

- Auth: Bearer API key
- Required scope: customers:read
- Parameters: q (query, optional, string); externalId (query, optional, string); pipelineStatus (query, optional, enum: ACTIVE, PROSPECT); limit (query, optional, string); includeArchived (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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Attach a customer document link

Creates a link-based 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. This creates one Document row and one idempotency identity only. It does not upload binary files, mutate the customer, delete documents, or touch tax, payment, ledger, order, inventory, or accounting records.

- 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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, primary, makePrimary
- 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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, catalog 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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, catalog 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 live RBAC 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); unitOfMeasure (query, optional, string); limit (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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

## GET /api/v1/products

Find products

Bounded product finder. Requires q, exact code, exact externalId, or supplierId.

- 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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

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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Update a product

Updates safe product identity, packaging/supplier semantics, metadata, and hazmat fields. Execute requests require If-Match. dryRun=true may omit If-Match and returns a blocked readiness check instead of writing. Product PATCH requires products:write plus live ProductPermission.update, If-Match, duplicate/self-exclusion checks, and impactAnalysis. When sales order, purchase order, lot, price book, or supplier cost usage exists, code, productFamilyId, packagingId, packagingType, qty, supplierType, and supplierId changes are blocked; externalId and non-usage-sensitive metadata may proceed with impactAnalysis. Product PATCH never mutates order, lot, price, cost, inventory, or accounting records and does not expose or edit product attributes, documents, or economics.

- 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 live RBAC 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Attach a product document link

Creates a link-based 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. This creates one Document row and one idempotency identity only. It does not upload binary files, mutate Product.sdsFile, change hazmat fields, delete documents, or touch inventory, lots, pricing, costs, orders, or accounting records.

- 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 live RBAC 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

Bounded supplier finder. Requires q or exact externalId and does not support broad sync or updatedSince.

- 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)
- 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Attach a supplier document link

Creates a link-based 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. This creates one Document row and one idempotency identity only. It does not upload binary files, mutate the supplier, delete documents, or touch tax, payment, ledger, order, inventory, or accounting records.

- 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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 live RBAC 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: The fail-closed rate limit 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 live RBAC 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. Requires exact identifiers, customerId, a bounded orderedAt window, or paired updatedAtFrom/updatedAtTo for parent-row changed-record discovery. This is not a cursor sync or export endpoint.

- Auth: Bearer API key
- Required scope: orders:read
- Parameters: orderNo (query, optional, string); customerOrderNo (query, optional, string); externalId (query, optional, string); customerId (query, optional, string uuid); orderedAtFrom (query, optional, string date-time); orderedAtTo (query, optional, string date-time); updatedAtFrom (query, optional, string date-time); updatedAtTo (query, optional, string date-time); status (query, optional, enum: DRAFT, CONFIRMED, SHIPPED, DELIVERED, COMPLETED, VOID); limit (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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Get a sales-order commercial document

Returns read-only sales-order header, line items, and stored totals. Keys with commercial-economics:read also receive public SO/PO costs, cost basis, profit, margin, and totals explanations where source data supports them. No mutation or cost cascade occurs.

- Auth: Bearer API key
- Required scope: orders:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Sales-order commercial document. 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 live RBAC 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: The fail-closed rate limit 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. Requires exact identifiers, supplierId, linkedOrderId, a bounded dueAt window, or paired updatedAtFrom/updatedAtTo for parent-row changed-record discovery. This is not a cursor sync or export endpoint.

- Auth: Bearer API key
- Required scope: purchase-orders:read
- Parameters: orderNo (query, optional, string); externalId (query, optional, string); supplierId (query, optional, string uuid); linkedOrderId (query, optional, string uuid); dueAtFrom (query, optional, string date-time); dueAtTo (query, optional, string date-time); updatedAtFrom (query, optional, string date-time); updatedAtTo (query, optional, string date-time); status (query, optional, enum: DRAFT, CONFIRMED, COMPLETED, VOID); limit (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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Get a purchase-order commercial document

Returns read-only purchase-order header, line items, stored totals, and supplier-owned PO costs. Keys with commercial-economics:read also receive base/landed line amounts, all safe PO cost rows, and totals participation metadata. No receiving, AP, GL, or mutation occurs.

- Auth: Bearer API key
- Required scope: purchase-orders:read
- Parameters: id (path, required, string uuid)
- Success responses: 200: Purchase-order commercial document. 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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Read current or historical Cost Book entries

Returns exact Decimal Cost Book truth. Current view is bounded and authoritative; history requires an exact productId + supplierId lane. Public access uses 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: view (query, optional, string); asOf (query, optional, string); productId (query, optional, string); supplierId (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 live RBAC 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: The fail-closed rate limit service is temporarily unavailable. Retry after the indicated delay. application/json object with error

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

Create or supersede verified Cost Book truth

Creates one direct or constructed verified Cost Book entry. dryRun=true returns write readiness without writing. Execute requires expectedCurrentEntryId and Idempotency-Key. Writes use integration provenance and are final governed truth, not proposals.

- 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: 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
