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

# Duro

> Product lifecycle management (PLM) API for hardware teams — query and manage components, BOM assemblies, libraries, and engineering change orders through a single GraphQL endpoint.

Product lifecycle management (PLM) API for hardware teams — query and manage components, BOM assemblies, libraries, and engineering change orders through a single GraphQL endpoint. Best for agents that read part data and revisions, create or update components, or drive change-management workflows (open change orders, add affected items). Unlike heavyweight PLMs like Arena or Windchill, Duro is an out-of-the-box, API-first PLM; every request is a POST to [https://api.durohub.com/graphql](https://api.durohub.com/graphql) with the operation in the body — see the routing hint for header and operation shapes.

9 example endpoints available through Lava's AI Gateway. See the [Duro API docs](https://docs.durohub.com/) for full documentation.

<Warning>This provider requires your own credentials — connect your API key or OAuth account before use.</Warning>

<Info>This is a **catch-all provider** — any valid URL under `https://api.durohub.com/graphql` is supported. Duro PLM GraphQL API. Single endpoint: POST [https://api.durohub.com/graphql](https://api.durohub.com/graphql). Auth is supplied automatically from the connected credential (x-api-key + x-organization + x-library; a key is scoped to one org/library). Each request POSTs a JSON body with a "query" string (the GraphQL document) and an optional "variables" object. Resources are namespaced: component.findOne(id), component.findAll(filter, pagination), component.create(inputs), component.update(inputs), component.delete(ids); changeOrders.get(filter, pagination), changeOrders.create(input), changeOrders.addItems(changeOrderId, input), changeOrders.submitForReview(id); plus libraries. Pagination is Relay cursor: pass pagination with first:N and after:cursor, then read the edges/node list alongside pageInfo (hasNextPage, endCursor) and totalCount (changeOrders nests these under a connection field). Filtering: component.findAll accepts a filter with categoryType (PART, ASSEMBLY, or DOCUMENT), name, cpns, statusId, and isArchived. Updates support optimistic concurrency via expectedVersion. Errors: GraphQL always returns HTTP 200 — failures appear in the top-level errors array with extensions.code (FORBIDDEN, or RATE\_LIMITED with extensions.retryAfter seconds). Component delete is permanent; prefer update with isArchived:true to archive. See [https://docs.durohub.com/](https://docs.durohub.com/) for the full reference. The endpoints below are curated examples.</Info>

## Endpoints

### List the libraries available to the connected key. Use as an auth/connectivity check (the "hello world" query) and to confirm the library slug.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', { body: {"query":"query Libraries { libraries { id name slug } }"} });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"query Libraries { libraries { id name slug } }"}'
    ```
  </Tab>
</Tabs>

### List components with optional filtering and Relay cursor pagination. Filter by categoryType (PART, ASSEMBLY, DOCUMENT), name, cpns, status, or archived flag.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "query ListComponents { component { findAll(filter: { categoryType: PART, isArchived: false }, pagination: { first: 20 }) { edges { node { id name revisionValue version status { name } category { name } } } pageInfo { hasNextPage endCursor } } } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"query ListComponents { component { findAll(filter: { categoryType: PART, isArchived: false }, pagination: { first: 20 }) { edges { node { id name revisionValue version status { name } category { name } } } pageInfo { hasNextPage endCursor } } } }"}'
    ```
  </Tab>
</Tabs>

### Fetch a single component by its UUID, including revision, status, category, and timestamps.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "query GetComponent { component { findOne(id: \"550e8400-e29b-41d4-a716-446655440000\") { id name description revisionValue version state status { name color } category { name type } createdAt updatedAt } } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"query GetComponent { component { findOne(id: \"550e8400-e29b-41d4-a716-446655440000\") { id name description revisionValue version state status { name color } category { name type } createdAt updatedAt } } }"}'
    ```
  </Tab>
</Tabs>

### Create one or more components. name is required; categoryId, description, revisionValue, eid, and attributeValues are optional. Returns the created components with their assigned revisionValue and version.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "mutation CreateComponent($inputs: [CreateComponentInput!]!) { component { create(inputs: $inputs) { id name revisionValue version createdAt } } }",
    "variables": {
      "inputs": [
        {
          "name": "Capacitor 100uF",
          "description": "Electrolytic capacitor, 100uF 25V",
          "categoryId": "part-category-uuid"
        }
      ]
    }
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"mutation CreateComponent($inputs: [CreateComponentInput!]!) { component { create(inputs: $inputs) { id name revisionValue version createdAt } } }","variables":{"inputs":[{"name":"Capacitor 100uF","description":"Electrolytic capacitor, 100uF 25V","categoryId":"part-category-uuid"}]}}'
    ```
  </Tab>
</Tabs>

### Update one or more components by ID. Pass expectedVersion for optimistic concurrency (the update fails with a conflict if the current version differs). Set isArchived: true to archive rather than delete.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "mutation UpdateComponent($inputs: [UpdateComponentInput!]!) { component { update(inputs: $inputs) { id name description version updatedAt } } }",
    "variables": {
      "inputs": [
        {
          "id": "123e4567-e89b-12d3-a456-426614174000",
          "name": "Motor Assembly v2",
          "expectedVersion": 1
        }
      ]
    }
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"mutation UpdateComponent($inputs: [UpdateComponentInput!]!) { component { update(inputs: $inputs) { id name description version updatedAt } } }","variables":{"inputs":[{"id":"123e4567-e89b-12d3-a456-426614174000","name":"Motor Assembly v2","expectedVersion":1}]}}'
    ```
  </Tab>
</Tabs>

### Permanently delete components by their IDs. This is irreversible — prefer archiving via update (isArchived: true) when you may need the component later.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "mutation DeleteComponents { component { delete(ids: [\"123e4567-e89b-12d3-a456-426614174000\"]) } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"mutation DeleteComponents { component { delete(ids: [\"123e4567-e89b-12d3-a456-426614174000\"]) } }"}'
    ```
  </Tab>
</Tabs>

### List change orders with optional filtering (by status, resolution, assignee, or stage) and cursor pagination. Results are wrapped in a `connection { edges { node } }` envelope.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "query GetChangeOrders { changeOrders { get(filter: { status: [DRAFT, OPEN] }, pagination: { first: 20 }) { connection { edges { node { id sequentialId name status resolution createdAt createdBy { firstName lastName email } } } pageInfo { hasNextPage endCursor } } totalCount } } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"query GetChangeOrders { changeOrders { get(filter: { status: [DRAFT, OPEN] }, pagination: { first: 20 }) { connection { edges { node { id sequentialId name status resolution createdAt createdBy { firstName lastName email } } } pageInfo { hasNextPage endCursor } } totalCount } } }"}'
    ```
  </Tab>
</Tabs>

### Create a change order in DRAFT status. Returns its sequentialId plus the configured approval stages and content fields. Add affected components next with addItems.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "mutation CreateChangeOrder { changeOrders { create(input: { name: \"ECO-2024-001: Update Motor Specifications\", description: \"Updating motor torque specifications to meet new performance requirements\" }) { id sequentialId name status resolution stages { id name order decisionMethod } createdAt } } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"mutation CreateChangeOrder { changeOrders { create(input: { name: \"ECO-2024-001: Update Motor Specifications\", description: \"Updating motor torque specifications to meet new performance requirements\" }) { id sequentialId name status resolution stages { id name order decisionMethod } createdAt } } }"}'
    ```
  </Tab>
</Tabs>

### Add components (the affected items) to a change order, each pinned to a component version. Use updateProposalsForItems afterward to set the proposed revision/status.

**POST** `https://api.durohub.com/graphql` — Free

<Tabs>
  <Tab title="SDK">
    ```typescript theme={null}
    const data = await lava.gateway('https://api.durohub.com/graphql', {
      body: {
    "query": "mutation AddItems { changeOrders { addItems(changeOrderId: \"123e4567-e89b-12d3-a456-426614174000\", input: { items: [{ id: \"component-uuid-1\", version: 3 }] }) { id itemId itemVersion proposedRevision proposedStatusId } } }"
    },
    });
    ```
  </Tab>

  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST "https://api.lava.so/v1/forward?u=https%3A%2F%2Fapi.durohub.com%2Fgraphql" \
      -H "Authorization: Bearer $LAVA_SECRET_KEY" \
      -H "Content-Type: application/json" \
      -d '{"query":"mutation AddItems { changeOrders { addItems(changeOrderId: \"123e4567-e89b-12d3-a456-426614174000\", input: { items: [{ id: \"component-uuid-1\", version: 3 }] }) { id itemId itemVersion proposedRevision proposedStatusId } } }"}'
    ```
  </Tab>
</Tabs>

## Next Steps

<CardGroup cols={2}>
  <Card title="All Providers" icon="grid" href="/gateway/supported-providers">
    Browse all supported AI providers
  </Card>

  <Card title="Forward Proxy" icon="route" href="/gateway/forward-proxy">
    Learn how to construct proxy URLs and authenticate requests
  </Card>
</CardGroup>
