> 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/getting-started/api-v2-migration.md).

# API v2 Migration Guide

This guide provides comprehensive information for migrating your existing Duro API integrations to API v2. This is a **breaking change** release that introduces a new header-based context system and role-based access control (RBAC).

## Overview

### Why This Change?

The previous API suffered from **inconsistent context handling**:

* Some operations required `libraryId` as a direct parameter
* Others expected it within an `input` object
* Some used `library` (slug) while others used `libraryId` (UUID)
* Organization context was sometimes explicit, sometimes implicit

**API v2 standardizes context through HTTP headers**, eliminating redundancy and providing a cleaner, more predictable interface.

### What's New?

| Feature              | v1 (Legacy)                  | v2 (New)                      |
| -------------------- | ---------------------------- | ----------------------------- |
| Library Context      | Parameter in each operation  | `x-library` header            |
| Organization Context | Parameter in some operations | `x-organization` header       |
| Access Control       | Simple role enum             | Full RBAC with permissions    |
| API Key Scope        | Tied to library at creation  | Must match `x-library` header |

### Key Benefits

1. **Consistency**: Every operation uses the same context mechanism
2. **Cleaner Queries**: No redundant library/organization IDs in every request
3. **Fine-grained Permissions**: New RBAC system enables granular access control
4. **Better Security**: Permission checks on every request
5. **Simplified Client Code**: Set headers once, use everywhere

***

## Migration Checklist

Before starting your migration:

