> For the complete documentation index, see [llms.txt](https://docs.durohub.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.durohub.com/core-concepts/change-orders.md).

# Change Orders

Change Orders (COs) are the backbone of engineering change management in PLM systems. They provide a structured, auditable process for proposing, reviewing, and implementing modifications to your components. Whether you're updating a component specification, revising a BOM, or making design changes, change orders ensure proper review, approval, and traceability.

## Overview

### What Are Change Orders?

A Change Order is a formal request to modify one or more components in your library. It captures:

* **What's changing**: The affected components and proposed modifications
* **Why it's changing**: Description and justification for the change
* **Who approves it**: Reviewers assigned to evaluate the change
* **The outcome**: Whether the change was approved, rejected, or withdrawn

### Change Order Lifecycle

Change orders follow a defined lifecycle:

```
DRAFT ──────► OPEN ──────► RESOLVED ──────► CLOSED
  │             │              │
  │             ▼              │
  │         ON_HOLD            │
  │             │              │
  └─────────────┴──────────────┘
            (reset)
```

| Status     | Description                                                                                |
| ---------- | ------------------------------------------------------------------------------------------ |
| `DRAFT`    | Initial state. The CO can be modified freely—add items, assign reviewers, fill in details. |
| `OPEN`     | Submitted for review. Reviewers evaluate and make decisions.                               |
| `ON_HOLD`  | Temporarily paused, awaiting additional information.                                       |
| `RESOLVED` | Review complete. Check the `resolution` field for the outcome.                             |
| `CLOSED`   | Final state. The change order is complete.                                                 |

### Resolution Types

When a change order is resolved, the `resolution` field indicates the outcome:

| Resolution  | Description                       |
| ----------- | --------------------------------- |
| `PENDING`   | Still awaiting reviewer decisions |
| `APPROVED`  | All required approvals obtained   |
| `REJECTED`  | Rejected by one or more reviewers |
| `WITHDRAWN` | Creator withdrew the change order |

### Change Order Types

Every change order carries a **type** (`coType`), a classification drawn from the industry-standard `CoType` enum. The type is fixed when the change order is created — there is no mutation to change it afterward — and is returned on every change order as the non-null `coType` field.

| Value | Meaning                      |
| ----- | ---------------------------- |
| `ECO` | Engineering Change Order     |
| `MCO` | Manufacturing Change Order   |
| `DCO` | Documentation Change Order   |
| `ECR` | Engineering Change Request   |
| `MCR` | Manufacturing Change Request |
| `DCR` | Documentation Change Request |
| `ECN` | Engineering Change Notice    |
| `MCN` | Manufacturing Change Notice  |
| `DCN` | Documentation Change Notice  |

For most types the value is **classification metadata only** — it records intent and drives reporting, but does not change how the change order behaves.

{% hint style="info" %}
**`DCO` is the exception — it changes behavior.** A Documentation Change Order is revision-frozen: approving and closing it never bumps the revision of any component in the change order, regardless of whether the component was modified. Consequently a DCO also **cannot change a component's `status` or `revision`** — attempting either is rejected (`DCO_STATUS_CHANGE_NOT_ALLOWED`, `DCO_REVISION_CHANGE_NOT_ALLOWED`). Use a DCO for documentation-only updates that need visibility across your team without triggering a revision bump.
{% endhint %}

**How the type is chosen at creation:**

1. If you pass an explicit `coType` in the create input, that value is used.
2. Otherwise, when creating from a template, the template's `defaultCoType` is used.
3. Otherwise (a template-less change order with no `coType`), the type defaults to `ECO`.

When a template is used, the resolved type must be one of the template's allowed `coTypes` — otherwise creation fails with `CO_TYPE_NOT_ALLOWED`. Templates declare their allowed types in the workflow YAML; see [Change Order Workflows → Declaring Allowed Change Order Types](/library-configuration/change-order-workflows.md#declaring-allowed-change-order-types).

***

## Required Headers

All change order operations require these headers:

```bash
curl 'https://api.durohub.com/graphql' \
  -H 'x-api-key: YOUR_API_KEY' \
  -H 'x-organization: @your-org' \
  -H 'x-library: @your-org/your-library' \
  -H 'Content-Type: application/json' \
  -d '{"query": "..."}'
```

| Header           | Required | Description                                    |
| ---------------- | -------- | ---------------------------------------------- |
| `x-api-key`      | Yes      | Your API authentication token                  |
| `x-organization` | Yes      | Organization slug (e.g., `@acme-corp`)         |
| `x-library`      | Yes      | Library slug (e.g., `@acme-corp/main-library`) |
| `Content-Type`   | Yes      | Must be `application/json`                     |

***

## Querying Change Orders

### List Change Orders

Query change orders with optional filtering and pagination:

```graphql
query GetChangeOrders {
  changeOrders {
    get(
      filter: { status: [DRAFT, OPEN] }
      pagination: { first: 20 }
    ) {
      connection {
        edges {
          node {
            id
            sequentialId
            name
            description
            status
            resolution
            createdAt
            createdBy {
              firstName
              lastName
              email
            }
            currentStage {
              name
              decisionState
            }
          }
        }
        pageInfo {
          hasNextPage
          endCursor
        }
      }
      totalCount
    }
  }
}
```

### Filter Options

| Field           | Type                       | Description                                                   |
| --------------- | -------------------------- | ------------------------------------------------------------- |
| `ids`           | `[ID!]`                    | Filter by specific UUIDs                                      |
| `sequentialIds` | `[Int!]`                   | Filter by sequential IDs (e.g., CO-001, CO-002)               |
| `status`        | `[ChangeOrderStatus!]`     | Filter by status (DRAFT, OPEN, RESOLVED, CLOSED, ON\_HOLD)    |
| `resolution`    | `[ChangeOrderResolution!]` | Filter by resolution (PENDING, APPROVED, REJECTED, WITHDRAWN) |
| `assigneeId`    | `ID`                       | Filter by assigned reviewer                                   |
| `stageId`       | `ID`                       | Filter by current stage                                       |

***

## Getting Available Templates

Before creating a change order, query the available templates for your library:

```graphql
query GetTemplates {
  changeOrders {
    getTemplates {
      id
      name
      config
      coTypes
      defaultCoType
      createdAt
    }
  }
}
```

Templates define the workflow structure including:

* Custom fields to capture change information
* Approval stages and their decision methods
* Default reviewers and notification settings
* The [change order types](#change-order-types) the template allows (`coTypes`) and its default (`defaultCoType`)

{% hint style="info" %}
`coTypes` and `defaultCoType` are only populated for templates authored against schema version `1.1` or later. Legacy (`1.0`) templates return `null` for both fields and behave as if they allow only `ECO`. See the [Workflow YAML Reference](/library-configuration/change-order-workflow-reference.md#change-order-types).
{% endhint %}

See [Change Order Workflows](/library-configuration/change-order-workflows.md) for creating custom templates.

***

## Creating a Change Order

Create a new change order in `DRAFT` status:

```graphql
mutation CreateChangeOrder {
  changeOrders {
    create(input: {
      name: "ECO-2024-001: Update Motor Specifications"
      description: "Updating motor torque specifications to meet new performance requirements"
      coType: ECO
    }) {
      id
      sequentialId
      name
      description
      status
      resolution
      coType
      stages {
        id
        name
        order
        decisionMethod
      }
      contents {
        id
        name
        label
        isRequired
      }
      createdAt
    }
  }
}
```

The `coType` input is optional. When omitted, the server resolves the type from the template's `defaultCoType`, falling back to `ECO` for template-less change orders. If you pass a `coType` that the template does not allow, creation fails with `CO_TYPE_NOT_ALLOWED`. See [Change Order Types](#change-order-types) for the full list of values and the behavior of `DCO`.

### Example Response

```json
{
  "data": {
    "changeOrders": {
      "create": {
        "id": "123e4567-e89b-12d3-a456-426614174000",
        "sequentialId": 42,
        "name": "ECO-2024-001: Update Motor Specifications",
        "description": "Updating motor torque specifications...",
        "status": "DRAFT",
        "resolution": "PENDING",
        "coType": "ECO",
        "stages": [
          {
            "id": "stage-uuid-1",
            "name": "Engineering Review",
            "order": 1,
            "decisionMethod": "MAJORITY"
          },
          {
            "id": "stage-uuid-2",
            "name": "Quality Approval",
            "order": 2,
            "decisionMethod": "UNANIMOUS"
          }
        ],
        "contents": [
          {
            "id": "content-uuid-1",
            "name": "change_category",
            "label": "Change Category",
            "isRequired": true
          }
        ],
        "createdAt": "2024-01-15T10:30:00Z"
      }
    }
  }
}
```

***

## Adding Items to a Change Order

Add components to the change order to indicate what will be modified:

```graphql
mutation AddItems {
  changeOrders {
    addItems(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        items: [
          { id: "component-uuid-1", version: 3 }
          { id: "component-uuid-2", version: 1 }
        ]
      }
    ) {
      id
      itemId
      itemVersion
      proposedRevision
      proposedStatusId
    }
  }
}
```

### Setting Proposed Changes

You can specify what the component will become after the change order is approved:

```graphql
mutation UpdateProposals {
  changeOrders {
    updateProposalsForItems(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        items: [
          {
            itemId: "component-uuid-1"
            revision: "2.A"
            statusId: "released-status-uuid"
          }
        ]
      }
    ) {
      id
      itemId
      proposedRevision
      proposedStatusId
    }
  }
}
```

### Removing Items

```graphql
mutation RemoveItems {
  changeOrders {
    removeItems(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        itemIds: ["component-uuid-2"]
      }
    ) {
      id
      itemId
    }
  }
}
```

***

## Attaching Documents to a Change Order

Attach supporting documents to a change order in `DRAFT` status. Unlike items, which have dedicated mutations, documents are managed through `submitDraft`:

### Adding Documents

```graphql
mutation AttachDocuments {
  changeOrders {
    submitDraft(
      id: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        documents: {
          add: [
            { componentId: "document-uuid-1", componentVersion: 1 }
            { componentId: "document-uuid-2", componentVersion: 3 }
          ]
        }
      }
    ) {
      id
      documents {
        id
        componentId
        componentVersion
      }
    }
  }
}
```

### Removing Documents

```graphql
mutation RemoveDocuments {
  changeOrders {
    submitDraft(
      id: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        documents: {
          remove: ["document-link-uuid-1"]
        }
      }
    ) {
      id
      documents {
        id
      }
    }
  }
}
```

{% hint style="info" %}
The `remove` field takes **document link IDs** (the `id` of each `ChangeOrderDocumentLink`), not component IDs. Query the change order's `documents` field to get these IDs.
{% endhint %}

***

## Setting Custom Field Values

If your template defines custom fields (like "Impact Assessment" or "Change Category"), set their values:

```graphql
mutation SetContentValue {
  changeOrders {
    setContentValue(
      contentId: "content-uuid-1"
      input: {
        values: ["design"]
      }
    ) {
      id
      name
      label
      values
    }
  }
}
```

{% hint style="info" %}
The `contentId` comes from the `contents` array in the change order response. Each content field has a unique ID.
{% endhint %}

***

## Adding Reviewers to Stages

Assign users to review each approval stage:

```graphql
mutation AddReviewers {
  changeOrders {
    addReviewersToStages(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        stages: [
          {
            stageId: "stage-uuid-1"
            userIds: ["user-uuid-1", "user-uuid-2"]
          }
          {
            stageId: "stage-uuid-2"
            userIds: ["user-uuid-3"]
          }
        ]
      }
    ) {
      id
      stages {
        id
        name
        reviewers {
          id
          user {
            firstName
            lastName
            email
          }
          decisionState
        }
      }
    }
  }
}
```

### Removing Reviewers

```graphql
mutation RemoveReviewers {
  changeOrders {
    removeReviewersFromStages(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        stages: [
          {
            stageId: "stage-uuid-1"
            userIds: ["user-uuid-2"]
          }
        ]
      }
    ) {
      id
      stages {
        id
        reviewers {
          id
        }
      }
    }
  }
}
```

***

## Configuring Stage Decision Methods

Each stage can use different approval logic:

| Method      | Description                       |
| ----------- | --------------------------------- |
| `UNANIMOUS` | All reviewers must approve        |
| `MAJORITY`  | More than 50% must approve        |
| `MINIMUM`   | At least N reviewers must approve |

```graphql
mutation UpdateDecisionMethods {
  changeOrders {
    updateDecisionMethodsForStages(
      changeOrderId: "123e4567-e89b-12d3-a456-426614174000"
      input: {
        stages: [
          {
            stageId: "stage-uuid-1"
            decisionMethod: MAJORITY
          }
          {
            stageId: "stage-uuid-2"
            decisionMethod: MINIMUM
            decisionMinimumCount: 2
          }
        ]
      }
    ) {
      id
      stages {
        id
        name
        decisionMethod
      }
    }
  }
}
```

***

## Submitting for Review

When your change order is ready, submit it for review. This transitions the status from `DRAFT` to `OPEN`:

```graphql
mutation SubmitForReview {
  changeOrders {
    submitForReview(id: "123e4567-e89b-12d3-a456-426614174000") {
      id
      status
      resolution
      currentStage {
        name
        decisionState
      }
    }
  }
}
```

{% hint style="warning" %}
**Before Submitting**: Ensure all required content fields are populated and at least one item is added. Use the `canSubmit` and `cannotSubmitReasons` fields to check readiness.
{% endhint %}

### Check Submission Readiness

```graphql
query CheckReadiness {
  changeOrders {
    get(filter: { ids: ["123e4567-e89b-12d3-a456-426614174000"] }) {
      connection {
        edges {
          node {
            id
            canSubmit
            cannotSubmitReasons
          }
        }
      }
    }
  }
}
```

***

## Making Review Decisions

Reviewers approve or reject their assigned stages:

### Approving

```graphql
mutation ApproveStage {
  changeOrders {
    updateReviewDecision(
      stageId: "stage-uuid-1"
      input: {
        decisionState: APPROVED
        note: "Reviewed and approved. All specifications meet requirements."
      }
    ) {
      id
      decisionState
      note
      decidedAt
      user {
        firstName
        lastName
      }
    }
  }
}
```

### Rejecting

```graphql
mutation RejectStage {
  changeOrders {
    updateReviewDecision(
      stageId: "stage-uuid-1"
      input: {
        decisionState: REJECTED
        note: "Missing thermal analysis documentation. Please add before resubmission."
      }
    ) {
      id
      decisionState
      note
      decidedAt
    }
  }
}
```

{% hint style="info" %}
When a stage meets its decision criteria (based on the decision method), the change order automatically progresses to the next stage or resolves.
{% endhint %}

***

## Completing Change Orders

### Closing an Approved Change Order

If `approvalRouterOption` is `MANUAL_CLOSE`, you need to explicitly close the change order:

```graphql
mutation CloseChangeOrder {
  changeOrders {
    close(id: "123e4567-e89b-12d3-a456-426614174000") {
      id
      status
      resolution
    }
  }
}
```

### Withdrawing a Change Order

The creator can withdraw a change order at any time:

```graphql
mutation WithdrawChangeOrder {
  changeOrders {
    withdraw(id: "123e4567-e89b-12d3-a456-426614174000") {
      id
      status
      resolution
    }
  }
}
```

### Resetting to Draft

Reset a change order back to `DRAFT` to make modifications and resubmit:

```graphql
mutation ResetChangeOrder {
  changeOrders {
    reset(id: "123e4567-e89b-12d3-a456-426614174000") {
      id
      status
      resolution
    }
  }
}
```

{% hint style="info" %}
**When to Reset**: Use reset after a rejection to modify the change order and resubmit, or after withdrawal if you want to revive the change order.
{% endhint %}

***

## Complete Workflow Example

Here's a complete example showing the typical happy path:

```javascript
const { GraphQLClient } = require('graphql-request');

const client = new GraphQLClient('https://api.durohub.com/graphql', {
  headers: {
    'x-api-key': process.env.DURO_API_KEY,
    'x-organization': '@acme-corp',
    'x-library': '@acme-corp/main-library',
  },
});

async function createAndSubmitChangeOrder() {
  // Step 1: Create the change order
  const createResult = await client.request(`
    mutation CreateCO($input: CreateChangeOrderInput!) {
      changeOrders {
        create(input: $input) {
          id
          stages { id name }
          contents { id name }
        }
      }
    }
  `, {
    input: {
      name: "ECO-2024-001: Motor Specification Update",
      description: "Update torque specs for Model X motor"
    }
  });

  const coId = createResult.changeOrders.create.id;
  const stageId = createResult.changeOrders.create.stages[0].id;
  console.log(`Created CO: ${coId}`);

  // Step 2: Add items (components)
  await client.request(`
    mutation AddItems($coId: ID!, $input: AddItemsInput!) {
      changeOrders {
        addItems(changeOrderId: $coId, input: $input) {
          id
        }
      }
    }
  `, {
    coId,
    input: {
      items: [{ id: "component-uuid", version: 1 }]
    }
  });
  console.log("Items added");

  // Step 3: Attach reference documents
  await client.request(`
    mutation AttachDocuments($id: ID!, $input: SubmitDraftInput!) {
      changeOrders {
        submitDraft(id: $id, input: $input) {
          id
          documents { id componentId componentVersion }
        }
      }
    }
  `, {
    id: coId,
    input: {
      documents: {
        add: [
          { componentId: "test-report-uuid", componentVersion: 1 },
          { componentId: "spec-sheet-uuid", componentVersion: 2 }
        ]
      }
    }
  });
  console.log("Reference documents attached");

  // Step 4: Add reviewers
  await client.request(`
    mutation AddReviewers($coId: ID!, $input: AddReviewersToStagesInput!) {
      changeOrders {
        addReviewersToStages(changeOrderId: $coId, input: $input) {
          id
        }
      }
    }
  `, {
    coId,
    input: {
      stages: [{ stageId, userIds: ["reviewer-uuid"] }]
    }
  });
  console.log("Reviewers added");

  // Step 5: Submit for review
  const submitResult = await client.request(`
    mutation Submit($id: ID!) {
      changeOrders {
        submitForReview(id: $id) {
          status
          resolution
        }
      }
    }
  `, { id: coId });
  console.log(`Status: ${submitResult.changeOrders.submitForReview.status}`);

  // Step 6: Reviewer approves (would be done by the reviewer)
  await client.request(`
    mutation Approve($stageId: ID!, $input: UpdateReviewDecisionInput!) {
      changeOrders {
        updateReviewDecision(stageId: $stageId, input: $input) {
          decisionState
        }
      }
    }
  `, {
    stageId,
    input: {
      decisionState: "APPROVED",
      note: "Approved - specifications verified"
    }
  });
  console.log("Approved!");

  // Step 7: Close the change order
  const closeResult = await client.request(`
    mutation Close($id: ID!) {
      changeOrders {
        close(id: $id) {
          status
          resolution
        }
      }
    }
  `, { id: coId });
  console.log(`Final status: ${closeResult.changeOrders.close.status}`);
}

createAndSubmitChangeOrder().catch(console.error);
```

***

## Handling Rejection

When a change order is rejected:

1. **Review the rejection notes** to understand what needs to change
2. **Reset to DRAFT** using the `reset` mutation
3. **Make necessary modifications** (update items, content, etc.)
4. **Resubmit** using `submitForReview`

```graphql
# After rejection, reset and fix
mutation ResetAndFix {
  changeOrders {
    reset(id: "co-uuid") {
      status  # Returns to DRAFT
    }
  }
}

# Make your changes, then resubmit
mutation Resubmit {
  changeOrders {
    submitForReview(id: "co-uuid") {
      status
      resolution
    }
  }
}
```

***

## Best Practices

### Planning

* **Use descriptive names**: Include an identifier (e.g., "ECO-2024-001") and brief description
* **Choose the right template**: Select a template that matches your change type
* **Complete all required fields**: Fill out custom content fields before submission

### Items and Scope

* **Include all affected components**: Add every component that will be modified
* **Specify correct versions**: Reference the specific version being changed
* **Keep scope focused**: One change order should address one logical change

### Review Process

* **Add appropriate reviewers**: Ensure all required stakeholders are included
* **Provide context in notes**: When approving or rejecting, include detailed notes
* **Check `canSubmit` before submitting**: Avoid submission errors

### Workflow Management

* **Don't skip states**: Follow the proper lifecycle transitions
* **Close completed COs promptly**: Move approved COs to CLOSED when changes are implemented
* **Document rejection reasons**: Provide actionable feedback when rejecting

***

## Next Steps

* [**Documents**](/core-concepts/documents.md): Learn about document management and how documents relate to change orders
* [**Change Order Workflows**](/library-configuration/change-order-workflows.md): Create custom templates with multi-stage approvals
* [**Change Order Workflow Reference**](/library-configuration/change-order-workflow-reference.md): Complete YAML specification
* [**Change Order Validations**](/library-configuration/change-order-validations.md): Implement validation rules
* [**Webhooks**](/advanced-topics/webhooks.md): Get notified when change orders are updated


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.durohub.com/core-concepts/change-orders.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
