> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# PTC Windchill (Windchill REST Services)

> Client-mode REST API connector for PTC Windchill: read parts, multi-level BOMs and component lists, part attachments and CAD drawings, documents, problem reports and change notices, and turn a quality event into a problem report or variance, through Windchill REST Services (OData v4)

Technical Preview

## Overview

[PTC Windchill](https://www.ptc.com/en/products/windchill) is the PLM system that owns parts, BOMs, CAD documents, drawings and change processes for many manufacturers. This connector lets shop-floor logic on MQTT look up a part and its released structure, build a kitting list from the multi-level components report, fetch part attachments and drawings for a work instruction screen, watch change notices, and raise a problem report or variance from a quality event, without custom code.

**PtcWindchillApi** (`PtcWindchillRestApi.lot`) is one client connector on `https://YOUR_WINDCHILL_SERVER` with 17 events: 1 CSRF token call, 14 reads and 2 writes. No event updates, deletes, revises or checks out anything.

> [!NOTE]
>
> Windchill REST Services (WRS) is an OData v4 API under `/Windchill/servlet/odata/<Domain>/`. This template uses the Product Management (`ProdMgmt`), Document Management (`DocMgmt`), Change Management (`ChangeMgmt`) and common (`PTC`) domains. Every server publishes its own `$metadata` per domain (for example `/Windchill/servlet/odata/ProdMgmt/$metadata`), which also lists your custom types and soft attributes. The events follow PTC's public [Windchill REST Services 2.7 guide](https://support.ptc.com/help/windchill_rest_services/r2.7/en/windchill_rest_services/examples_lp_prodmgmt.html). To add another entity set or action, copy an event and change the path.

## Server host

Windchill is installed per customer, or runs as Windchill+ (SaaS). Replace `YOUR_WINDCHILL_SERVER` with your Windchill web server host, with no trailing slash, and add the port when it does not use 443. To pin a domain version, insert it after `odata/` (for example `/Windchill/servlet/odata/v5/ProdMgmt/`); without a version the server uses its default.

## Authentication

> [!WARNING]
>
> WRS calls act as the Windchill user behind the credentials. Keep them in Hub secrets, map them in with `GET SECRET`, and never publish the authorization value or the CSRF nonce on a topic other clients can read.

* **HTTP Basic (default).** Windchill relies on web server authentication. Store the full header value, `Basic <base64 of user:password>`, as the secret `WINDCHILL_AUTHORIZATION` and send it as `"authorization"` in every payload.
* **OAuth 2.0.** When Windchill is set up as an OAuth resource server (client credentials for machine clients), send `"authorization": "Bearer <access token>"` and change every endpoint prefix from `/Windchill/servlet/odata/` to `/Windchill/oauth/servlet/odata/` ([WRS OAuth authorization](https://support.ptc.com/help/windchill_rest_services/r2.7/en/windchill_rest_services/oauth_for_wrs.html)). Getting the token from your authorization server is outside this connector.
* **CSRF nonce.** Every `POST` needs the header `CSRF_NONCE`. Publish on `mes/ptc-windchill/csrf-token/get`, read `NonceValue` from the reply and send it as `"nonce"`. The nonce belongs to the server session, so refresh it when POST calls start failing.

## Payload conventions

* `id` is a Windchill object ID, for example `OR:wt.part.WTPart:191559` (find it with `QueryParts` by number).
* `filter` is an OData `$filter` expression, **URL-encoded** because the broker puts it straight into the URL: `Number%20eq%20'0000000007'` or `startswith(Number,'00')`. Set the request header `PTC-WildcardSearch: true` (add it to the event) to use `*` wildcards.
* `request` is the JSON body sent unchanged on `POST` events.

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "filter": "Number%20eq%20'0000000007'",
  "top": "10"
}
```

## Events

| Event | Method | Path (after `/Windchill/servlet/odata/`) | Topic | What it does |
| - | - | - | - | - |
| `GetCsrfToken` | GET | `PTC/GetCSRFToken()` | `mes/ptc-windchill/csrf-token/get` | CSRF nonce (NonceKey CSRF\_NONCE, NonceValue). Send NonceValue as nonce on every POST event |
| `QueryParts` | GET | `ProdMgmt/Parts?$filter={value.json.filter}&$top={value.json.top}` | `mes/ptc-windchill/parts/query` | Parts by OData $filter (URL-encoded, for example Number eq '...' or startswith(Number,'00')) and $top |
| `GetPart` | GET | `ProdMgmt/Parts('{value.json.id}')?$expand=Uses` | `mes/ptc-windchill/part/get` | One part by OID with its part usage links (Uses) |
| `GetPartStructure` | POST | `ProdMgmt/Parts('{value.json.id}')/PTC.ProdMgmt.GetPartStructure?$expand=Components($levels=max)` | `mes/ptc-windchill/part-structure/get` | Multi-level BOM (part structure) of a part with inline NavigationCriteria (config spec, view, plant filters); send \{} for the default filter |
| `GetComponentsReport` | POST | `ProdMgmt/Parts('{value.json.id}')/PTC.ProdMgmt.GetMultiLevelComponentsReport?$select=Quantity,Unit,Name,Number&$expand=Part($select=Identity,Name)` | `mes/ptc-windchill/components-report/get` | Consolidated multi-level components list (quantity, unit) for kitting and material staging; replaces deprecated GetPartsList |
| `GetPartAttachments` | GET | `ProdMgmt/Parts('{value.json.id}')/Attachments` | `mes/ptc-windchill/part-attachments/get` | Attachments (secondary content: file name, format, download URL) of a part, for work instruction display |
| `GetPartCadDocuments` | GET | `ProdMgmt/Parts('{value.json.id}')/PartDocAssociations?$expand=RelatedCADDoc($select=Identity)` | `mes/ptc-windchill/part-cad-documents/get` | CAD documents and drawings associated with a part |
| `QueryDocuments` | GET | `DocMgmt/Documents?$filter={value.json.filter}&$top={value.json.top}` | `mes/ptc-windchill/documents/query` | Documents by OData \$filter (URL-encoded), for example work instructions by number prefix |
| `GetDocumentStructure` | GET | `DocMgmt/Documents('{value.json.id}')/DocUsageLinks?$expand=DocUsedBy,DocUses` | `mes/ptc-windchill/document-structure/get` | Document structure (usage links to parent and child documents) |
| `ListProblemReports` | GET | `ChangeMgmt/ProblemReports` | `mes/ptc-windchill/problem-reports/list` | All problem reports visible to the user |
| `GetProblemReport` | GET | `ChangeMgmt/ProblemReports('{value.json.id}')` | `mes/ptc-windchill/problem-report/get` | One problem report by OID (state, priority, category) |
| `GetProblemReportAffectedObjects` | GET | `ChangeMgmt/ProblemReports('{value.json.id}')/CIAffectLinks?$expand=AffectedObjects` | `mes/ptc-windchill/problem-report-affected/get` | Affected parts / documents of a problem report |
| `CreateProblemReport` | POST | `ChangeMgmt/ProblemReports` | `mes/ptc-windchill/problem-report/create` | Write. problem report from a quality event, optionally with affected parts ([Changeables@odata.bind](mailto:Changeables@odata.bind)) in the product context |
| `CreateVariance` | POST | `ChangeMgmt/Variances` | `mes/ptc-windchill/variance/create` | Write. variance (deviation / waiver) request, for example to run a lot with an approved deviation |
| `ListChangeRequests` | GET | `ChangeMgmt/ChangeRequests?$expand=AffectedObjects` | `mes/ptc-windchill/change-requests/list` | Change requests with their affected objects |
| `ListChangeNotices` | GET | `ChangeMgmt/ChangeNotices` | `mes/ptc-windchill/change-notices/list` | Change notices (released engineering changes) to flag BOM / routing updates on the shop floor |
| `GetChangeNotice` | GET | `ChangeMgmt/ChangeNotices('{value.json.id}')` | `mes/ptc-windchill/change-notice/get` | One change notice by OID |

Replies arrive on `<topic>/response`.

### Part structure and kitting list

`GetPartStructure` returns the multi-level BOM; `GetComponentsReport` returns one consolidated line per component with total quantity and unit, which suits kitting and line-side staging. Both take a `NavigationCriteria` body (config spec, view, plant filters). Send `{}` to use the default filter, or the ID of a saved filter: `{"NavigationCriteria": {"ID": "OR:wt.filter.NavigationCriteria:..."}}`.

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "id": "OR:wt.part.WTPart:191559",
  "nonce": "<NonceValue from GetCsrfToken>",
  "request": {
    "NavigationCriteria": {
      "ApplicableType": "PTC.ProdMgmt.Part",
      "ApplyToTopLevelObject": true,
      "Centricity": false,
      "ConfigSpecs": [
        {
          "@odata.type": "#PTC.NavCriteria.WTPartStandardConfigSpec",
          "WorkingIncluded": false,
          "View": "Manufacturing"
        }
      ],
      "Filters": [],
      "HideUnresolvedDependents": false,
      "UseDefaultForUnresolved": false
    }
  }
}
```

### Problem report from a quality event

`CreateProblemReport` creates a standalone problem report in a product or library context. Add affected parts with `Changeables@odata.bind`. Category, priority and life cycle values depend on your Change Management setup.

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{
  "authorization": "Basic <base64 user:password>",
  "nonce": "<NonceValue from GetCsrfToken>",
  "request": {
    "Name": "Press 01 dimensional NOK",
    "Description": "Bore diameter out of tolerance on 3 of 20 parts (station 03)",
    "Category": {
      "Value": "DESIGN_ISSUE"
    },
    "IssuePriority": {
      "Value": "HIGH"
    },
    "Context@odata.bind": "Containers('OR:wt.pdmlink.PDMLinkProduct:122008')",
    "Changeables@odata.bind": [
      "Changeables('OR:wt.part.WTPart:122556')"
    ]
  }
}
```

## Connector

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
# Coreflux REST_API template — PTC Windchill (beta): read parts, part structures (multi-level BOM), consolidated
#   component lists, attachments and CAD / drawing associations, query documents, read problem reports, change requests
#   and change notices, and from a quality event create a problem report (with affected parts) or a variance, over
#   Windchill REST Services (WRS, OData v4) at /Windchill/servlet/odata/.
# Hugo catalog #145, Tier 3 (mes). 17 events (2 writes, no PATCH / DELETE). Hand-curated from PTC's public WRS 2.7 help
#   pages cached in openapi-cache/ptc-windchill/ (each server also serves its own $metadata per domain).
# Docs: https://docs.coreflux.org/latest/lot-language/routes/rest-api-apps/ptc-windchill
#
# Host: Windchill is installed per customer (or Windchill+ SaaS). Replace YOUR_WINDCHILL_SERVER with the Windchill web
#   server host (add :port when it does not share 443).
# Auth: HTTP Basic by default: publish "authorization": "Basic <base64 user:password>". OAuth 2.0 sites (Windchill as
#   resource server, client credentials) send "Bearer <token>" and must call /Windchill/oauth/servlet/odata/ instead:
#   replace the endpoint prefix. Keep credentials in Hub secrets.
# CSRF: POST events need "nonce": NonceValue from GetCsrfToken (header CSRF_NONCE). The nonce belongs to the session.
# Payloads: OIDs go in "id" (for example "OR:wt.part.WTPart:191559"); $filter values must be URL-encoded; "request" is
#   the JSON body sent unchanged.
#     QueryParts  {"authorization": "Basic ...", "filter": "Number%20eq%20'0000000007'", "top": "10"}
#

DEFINE ROUTE PtcWindchillApi WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "https://YOUR_WINDCHILL_SERVER"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "true"
        WITH REQUEST_TIMEOUT '60'
        WITH DEFAULT_CONTENT_TYPE "application/json"
        # Smoke: GetCsrfToken -> QueryParts (Number) -> GetPart -> GetPartStructure -> GetPartAttachments -> ListChangeNotices. Never commit passwords or tokens.
    # CSRF nonce (NonceKey CSRF_NONCE, NonceValue). Send NonceValue as nonce on every POST event
    ADD EVENT GetCsrfToken
        WITH SOURCE_TOPIC "mes/ptc-windchill/csrf-token/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/csrf-token/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/PTC/GetCSRFToken()"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Parts by OData $filter (URL-encoded, for example Number eq '...' or startswith(Number,'00')) and $top
    ADD EVENT QueryParts
        WITH SOURCE_TOPIC "mes/ptc-windchill/parts/query"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/parts/query/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts?$filter={value.json.filter}&$top={value.json.top}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # One part by OID with its part usage links (Uses)
    ADD EVENT GetPart
        WITH SOURCE_TOPIC "mes/ptc-windchill/part/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/part/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts('{value.json.id}')?$expand=Uses"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Multi-level BOM (part structure) of a part with inline NavigationCriteria (config spec, view, plant filters); send {} for the default filter
    ADD EVENT GetPartStructure
        WITH SOURCE_TOPIC "mes/ptc-windchill/part-structure/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/part-structure/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts('{value.json.id}')/PTC.ProdMgmt.GetPartStructure?$expand=Components($levels=max)"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "Content-Type" "application/json"
            ADD "CSRF_NONCE" "{value.json.nonce}"
        WITH BODY "{value.json.request}"
    # Consolidated multi-level components list (quantity, unit) for kitting and material staging; replaces deprecated GetPartsList
    ADD EVENT GetComponentsReport
        WITH SOURCE_TOPIC "mes/ptc-windchill/components-report/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/components-report/get/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts('{value.json.id}')/PTC.ProdMgmt.GetMultiLevelComponentsReport?$select=Quantity,Unit,Name,Number&$expand=Part($select=Identity,Name)"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "Content-Type" "application/json"
            ADD "CSRF_NONCE" "{value.json.nonce}"
        WITH BODY "{value.json.request}"
    # Attachments (secondary content: file name, format, download URL) of a part, for work instruction display
    ADD EVENT GetPartAttachments
        WITH SOURCE_TOPIC "mes/ptc-windchill/part-attachments/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/part-attachments/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts('{value.json.id}')/Attachments"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # CAD documents and drawings associated with a part
    ADD EVENT GetPartCadDocuments
        WITH SOURCE_TOPIC "mes/ptc-windchill/part-cad-documents/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/part-cad-documents/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ProdMgmt/Parts('{value.json.id}')/PartDocAssociations?$expand=RelatedCADDoc($select=Identity)"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Documents by OData $filter (URL-encoded), for example work instructions by number prefix
    ADD EVENT QueryDocuments
        WITH SOURCE_TOPIC "mes/ptc-windchill/documents/query"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/documents/query/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/DocMgmt/Documents?$filter={value.json.filter}&$top={value.json.top}"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Document structure (usage links to parent and child documents)
    ADD EVENT GetDocumentStructure
        WITH SOURCE_TOPIC "mes/ptc-windchill/document-structure/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/document-structure/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/DocMgmt/Documents('{value.json.id}')/DocUsageLinks?$expand=DocUsedBy,DocUses"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # All problem reports visible to the user
    ADD EVENT ListProblemReports
        WITH SOURCE_TOPIC "mes/ptc-windchill/problem-reports/list"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/problem-reports/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ProblemReports"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # One problem report by OID (state, priority, category)
    ADD EVENT GetProblemReport
        WITH SOURCE_TOPIC "mes/ptc-windchill/problem-report/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/problem-report/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ProblemReports('{value.json.id}')"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Affected parts / documents of a problem report
    ADD EVENT GetProblemReportAffectedObjects
        WITH SOURCE_TOPIC "mes/ptc-windchill/problem-report-affected/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/problem-report-affected/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ProblemReports('{value.json.id}')/CIAffectLinks?$expand=AffectedObjects"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # WRITE: problem report from a quality event, optionally with affected parts (Changeables@odata.bind) in the product context
    ADD EVENT CreateProblemReport
        WITH SOURCE_TOPIC "mes/ptc-windchill/problem-report/create"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/problem-report/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ProblemReports"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "Content-Type" "application/json"
            ADD "CSRF_NONCE" "{value.json.nonce}"
        WITH BODY "{value.json.request}"
    # WRITE: variance (deviation / waiver) request, for example to run a lot with an approved deviation
    ADD EVENT CreateVariance
        WITH SOURCE_TOPIC "mes/ptc-windchill/variance/create"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/variance/create/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/Variances"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
            ADD "Content-Type" "application/json"
            ADD "CSRF_NONCE" "{value.json.nonce}"
        WITH BODY "{value.json.request}"
    # Change requests with their affected objects
    ADD EVENT ListChangeRequests
        WITH SOURCE_TOPIC "mes/ptc-windchill/change-requests/list"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/change-requests/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ChangeRequests?$expand=AffectedObjects"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # Change notices (released engineering changes) to flag BOM / routing updates on the shop floor
    ADD EVENT ListChangeNotices
        WITH SOURCE_TOPIC "mes/ptc-windchill/change-notices/list"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/change-notices/list/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ChangeNotices"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    # One change notice by OID
    ADD EVENT GetChangeNotice
        WITH SOURCE_TOPIC "mes/ptc-windchill/change-notice/get"
        WITH DESTINATION_TOPIC "mes/ptc-windchill/change-notice/get/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/Windchill/servlet/odata/ChangeMgmt/ChangeNotices('{value.json.id}')"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
```

## Example actions

These actions refresh the CSRF nonce, look up a part by number from a station, request a kitting list when an order is released, and turn a press quality event into a problem report. Set `internal/ptc-windchill/product-context` to the product container OID (for example `OR:wt.pdmlink.PDMLinkProduct:122008`) first.

```lot theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ACTION WcCsrfRefresh
ON EVERY 20 MINUTES DO
    SET "auth" WITH GET SECRET "WINDCHILL_AUTHORIZATION"
    PUBLISH TOPIC "mes/ptc-windchill/csrf-token/get" WITH { "authorization": {auth} }

DEFINE ACTION WcKeepNonce
ON TOPIC "mes/ptc-windchill/csrf-token/get/response" DO
    SET "nonce" WITH (GET JSON "NonceValue" IN PAYLOAD AS STRING)
    KEEP TOPIC "internal/ptc-windchill/nonce" WITH {nonce}

DEFINE ACTION WcPartLookup
ON TOPIC "porto/line1/station03/work-instruction/part-number" DO
    SET "auth" WITH GET SECRET "WINDCHILL_AUTHORIZATION"
    SET "pn" WITH PAYLOAD AS STRING
    PUBLISH TOPIC "mes/ptc-windchill/parts/query" WITH { "authorization": {auth}, "filter": "Number%20eq%20'" + {pn} + "'", "top": "1" }

DEFINE ACTION WcKittingList
ON TOPIC "porto/line1/order/released/part-oid" DO
    SET "auth" WITH GET SECRET "WINDCHILL_AUTHORIZATION"
    SET "nonce" WITH GET TOPIC "internal/ptc-windchill/nonce" AS STRING
    SET "oid" WITH PAYLOAD AS STRING
    PUBLISH TOPIC "mes/ptc-windchill/components-report/get" WITH { "authorization": {auth}, "nonce": {nonce}, "id": {oid}, "request": {} }

DEFINE ACTION WcQualityEventToProblemReport
ON TOPIC "porto/line1/press01/quality-event" DO
    SET "auth" WITH GET SECRET "WINDCHILL_AUTHORIZATION"
    SET "nonce" WITH GET TOPIC "internal/ptc-windchill/nonce" AS STRING
    SET "ctx" WITH GET TOPIC "internal/ptc-windchill/product-context" AS STRING
    SET "title" WITH (GET JSON "title" IN PAYLOAD AS STRING)
    SET "detail" WITH (GET JSON "detail" IN PAYLOAD AS STRING)
    PUBLISH TOPIC "mes/ptc-windchill/problem-report/create" WITH { "authorization": {auth}, "nonce": {nonce}, "request": { "Name": {title}, "Description": {detail}, "Category": { "Value": "OTHER" }, "IssuePriority": { "Value": "HIGH" }, "Context@odata.bind": "Containers('" + {ctx} + "')" } }
```

## Not included

* Updates, check out / check in, revise and delete operations (by policy for a shop-floor template).
* Content upload (three-stage upload to the file vault) and `DownloadContentAsZip` (returns a ZIP stream, not JSON). Use the download URL from `GetPartAttachments` instead.
* Deprecated `GetBOM` and `GetPartsList` actions (replaced by `GetPartStructure` and `GetMultiLevelComponentsReport`).
* Webhooks: Windchill has no generic outbound webhook. Poll `ListChangeNotices`, or push events with Windchill's own event and workflow tooling.

## Status

**Beta, blocked on a live test.** Smoke test on 2026-10-06 05:23 WEST: static 93/93, local mock WRS 17/17, controls 8/8, public PTC help pages 5/5. The ready gate needs an authenticated call against a real Windchill server: `GetCsrfToken` and `QueryParts`, then a `POST` with the nonce, or a broker MQTT round trip. PTC offers no public Windchill sandbox.

To unblock, provide `WC_HOST`, `WC_USER` and `WC_PASSWORD` (a read user, plus create rights on problem reports in a test product for the write test) and `WC_TEST_PART_NUMBER`, then run `python3 smoke_ptc_windchill.py`.

See also the [REST API connectors](/latest/lot-language/routes/rest-api-routes) base page and the [REST API apps catalog](/latest/lot-language/routes/rest-api-apps/index).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.