* [ ] Identify all API calls in your codebase
* [ ] Update your HTTP client to send required headers
* [ ] Review the [Breaking Changes](#breaking-changes) section
* [ ] Update input objects to remove deprecated fields
* [ ] Test with API v2 endpoint
* [ ] Update error handling for new permission errors

***

## Required Headers

All authenticated API requests **must** include these headers:

### `x-organization` (Required)

Identifies the organization context. Accepts either:

* Organization UUID: `550e8400-e29b-41d4-a716-446655440000`
* Organization slug: `@my-company`

```http
x-organization: @my-company
```

### `x-library` (Required for library-scoped operations)

Identifies the library context. Accepts either:

* Library UUID: `660e8400-e29b-41d4-a716-446655440000`
* Library slug path: `@my-company/product-library`

```http
x-library: @my-company/product-library
```

### `x-api-key` (For API authentication)

Your API key for authentication (unchanged from v1).

```http
x-api-key: your-api-key-here
```

{% hint style="warning" %}
**Important**: Your API key is scoped to a specific library. The `x-library` header **must match** the library your API key was created for. Mismatched headers will result in `403 Forbidden` errors.
{% endhint %}

### Complete Request Example

```bash
curl -X POST https://api.durohub.com/graphql \
  -H "Content-Type: application/json" \
  -H "x-api-key: your-api-key" \
  -H "x-organization: @acme-corp" \
  -H "x-library: @acme-corp/hardware-library" \
  -d '{"query": "{ component { findAll { edges { node { id name } } } } }"}'
```

***

## Complete Breaking Changes Reference

This section provides **exhaustive tables** of every change grouped by category.

***

### 1. Input Objects: Removed Fields

Fields removed from input types - context now provided via headers.

| Input Type                         | Removed Field(s)                             | Header to Use    |
| ---------------------------------- | -------------------------------------------- | ---------------- |
| `BulkCreateReusableInstancesInput` | `libraryId: String!`                         | `x-library`      |
| `CategoryFilterInput`              | `libraryId: String`                          | `x-library`      |
| `ComponentFilterInput`             | `libraryId: String`, `libraryIds: [String!]` | `x-library`      |
| `ConfigFilterInput`                | `libraryId: String`                          | `x-library`      |
| `ConfigureLibraryInput`            | `libraryId: String!`                         | `x-library`      |
| `CreateApiKeyInput`                | `libraryId: String!`                         | `x-library`      |
| `CreateComponentInput`             | `libraryId: ID!`                             | `x-library`      |
| `CreateLibraryInput`               | `organizationId: String!`                    | `x-organization` |
| `CreateValidationRuleInput`        | `libraryId: ID!`                             | `x-library`      |
| `CreateWebhookInput`               | `libraryId: String!`                         | `x-library`      |
| `CustomStatusFilterInput`          | `libraryId: String`                          | `x-library`      |
| `DeactivateApiKeyInput`            | `libraryId: String!`                         | `x-library`      |
| `FindAllApiKeyForUserInput`        | `libraryId: String`                          | `x-library`      |
| `FindOneApiKeyForUserInput`        | `libraryId: String`                          | `x-library`      |
| `IdsFilterInput`                   | `libraryId: String`                          | `x-library`      |
| `IsPinnedComponentInput`           | `libraryId: ID!`                             | `x-library`      |
| `NextRevisionInput`                | `libraryId: String!`                         | `x-library`      |
| `PinComponentsInput`               | `libraryId: ID!`                             | `x-library`      |
| `RevokeAllApiKeysForUserInput`     | `libraryId: String!`                         | `x-library`      |
| `RotateApiKeyInput`                | `libraryId: String!`                         | `x-library`      |
| `SetLibraryConfigInput`            | `libraryId: String!`                         | `x-library`      |
| `UnPinComponentsInput`             | `libraryId: ID!`                             | `x-library`      |
| `UpdateApiKeyInput`                | `libraryId: String!`                         | `x-library`      |
| `UpdateComponentInput`             | `libraryId: ID`                              | `x-library`      |
| `ValidateApiKeyInput`              | `libraryId: String!`                         | `x-library`      |
| `ValidateRevisionValueInput`       | `libraryId: String!`                         | `x-library`      |
| `ValidationRuleFilter`             | `libraryId: ID`                              | `x-library`      |
| `NaturalLanguageSearchInput`       | `libraryIds: [String!]`                      | `x-library`      |

***

### 2. Input Objects: Modified Fields

Fields changed or deprecated in input types.

| Input Type        | Field          | v1 (Legacy)                              | v2 (New)                                            |
| ----------------- | -------------- | ---------------------------------------- | --------------------------------------------------- |
| `BulkInviteInput` | `role`         | `role: OrganizationRoleEnum!` (required) | `role: OrganizationRoleEnum` (optional, deprecated) |
| `BulkInviteInput` | `roleId`       | *(not present)*                          | `roleId: String` (deprecated, use `orgRoleId`)      |
| `BulkInviteInput` | `orgRoleId`    | *(not present)*                          | `orgRoleId: String` (new, preferred)                |
| `BulkInviteInput` | `libraryRoles` | *(not present)*                          | `libraryRoles: [LibraryRoleAssignment!]` (new)      |

***

### 3. Root Query Changes

Changes to top-level Query fields.

| Query               | v1 Signature                                              | v2 Signature                                      | Change Type              |
| ------------------- | --------------------------------------------------------- | ------------------------------------------------- | ------------------------ |
| `altiumHealthCheck` | `altiumHealthCheck: AltiumHealthCheckResponse!`           | *(removed)*                                       | **REMOVED**              |
| `customStatuses`    | `customStatuses(filter: CustomStatusFilterInput!)`        | `customStatuses(filter: CustomStatusFilterInput)` | Filter now optional      |
| `configs`           | `configs(filter: ConfigFilterInput!)`                     | `configs(filter: ConfigFilterInput)`              | Filter now optional      |
| `configSyncStatus`  | `configSyncStatus(libraryId: String!, type: ConfigType!)` | `configSyncStatus(type: ConfigType!)`             | `libraryId` removed      |
| `libraries`         | `libraries(organizationId: ID!)`                          | `libraries`                                       | `organizationId` removed |
| `roles`             | *(not present)*                                           | `roles: RoleQueryNamespace!`                      | **NEW**                  |

***

### 4. Root Mutation Changes

Changes to top-level Mutation fields.

| Mutation                  | v1 Signature                                              | v2 Signature                    | Change Type                        |
| ------------------------- | --------------------------------------------------------- | ------------------------------- | ---------------------------------- |
| `generateAltiumViewerUrl` | `generateAltiumViewerUrl(input: GenerateViewerUrlInput!)` | *(removed)*                     | **REMOVED**                        |
| `membership`              | `membership: MembershipMutationNamespace!`                | *(removed from root)*           | Moved to `organization.membership` |
| `roles`                   | *(not present)*                                           | `roles: RoleMutationNamespace!` | **NEW**                            |

***

### 5. Namespace Query Method Changes

Changes to methods within query namespaces.

#### `CategoryQueryNamespace`

| Method    | v1 Signature                                           | v2 Signature                           |
| --------- | ------------------------------------------------------ | -------------------------------------- |
| `findAll` | `findAll(libraryId: ID!, filter: CategoryFilterInput)` | `findAll(filter: CategoryFilterInput)` |

#### `ChangeOrdersQueryOperations`

| Method         | v1 Signature                                                                        | v2 Signature                                                       |
| -------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| `get`          | `get(library: String, filter: ChangeOrderFilterInput, pagination: PaginationInput)` | `get(filter: ChangeOrderFilterInput, pagination: PaginationInput)` |
| `getTemplates` | `getTemplates(library: String)`                                                     | `getTemplates`                                                     |

#### `ComponentQueryNamespace`

| Method                   | v1 Signature                                                                                    | v2 Signature                                                                    |
| ------------------------ | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `findOne`                | `findOne(id: ID!): Component!`                                                                  | `findOne(id: ID!): Component` (now nullable)                                    |
| `validateAttributes`     | `validateAttributes(categoryId: ID!, attributeValues: [AttributeValueInput!]!, libraryId: ID!)` | `validateAttributes(categoryId: ID!, attributeValues: [AttributeValueInput!]!)` |
| `getAllPinnedComponents` | `getAllPinnedComponents(libraryId: String!)`                                                    | `getAllPinnedComponents`                                                        |

#### `IdentifierQueryNamespace`

| Method                     | v1 Signature                                                                                                       | v2 Signature                                                                                   |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `validateOverrides`        | `validateOverrides(libraryId: String!, overrides: [IdElementOverrideInput!]!)`                                     | `validateOverrides(overrides: [IdElementOverrideInput!]!)`                                     |
| `validateCompleteOverride` | `validateCompleteOverride(libraryId: String!, overrides: [IdElementOverrideInput!]!, componentId: String)`         | `validateCompleteOverride(overrides: [IdElementOverrideInput!]!, componentId: String)`         |
| `overridePermissions`      | `overridePermissions(libraryId: String!)`                                                                          | `overridePermissions`                                                                          |
| `reusableGroupInstances`   | `reusableGroupInstances(libraryId: String!, configId: String!, groupName: String!, filters: [ElementValueInput!])` | `reusableGroupInstances(configId: String!, groupName: String!, filters: [ElementValueInput!])` |
| `validateFreeformOverride` | `validateFreeformOverride(libraryId: String!, value: String!, componentId: String)`                                | `validateFreeformOverride(value: String!, componentId: String)`                                |

#### `OrganizationQueryNamespace`

| Method             | v1 Signature                                                             | v2 Signature                                                 |
| ------------------ | ------------------------------------------------------------------------ | ------------------------------------------------------------ |
| `invitations`      | `invitations(filter: InvitationFilterInput): [OrganizationInvitation!]!` | `invitations(filter: InvitationFilterInput): [Invitation!]!` |
| `discoverByDomain` | *(not present)*                                                          | `discoverByDomain: Organization`                             |

#### `WebhookQueryNamespace`

| Method    | v1 Signature                         | v2 Signature |
| --------- | ------------------------------------ | ------------ |
| `findAll` | `findAll(input: FindWebhooksInput!)` | `findAll`    |

***

### 6. Namespace Mutation Method Changes

Changes to methods within mutation namespaces.

#### `ChangeOrdersMutationOperations`

| Method           | v1 Signature                                                   | v2 Signature                                  |
| ---------------- | -------------------------------------------------------------- | --------------------------------------------- |
| `create`         | `create(input: CreateChangeOrderInput!, libraryId: ID)`        | `create(input: CreateChangeOrderInput!)`      |
| `createTemplate` | `createTemplate(input: CreateTemplateInput!, library: String)` | `createTemplate(input: CreateTemplateInput!)` |

#### `ConfigMutationNamespace`

| Method                            | v1 Signature                                          | v2 Signature                      |
| --------------------------------- | ----------------------------------------------------- | --------------------------------- |
| `manuallyProcessCategoriesConfig` | `manuallyProcessCategoriesConfig(libraryId: String!)` | `manuallyProcessCategoriesConfig` |

#### `OrganizationMutationNamespace`

| Method              | v1 Signature                                                        | v2 Signature                               |
| ------------------- | ------------------------------------------------------------------- | ------------------------------------------ |
| `membership`        | `membership(organizationId: String!): MembershipMutationNamespace!` | `membership: MembershipMutationNamespace!` |
| `declineInvitation` | *(not present)*                                                     | `declineInvitation(id: String!): Boolean!` |

#### `MembershipMutationNamespace`

| Method                | v1 Signature                                           | v2 Signature                                                      |
| --------------------- | ------------------------------------------------------ | ----------------------------------------------------------------- |
| `update`              | `update(userId: String!, role: OrganizationRoleEnum!)` | `update(userId: String!, roleId: String!)`                        |
| `updateLibraryAccess` | *(not present)*                                        | `updateLibraryAccess(input: UpdateLibraryAccessInput!): Boolean!` |
| `removeOrgRole`       | *(not present)*                                        | `removeOrgRole(userId: String!): Boolean!`                        |

***

### 7. Enum Changes

#### `OrganizationRoleEnum`

| v1 Values       | v2 Values    | Notes                      |
| --------------- | ------------ | -------------------------- |
| `SITE_ADMIN`    | `SITE_ADMIN` | Unchanged                  |
| `ADMIN`         | `ADMIN`      | Unchanged                  |
| `USER`          | `EDITOR`     | **RENAMED**                |
| `APPROVER`      | *(removed)*  | **REMOVED** - use `EDITOR` |
| `REVIEWER`      | `REVIEWER`   | Unchanged                  |
| *(not present)* | `VIEWER`     | **NEW**                    |
| `SUPPLIER`      | `SUPPLIER`   | Unchanged                  |

***

### 8. Type Changes

#### Renamed Types

| v1 Type                  | v2 Type      | Notes                     |
| ------------------------ | ------------ | ------------------------- |
| `OrganizationInvitation` | `Invitation` | Enhanced with RBAC fields |

#### Modified Types

| Type               | Change                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------ |
| `Organization`     | Added `roles: [Role!]!` field                                                              |
| `Organization`     | Changed `invitations` return type to `[Invitation!]!`                                      |
| `OrganizationRole` | Added `rbacRole: Role`, `hasDirectOrgRole: Boolean!`, `libraryAccess: [LibraryAccessDto!]` |
| `Library`          | Added `stats: LibraryStatsType` field                                                      |

***

### 9. Removed Types (Complete List)

| Removed Type                | Category                    |
| --------------------------- | --------------------------- |
| `AltiumHealthCheckResponse` | Altium integration          |
| `ViewerUrlResponse`         | Altium integration          |
| `GenerateViewerUrlInput`    | Altium integration          |
| `OrganizationInvitation`    | Renamed to `Invitation`     |
| `FindWebhooksInput`         | Webhooks (no longer needed) |

***

### 10. New Types (Complete List)

| New Type                   | Category    | Purpose                                |
| -------------------------- | ----------- | -------------------------------------- |
| `Role`                     | RBAC        | Defines a role with permissions        |
| `Permission`               | RBAC        | Individual permission definition       |
| `RoleType`                 | RBAC        | Enum: `ORG`, `LIBRARY`                 |
| `RoleMutationNamespace`    | RBAC        | Mutations for role management          |
| `RoleQueryNamespace`       | RBAC        | Queries for role management            |
| `CreateRoleInput`          | RBAC        | Input for creating custom roles        |
| `UpdateRoleInput`          | RBAC        | Input for updating roles               |
| `DeleteRoleInput`          | RBAC        | Input for deleting roles               |
| `Invitation`               | Invitations | Replaces `OrganizationInvitation`      |
| `LibraryAccessDto`         | RBAC        | Library-specific role info             |
| `LibraryRoleAssignment`    | RBAC        | Input for assigning library roles      |
| `LibraryStatsType`         | Library     | Component/user counts                  |
| `UpdateLibraryAccessInput` | RBAC        | Input for updating user library access |

***

### 11. Code Examples (Before/After)

Quick reference examples for common operations.

#### Components

```graphql
# v1 - Creating a component
mutation {
  component {
    create(inputs: [{ name: "Widget", libraryId: "lib-uuid", categoryId: "cat-uuid" }]) {
      id
    }
  }
}

# v2 - libraryId removed from input, use x-library header
mutation {
  component {
    create(inputs: [{ name: "Widget", categoryId: "cat-uuid" }]) {
      id
    }
  }
}
```

#### Change Orders

```graphql
# v1 - Querying change orders
query {
  changeOrders {
    get(library: "@company/lib", filter: { status: [OPEN] }) {
      connection { edges { node { id } } }
    }
  }
}

# v2 - library parameter removed
query {
  changeOrders {
    get(filter: { status: [OPEN] }) {
      connection { edges { node { id } } }
    }
  }
}
```

#### Libraries

```graphql
# v1 - Listing libraries
query {
  libraries(organizationId: "org-uuid") {
    id
    name
  }
}

# v2 - organizationId removed, use x-organization header
query {
  libraries {
    id
    name
  }
}
```

#### Membership

```graphql
# v1 - Updating user role
mutation {
  organization {
    membership(organizationId: "org-uuid") {
      update(userId: "user-uuid", role: ADMIN) { id }
    }
  }
}

# v2 - organizationId removed, role changed to roleId
mutation {
  organization {
    membership {
      update(userId: "user-uuid", roleId: "role-uuid") { id }
    }
  }
}
```

***

## Role-Based Access Control (RBAC)

API v2 introduces a comprehensive RBAC system that replaces the simple role enum approach.

### Key Concepts

1. **Permissions**: Granular capabilities like `components.create`, `change_orders.approve`
2. **Roles**: Collections of permissions (e.g., Editor, Viewer, Admin)
3. **Role Types**: Organization-level (`ORG`) or Library-level (`LIBRARY`)
4. **Hierarchical Resolution**: Library roles override organization roles for specific libraries

### Role Hierarchy

| Level             | Description                                      |
| ----------------- | ------------------------------------------------ |
| Organization Role | Default permissions for all libraries in the org |
| Library Role      | Override permissions for a specific library      |

**Example**: A user with Org Editor role but Library Viewer role for "Engineering Library" will have:

* Editor permissions in all other libraries
* Viewer (read-only) permissions in Engineering Library

### Legacy Role Mapping

If you were using the legacy `OrganizationRoleEnum`, here's how roles map:

| Legacy Enum  | New System Role | Permissions                         |
| ------------ | --------------- | ----------------------------------- |
| `SITE_ADMIN` | Site Admin      | Full system access (admin)          |
| `ADMIN`      | Admin           | Full organization access (admin)    |
| `USER`       | **Editor**      | Create, edit, approve change orders |
| `APPROVER`   | *Removed*       | Use Editor or Reviewer              |
| `REVIEWER`   | **Viewer**      | Read-only access                    |
| `SUPPLIER`   | Supplier        | Limited external access             |

{% hint style="info" %}
The `USER` role has been renamed to `EDITOR` to better reflect its capabilities. The `APPROVER` role has been removed - use `EDITOR` for users who need to approve change orders.
{% endhint %}

### New RBAC Queries

```graphql
# Get all available permissions
query {
  roles {
    allPermissions {
      id
      name
      description
      resource
      action
    }
  }
}

# Get a role by ID
query {
  roles {
    findById(id: "role-uuid") {
      id
      name
      description
      type
      isAdmin
      isSystemRole
      permissions {
        id
        name
      }
    }
  }
}
```

### Permission Categories

| Resource        | Actions                                                                                             |
| --------------- | --------------------------------------------------------------------------------------------------- |
| `components`    | `create`, `read`, `update`, `delete`, `revision.create`                                             |
| `assemblies`    | `create`, `read`, `update`, `delete`                                                                |
| `change_orders` | `create`, `read`, `update`, `delete`, `submit`, `approve`, `reject`, `release`, `withdraw`, `reset` |
| `library`       | `read`, `settings.update`, `categories.manage`, `statuses.manage`, `features.manage`                |
| `organization`  | `read`, `settings.update`, `users.read`, `users.invite`, `users.remove`, `users.update_role`        |
| `roles`         | `read`, `create`, `update`, `delete`, `assign`                                                      |
| `comments`      | `create`, `read`, `update`, `delete`, `moderate`                                                    |

### Permission Errors

API v2 will return `403 Forbidden` with detailed error codes when permission checks fail:

```json
{
  "errors": [
    {
      "message": "You do not have permission to perform this action",
      "extensions": {
        "code": "FORBIDDEN",
        "requiredPermission": "components.create"
      }
    }
  ]
}
```

***

## Invitation System Changes

### Type Rename

The `OrganizationInvitation` type has been renamed to `Invitation` and enhanced with RBAC support:

```graphql
# v2 Invitation type
type Invitation {
  id: String!
  email: String!
  roleId: String!        # New: references RBAC role
  role: Role!            # New: full role details
  invitedById: String!
  invitedBy: User!
  accepted: Boolean!
  organization: Organization
}
```

### Bulk Invite Changes

```graphql
# v1 (Legacy)
mutation {
  organization {
    bulkInvite(input: {
      emails: ["user@example.com"]
      organizationId: "org-uuid"
      role: ADMIN
    }) {
      successful { email }
    }
  }
}

# v2 (New) - role is deprecated, use orgRoleId or libraryRoles
mutation {
  organization {
    bulkInvite(input: {
      emails: ["user@example.com"]
      organizationId: "org-uuid"
      orgRoleId: "editor-role-uuid"
      libraryRoles: [
        { libraryId: "lib-uuid", roleName: "Viewer" }
      ]
    }) {
      successful { email }
    }
  }
}
```

***

## Efficient Migration Strategy

### Step 1: Update HTTP Client Configuration

Configure your HTTP client to automatically include context headers:

```javascript
// JavaScript/TypeScript example
const client = new GraphQLClient('https://api.durohub.com/graphql', {
  headers: {
    'x-api-key': process.env.DURO_API_KEY,
    'x-organization': '@my-company',
    'x-library': '@my-company/my-library',
  },
});
```

```python
# Python example
import requests

session = requests.Session()
session.headers.update({
    'x-api-key': os.environ['DURO_API_KEY'],
    'x-organization': '@my-company',
    'x-library': '@my-company/my-library',
    'Content-Type': 'application/json',
})
```

### Step 2: Search and Replace Input Objects

Use these regex patterns to find affected code:

```regex
# Find libraryId in input objects
libraryId\s*[:=]\s*["']?[^,}\s]+["']?

# Find library parameter in queries
\(library\s*[:=]

# Find organizationId in mutations
organizationId\s*[:=]
```

### Step 3: Update Query/Mutation Calls

1. Remove `libraryId` parameters from all input objects
2. Remove `library` and `libraryId` arguments from query/mutation calls
3. Ensure headers are set before making requests

### Step 4: Handle New Error Responses

Update error handling to recognize permission errors:

```javascript
try {
  const result = await client.request(query);
} catch (error) {
  if (error.response?.errors?.[0]?.extensions?.code === 'FORBIDDEN') {
    const requiredPermission = error.response.errors[0].extensions.requiredPermission;
    console.error(`Missing permission: ${requiredPermission}`);
  }
}
```

### Step 5: Test Thoroughly

1. Test all CRUD operations for components
2. Test change order workflows
3. Test configuration updates
4. Verify webhook functionality
5. Test with different user roles

***

## FAQ

### Q: Can I use both v1 and v2 patterns?

**A**: No. The v2 schema removes the parameters entirely. You must update all calls.

### Q: What if I access multiple libraries?

**A**: Change the `x-library` header for each request. Most HTTP clients support per-request header overrides.

### Q: How do I get my organization/library slugs?

**A**: View your URL in Duro: `durohub.com/org/@org-slug/libs/library-slug`. The slugs are the `@org-slug` and `library-slug` portions.

### Q: My API key was created for a specific library. Do I need a new one?

**A**: No, existing API keys continue to work. Just ensure your `x-library` header matches the library your key was created for.

### Q: What happens if headers are missing?

**A**: You'll receive a `400 Bad Request` error indicating which headers are required.

***

## Support

If you encounter issues during migration:

1. Check the [Error Handling](/advanced-topics/error-handling.md) guide
2. Review the GraphQL Playground at `https://api.durohub.com/graphql`
3. Contact support at <support@durolabs.co>

***

## Next Steps

* Explore the [GraphQL Playground](https://api.durohub.com/graphql) with the new schema
* Update your [Webhooks](/advanced-topics/webhooks.md) configuration if needed
* Review the complete permission list in your organization's Settings > Roles & Permissions


---

# 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/getting-started/api-v2-migration.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.
