> For the complete documentation index, see [llms.txt](https://docs.imerit.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.imerit.net/api/docs/models.md).

# Models

## The ErrorResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ErrorResponse":{"type":"object","properties":{"status":{"type":"string","enum":["fail","error"]},"message":{"type":"string"}}}}}}
```

## The MessageResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"MessageResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}
```

## The ProjectListItem object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ProjectListItem":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"organization":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The Project object

````json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Project":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["ango","pct","iframe"],"default":"ango"},"owner":{"type":"string","description":"Owner email"},"organization":{"type":"string","description":"Organization ID"},"categorySchema":{"$ref":"#/components/schemas/CategorySchema"},"stages":{"type":"array","items":{"$ref":"#/components/schemas/Stage"}},"assignedTo":{"type":"array","items":{"$ref":"#/components/schemas/Assignee"}},"batches":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}},"queueVersion":{"type":"number"},"assetCount":{"type":"integer"},"benchmarkEnabled":{"type":"boolean"},"benchmarkRatio":{"type":"number"},"instructions":{"type":"string","description":"Instructions URL"},"ocrLanguage":{"type":"string"},"idleTimeout":{"type":"number","description":"Idle timeout in seconds"},"projectPlugins":{"type":"object"},"pluginPresets":{"type":"array","items":{"type":"object"}},"errorCodesEnabled":{"type":"boolean"},"errorSchema":{"type":"object"},"exportStorageId":{"type":"string"},"exportStorageBucket":{"type":"string"},"exportStoragePath":{"type":"string"},"exportStorageEnabled":{"type":"boolean"},"taskSkipEnabled":{"type":"boolean"},"unassignSkippedTask":{"type":"boolean"},"gcSyncEnabled":{"type":"boolean"},"pctConfig":{"$ref":"#/components/schemas/PctConfig"},"role":{"type":"string","description":"Caller's role on this project (present on GET /project/{projectId} only)","enum":["Manager","Lead","Labeler","Reviewer"]},"deleted":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CategorySchema":{"type":"object","description":"Label configuration schema that defines the annotation tools, classifications, and relations for a project.\nThis schema determines what annotation types are available to users and how they can label assets.\n\n**Note:** Schema structure varies between Ango and PCT projects.\n- Ango projects: Use standard annotation tools (bounding-box, polygon, etc.)\n- PCT projects: Use PCT tool type with markingTools array and nested classifications with PCT-specific fields\n","properties":{"tools":{"type":"array","description":"Array of annotation tools (bounding box, polygon, segmentation, etc.)","items":{"$ref":"#/components/schemas/Tool"}},"classifications":{"type":"array","description":"Array of classification questions (radio, checkbox, dropdown, text, etc.)","items":{"$ref":"#/components/schemas/Classification"}},"relations":{"type":"array","description":"Array of relation types that can connect annotations","items":{"$ref":"#/components/schemas/Relation"}}}},"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}},"Stage":{"type":"object","description":"Workflow stage configuration. Different stage types have different properties.\n- Label: Manual annotation stage\n- Review: QA/review stage\n- Logic: Conditional routing stage\n- Plugin: ML model integration stage\n- Webhook: External API callback stage\n- Consensus: Multi-annotator agreement stage\n- Hold: Pause stage\n- Start: Entry point (auto-forwards)\n- Complete: Terminal success stage\n- Archive: Terminal archive stage\n","required":["id","type"],"properties":{"id":{"type":"string","description":"Unique identifier for this stage"},"name":{"type":"string","description":"Display name for this stage"},"type":{"type":"string","description":"Type of stage","enum":["Label","Review","Logic","Plugin","Webhook","Consensus","Hold","Start","Complete","Archive"]},"next":{"type":"array","items":{"type":"string"},"description":"Array of next stage IDs (for Logic stages, order matters)"},"position":{"type":"object","description":"Position in workflow diagram UI","properties":{"x":{"type":"number"},"y":{"type":"number"}}},"assignedTo":{"type":"array","description":"Users assigned to work on this stage (Label/Review stages)","items":{"type":"string"}},"rememberAssignee":{"type":"boolean","description":"Auto-assign to previous stage's user (sticky assignment)","default":false},"logic":{"$ref":"#/components/schemas/LogicConfig","description":"Logic routing configuration (Logic stages only)"},"pluginId":{"type":"string","description":"Plugin ID to execute (Plugin stages only)"},"pluginConfig":{"type":"object","description":"Plugin-specific configuration (Plugin stages only)"},"webhook":{"$ref":"#/components/schemas/WebhookConfig","description":"Webhook configuration (Webhook stages only)"},"consensusConfig":{"$ref":"#/components/schemas/ConsensusConfig","description":"Consensus configuration (Consensus stages only)"},"readOnly":{"type":"boolean","description":"Whether this stage is read-only (users can view but not edit)","default":false},"preventRequeue":{"type":"boolean","description":"Prevent tasks from being requeued to this stage","default":false},"autoForward":{"type":"boolean","description":"Automatically advance to next stage without user action","default":true},"consensusId":{"type":"string","description":"Links stage to a consensus stage (used in consensus workflows)"},"consensusDynamic":{"type":"boolean","description":"Dynamic vs static consensus stage","default":false}}},"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}},"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}},"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}},"Assignee":{"type":"object","properties":{"assignee":{"type":"string","description":"User email"},"role":{"type":"string","enum":["Manager","Labeler","Reviewer","Lead"]}}},"Batch":{"type":"object","required":["name"],"properties":{"_id":{"type":"string","description":"Batch ID (auto-generated if not provided)"},"name":{"type":"string","description":"Batch name"}}},"PctConfig":{"type":"object","description":"Configuration specific to Point Cloud Tool (PCT) projects.\nThese settings control how 3D point cloud annotation behaves.\n\nExample:\n```json\n{\n  \"allowOverlapping\": false,\n  \"trackingMultipleSensors\": true,\n  \"segmentationMode\": false\n}\n```\n","properties":{"allowOverlapping":{"type":"boolean","description":"Allow overlapping 3D bounding boxes","default":false},"trackingMultipleSensors":{"type":"boolean","description":"Enable tracking across multiple LiDAR sensors","default":false},"segmentationMode":{"type":"boolean","description":"Enable segmentation mode for point clouds","default":false},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
````

## The ProjectCreateRequest object

````json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ProjectCreateRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","minLength":1,"description":"Project name"},"description":{"type":"string","description":"Project description"},"type":{"type":"string","description":"Project type","enum":["ango","pct","iframe"],"default":"ango"},"pctConfig":{"$ref":"#/components/schemas/PctConfig","description":"Point Cloud Tool configuration (required only when type is \"pct\")"}}},"PctConfig":{"type":"object","description":"Configuration specific to Point Cloud Tool (PCT) projects.\nThese settings control how 3D point cloud annotation behaves.\n\nExample:\n```json\n{\n  \"allowOverlapping\": false,\n  \"trackingMultipleSensors\": true,\n  \"segmentationMode\": false\n}\n```\n","properties":{"allowOverlapping":{"type":"boolean","description":"Allow overlapping 3D bounding boxes","default":false},"trackingMultipleSensors":{"type":"boolean","description":"Enable tracking across multiple LiDAR sensors","default":false},"segmentationMode":{"type":"boolean","description":"Enable segmentation mode for point clouds","default":false},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
````

## The ProjectUpdateRequest object

````json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ProjectUpdateRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string"},"categorySchema":{"$ref":"#/components/schemas/CategorySchema"},"stages":{"type":"array","items":{"$ref":"#/components/schemas/Stage"}},"batches":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}},"benchmarkEnabled":{"type":"boolean"},"benchmarkRatio":{"type":"number"},"instructions":{"type":"string"},"ocrLanguage":{"type":"string"},"idleTimeout":{"type":"number"},"projectPlugins":{"type":"object"},"pluginPresets":{"type":"array","items":{"type":"object"}},"errorCodesEnabled":{"type":"boolean"},"errorSchema":{"type":"object"},"exportStorageId":{"type":"string"},"exportStorageBucket":{"type":"string"},"exportStoragePath":{"type":"string"},"exportStorageEnabled":{"type":"boolean"},"taskSkipEnabled":{"type":"boolean"},"unassignSkippedTask":{"type":"boolean"},"gcSyncEnabled":{"type":"boolean"},"benchmarkCutoff":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"}},"queueCountsEnabled":{"type":"boolean"},"assetBuilderTemplates":{"type":"array","items":{"type":"object"}},"pctConfig":{"$ref":"#/components/schemas/PctConfig","description":"Point Cloud Tool configuration (only for pct project type)"},"deleted":{"type":"boolean"}}},"CategorySchema":{"type":"object","description":"Label configuration schema that defines the annotation tools, classifications, and relations for a project.\nThis schema determines what annotation types are available to users and how they can label assets.\n\n**Note:** Schema structure varies between Ango and PCT projects.\n- Ango projects: Use standard annotation tools (bounding-box, polygon, etc.)\n- PCT projects: Use PCT tool type with markingTools array and nested classifications with PCT-specific fields\n","properties":{"tools":{"type":"array","description":"Array of annotation tools (bounding box, polygon, segmentation, etc.)","items":{"$ref":"#/components/schemas/Tool"}},"classifications":{"type":"array","description":"Array of classification questions (radio, checkbox, dropdown, text, etc.)","items":{"$ref":"#/components/schemas/Classification"}},"relations":{"type":"array","description":"Array of relation types that can connect annotations","items":{"$ref":"#/components/schemas/Relation"}}}},"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}},"Stage":{"type":"object","description":"Workflow stage configuration. Different stage types have different properties.\n- Label: Manual annotation stage\n- Review: QA/review stage\n- Logic: Conditional routing stage\n- Plugin: ML model integration stage\n- Webhook: External API callback stage\n- Consensus: Multi-annotator agreement stage\n- Hold: Pause stage\n- Start: Entry point (auto-forwards)\n- Complete: Terminal success stage\n- Archive: Terminal archive stage\n","required":["id","type"],"properties":{"id":{"type":"string","description":"Unique identifier for this stage"},"name":{"type":"string","description":"Display name for this stage"},"type":{"type":"string","description":"Type of stage","enum":["Label","Review","Logic","Plugin","Webhook","Consensus","Hold","Start","Complete","Archive"]},"next":{"type":"array","items":{"type":"string"},"description":"Array of next stage IDs (for Logic stages, order matters)"},"position":{"type":"object","description":"Position in workflow diagram UI","properties":{"x":{"type":"number"},"y":{"type":"number"}}},"assignedTo":{"type":"array","description":"Users assigned to work on this stage (Label/Review stages)","items":{"type":"string"}},"rememberAssignee":{"type":"boolean","description":"Auto-assign to previous stage's user (sticky assignment)","default":false},"logic":{"$ref":"#/components/schemas/LogicConfig","description":"Logic routing configuration (Logic stages only)"},"pluginId":{"type":"string","description":"Plugin ID to execute (Plugin stages only)"},"pluginConfig":{"type":"object","description":"Plugin-specific configuration (Plugin stages only)"},"webhook":{"$ref":"#/components/schemas/WebhookConfig","description":"Webhook configuration (Webhook stages only)"},"consensusConfig":{"$ref":"#/components/schemas/ConsensusConfig","description":"Consensus configuration (Consensus stages only)"},"readOnly":{"type":"boolean","description":"Whether this stage is read-only (users can view but not edit)","default":false},"preventRequeue":{"type":"boolean","description":"Prevent tasks from being requeued to this stage","default":false},"autoForward":{"type":"boolean","description":"Automatically advance to next stage without user action","default":true},"consensusId":{"type":"string","description":"Links stage to a consensus stage (used in consensus workflows)"},"consensusDynamic":{"type":"boolean","description":"Dynamic vs static consensus stage","default":false}}},"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}},"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}},"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}},"Batch":{"type":"object","required":["name"],"properties":{"_id":{"type":"string","description":"Batch ID (auto-generated if not provided)"},"name":{"type":"string","description":"Batch name"}}},"PctConfig":{"type":"object","description":"Configuration specific to Point Cloud Tool (PCT) projects.\nThese settings control how 3D point cloud annotation behaves.\n\nExample:\n```json\n{\n  \"allowOverlapping\": false,\n  \"trackingMultipleSensors\": true,\n  \"segmentationMode\": false\n}\n```\n","properties":{"allowOverlapping":{"type":"boolean","description":"Allow overlapping 3D bounding boxes","default":false},"trackingMultipleSensors":{"type":"boolean","description":"Enable tracking across multiple LiDAR sensors","default":false},"segmentationMode":{"type":"boolean","description":"Enable segmentation mode for point clouds","default":false},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
````

## The ProjectListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ProjectListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"projects":{"type":"array","items":{"$ref":"#/components/schemas/ProjectListItem"}},"total":{"type":"integer"}}}}},"ProjectListItem":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"organization":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The ProjectResponse object

````json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ProjectResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"project":{"$ref":"#/components/schemas/Project"}}}}},"Project":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["ango","pct","iframe"],"default":"ango"},"owner":{"type":"string","description":"Owner email"},"organization":{"type":"string","description":"Organization ID"},"categorySchema":{"$ref":"#/components/schemas/CategorySchema"},"stages":{"type":"array","items":{"$ref":"#/components/schemas/Stage"}},"assignedTo":{"type":"array","items":{"$ref":"#/components/schemas/Assignee"}},"batches":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}},"queueVersion":{"type":"number"},"assetCount":{"type":"integer"},"benchmarkEnabled":{"type":"boolean"},"benchmarkRatio":{"type":"number"},"instructions":{"type":"string","description":"Instructions URL"},"ocrLanguage":{"type":"string"},"idleTimeout":{"type":"number","description":"Idle timeout in seconds"},"projectPlugins":{"type":"object"},"pluginPresets":{"type":"array","items":{"type":"object"}},"errorCodesEnabled":{"type":"boolean"},"errorSchema":{"type":"object"},"exportStorageId":{"type":"string"},"exportStorageBucket":{"type":"string"},"exportStoragePath":{"type":"string"},"exportStorageEnabled":{"type":"boolean"},"taskSkipEnabled":{"type":"boolean"},"unassignSkippedTask":{"type":"boolean"},"gcSyncEnabled":{"type":"boolean"},"pctConfig":{"$ref":"#/components/schemas/PctConfig"},"role":{"type":"string","description":"Caller's role on this project (present on GET /project/{projectId} only)","enum":["Manager","Lead","Labeler","Reviewer"]},"deleted":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CategorySchema":{"type":"object","description":"Label configuration schema that defines the annotation tools, classifications, and relations for a project.\nThis schema determines what annotation types are available to users and how they can label assets.\n\n**Note:** Schema structure varies between Ango and PCT projects.\n- Ango projects: Use standard annotation tools (bounding-box, polygon, etc.)\n- PCT projects: Use PCT tool type with markingTools array and nested classifications with PCT-specific fields\n","properties":{"tools":{"type":"array","description":"Array of annotation tools (bounding box, polygon, segmentation, etc.)","items":{"$ref":"#/components/schemas/Tool"}},"classifications":{"type":"array","description":"Array of classification questions (radio, checkbox, dropdown, text, etc.)","items":{"$ref":"#/components/schemas/Classification"}},"relations":{"type":"array","description":"Array of relation types that can connect annotations","items":{"$ref":"#/components/schemas/Relation"}}}},"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}},"Stage":{"type":"object","description":"Workflow stage configuration. Different stage types have different properties.\n- Label: Manual annotation stage\n- Review: QA/review stage\n- Logic: Conditional routing stage\n- Plugin: ML model integration stage\n- Webhook: External API callback stage\n- Consensus: Multi-annotator agreement stage\n- Hold: Pause stage\n- Start: Entry point (auto-forwards)\n- Complete: Terminal success stage\n- Archive: Terminal archive stage\n","required":["id","type"],"properties":{"id":{"type":"string","description":"Unique identifier for this stage"},"name":{"type":"string","description":"Display name for this stage"},"type":{"type":"string","description":"Type of stage","enum":["Label","Review","Logic","Plugin","Webhook","Consensus","Hold","Start","Complete","Archive"]},"next":{"type":"array","items":{"type":"string"},"description":"Array of next stage IDs (for Logic stages, order matters)"},"position":{"type":"object","description":"Position in workflow diagram UI","properties":{"x":{"type":"number"},"y":{"type":"number"}}},"assignedTo":{"type":"array","description":"Users assigned to work on this stage (Label/Review stages)","items":{"type":"string"}},"rememberAssignee":{"type":"boolean","description":"Auto-assign to previous stage's user (sticky assignment)","default":false},"logic":{"$ref":"#/components/schemas/LogicConfig","description":"Logic routing configuration (Logic stages only)"},"pluginId":{"type":"string","description":"Plugin ID to execute (Plugin stages only)"},"pluginConfig":{"type":"object","description":"Plugin-specific configuration (Plugin stages only)"},"webhook":{"$ref":"#/components/schemas/WebhookConfig","description":"Webhook configuration (Webhook stages only)"},"consensusConfig":{"$ref":"#/components/schemas/ConsensusConfig","description":"Consensus configuration (Consensus stages only)"},"readOnly":{"type":"boolean","description":"Whether this stage is read-only (users can view but not edit)","default":false},"preventRequeue":{"type":"boolean","description":"Prevent tasks from being requeued to this stage","default":false},"autoForward":{"type":"boolean","description":"Automatically advance to next stage without user action","default":true},"consensusId":{"type":"string","description":"Links stage to a consensus stage (used in consensus workflows)"},"consensusDynamic":{"type":"boolean","description":"Dynamic vs static consensus stage","default":false}}},"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}},"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}},"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}},"Assignee":{"type":"object","properties":{"assignee":{"type":"string","description":"User email"},"role":{"type":"string","enum":["Manager","Labeler","Reviewer","Lead"]}}},"Batch":{"type":"object","required":["name"],"properties":{"_id":{"type":"string","description":"Batch ID (auto-generated if not provided)"},"name":{"type":"string","description":"Batch name"}}},"PctConfig":{"type":"object","description":"Configuration specific to Point Cloud Tool (PCT) projects.\nThese settings control how 3D point cloud annotation behaves.\n\nExample:\n```json\n{\n  \"allowOverlapping\": false,\n  \"trackingMultipleSensors\": true,\n  \"segmentationMode\": false\n}\n```\n","properties":{"allowOverlapping":{"type":"boolean","description":"Allow overlapping 3D bounding boxes","default":false},"trackingMultipleSensors":{"type":"boolean","description":"Enable tracking across multiple LiDAR sensors","default":false},"segmentationMode":{"type":"boolean","description":"Enable segmentation mode for point clouds","default":false},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
````

## The WorkflowUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"WorkflowUpdateRequest":{"type":"object","description":"Request body for updating project workflow stages","required":["stages"],"properties":{"stages":{"type":"array","description":"Complete array of workflow stages for the project","items":{"$ref":"#/components/schemas/Stage"},"minItems":3}}},"Stage":{"type":"object","description":"Workflow stage configuration. Different stage types have different properties.\n- Label: Manual annotation stage\n- Review: QA/review stage\n- Logic: Conditional routing stage\n- Plugin: ML model integration stage\n- Webhook: External API callback stage\n- Consensus: Multi-annotator agreement stage\n- Hold: Pause stage\n- Start: Entry point (auto-forwards)\n- Complete: Terminal success stage\n- Archive: Terminal archive stage\n","required":["id","type"],"properties":{"id":{"type":"string","description":"Unique identifier for this stage"},"name":{"type":"string","description":"Display name for this stage"},"type":{"type":"string","description":"Type of stage","enum":["Label","Review","Logic","Plugin","Webhook","Consensus","Hold","Start","Complete","Archive"]},"next":{"type":"array","items":{"type":"string"},"description":"Array of next stage IDs (for Logic stages, order matters)"},"position":{"type":"object","description":"Position in workflow diagram UI","properties":{"x":{"type":"number"},"y":{"type":"number"}}},"assignedTo":{"type":"array","description":"Users assigned to work on this stage (Label/Review stages)","items":{"type":"string"}},"rememberAssignee":{"type":"boolean","description":"Auto-assign to previous stage's user (sticky assignment)","default":false},"logic":{"$ref":"#/components/schemas/LogicConfig","description":"Logic routing configuration (Logic stages only)"},"pluginId":{"type":"string","description":"Plugin ID to execute (Plugin stages only)"},"pluginConfig":{"type":"object","description":"Plugin-specific configuration (Plugin stages only)"},"webhook":{"$ref":"#/components/schemas/WebhookConfig","description":"Webhook configuration (Webhook stages only)"},"consensusConfig":{"$ref":"#/components/schemas/ConsensusConfig","description":"Consensus configuration (Consensus stages only)"},"readOnly":{"type":"boolean","description":"Whether this stage is read-only (users can view but not edit)","default":false},"preventRequeue":{"type":"boolean","description":"Prevent tasks from being requeued to this stage","default":false},"autoForward":{"type":"boolean","description":"Automatically advance to next stage without user action","default":true},"consensusId":{"type":"string","description":"Links stage to a consensus stage (used in consensus workflows)"},"consensusDynamic":{"type":"boolean","description":"Dynamic vs static consensus stage","default":false}}},"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}},"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}},"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}}}}}
```

## The CategorySchemaUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"CategorySchemaUpdateRequest":{"type":"object","description":"Request body for updating project category schema (annotation tools and classifications)","required":["categorySchema"],"properties":{"categorySchema":{"$ref":"#/components/schemas/CategorySchema"}}},"CategorySchema":{"type":"object","description":"Label configuration schema that defines the annotation tools, classifications, and relations for a project.\nThis schema determines what annotation types are available to users and how they can label assets.\n\n**Note:** Schema structure varies between Ango and PCT projects.\n- Ango projects: Use standard annotation tools (bounding-box, polygon, etc.)\n- PCT projects: Use PCT tool type with markingTools array and nested classifications with PCT-specific fields\n","properties":{"tools":{"type":"array","description":"Array of annotation tools (bounding box, polygon, segmentation, etc.)","items":{"$ref":"#/components/schemas/Tool"}},"classifications":{"type":"array","description":"Array of classification questions (radio, checkbox, dropdown, text, etc.)","items":{"$ref":"#/components/schemas/Classification"}},"relations":{"type":"array","description":"Array of relation types that can connect annotations","items":{"$ref":"#/components/schemas/Relation"}}}},"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}}}}}
```

## The LabelValidationUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"LabelValidationUpdateRequest":{"type":"object","description":"Request body for updating project label validation configuration.\nSupports custom validation functions (JavaScript for Ango, Python for PCT) and external API validation.\n","properties":{"validationFunction":{"type":"string","description":"Custom validation function as a string.\n- For Ango projects: JavaScript function that receives `answers` object\n- For PCT projects: Python function that receives `answers` dict\n- Must return array/list of error objects with: objectId, message, preventSubmission\n"},"customValidationEnabled":{"type":"boolean","description":"Enable/disable custom validation function execution"},"submissionPrevent":{"type":"boolean","description":"Globally prevent task submission when validation fails (optional)"},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
```

## The ExternalValidation object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}}}}}
```

## The SegmentationValidation object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
```

## The CategorySchema object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"CategorySchema":{"type":"object","description":"Label configuration schema that defines the annotation tools, classifications, and relations for a project.\nThis schema determines what annotation types are available to users and how they can label assets.\n\n**Note:** Schema structure varies between Ango and PCT projects.\n- Ango projects: Use standard annotation tools (bounding-box, polygon, etc.)\n- PCT projects: Use PCT tool type with markingTools array and nested classifications with PCT-specific fields\n","properties":{"tools":{"type":"array","description":"Array of annotation tools (bounding box, polygon, segmentation, etc.)","items":{"$ref":"#/components/schemas/Tool"}},"classifications":{"type":"array","description":"Array of classification questions (radio, checkbox, dropdown, text, etc.)","items":{"$ref":"#/components/schemas/Classification"}},"relations":{"type":"array","description":"Array of relation types that can connect annotations","items":{"$ref":"#/components/schemas/Relation"}}}},"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}}}}}
```

## The CategorySchemaPCTExample object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"CategorySchemaPCTExample":{"type":"object","description":"Example category schema for a PCT (Point Cloud Tool) project.\nShows complete PCT tool configuration with all available fields including marking tools,\ncuboid presets, and nested classifications with PCT-specific attributes.\n"}}}}
```

## The Tool object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Tool":{"type":"object","description":"Annotation tool configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this tool"},"title":{"type":"string","description":"Display name for the tool"},"tool":{"type":"string","description":"Type of annotation tool","enum":["bounding-box","polygon","polyline","point","rotated-bounding-box","segmentation","brush","medical-brush","ner","pdf","pct","angle"]},"required":{"type":"boolean","description":"Whether this annotation is required","default":false},"color":{"type":"string","description":"Hex color code for this annotation class","pattern":"^#[0-9A-Fa-f]{6}$"},"shortcutKey":{"type":"string","description":"Keyboard shortcut for quick selection"},"classifications":{"type":"array","description":"Nested classifications specific to this tool","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow creating multiple instances of this annotation","default":false},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data (for organizing exported annotations)"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"markingTools":{"type":"array","description":"(PCT only) List of marking tools enabled for this PCT tool.\nAvailable marking tools: polygon, polygon2d, polyline, polyline2d, cuboid, rectangle\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}},"truncate":{"type":"boolean","description":"(PCT only) Enable truncation for this tool","default":false},"presetCuboidDimensions":{"type":"boolean","description":"(PCT only) Enable preset cuboid dimensions","default":false},"cuboidLength":{"type":"string","description":"(PCT only) Preset cuboid length value (stored as string)"},"cuboidWidth":{"type":"string","description":"(PCT only) Preset cuboid width value (stored as string)"},"cuboidHeight":{"type":"string","description":"(PCT only) Preset cuboid height value (stored as string)"},"keypointWithVerticalLine":{"type":"boolean","description":"(PCT only) Enable keypoint with vertical line feature","default":false},"edgeLengthConstraint":{"type":"string","description":"(PCT only) Minimum edge length constraint (stored as string)"},"hasInstance":{"type":"boolean","description":"(PCT only) Enable instance tracking for this tool","default":false}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}}}}}
```

## The Classification object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}},"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}}}}}
```

## The ClassificationOption object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ClassificationOption":{"type":"object","description":"Option for a classification question","required":["schemaId","value"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this option"},"value":{"type":"string","description":"Display text and internal value for this option"},"label":{"type":"string","description":"Alternative display text (deprecated, use 'value')"},"children":{"type":"array","description":"Nested classifications that appear when this option is selected","items":{"$ref":"#/components/schemas/Classification"}}}},"Classification":{"type":"object","description":"Classification question configuration","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this classification"},"title":{"type":"string","description":"Question or label text"},"tool":{"type":"string","description":"Type of classification input (same as 'type')","enum":["radio","checkbox","single-dropdown","multi-dropdown","tree-dropdown","single-tree-dropdown","text","boolean"]},"color":{"type":"string","description":"Hex color code for this classification","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether answering this classification is required","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut key"},"columnField":{"type":"boolean","description":"Whether to show in column view","default":false},"frameSpecific":{"type":"boolean","description":"Whether classification is frame-specific (for videos)","default":false},"showDropdown":{"type":"boolean","description":"Whether to show as dropdown in UI","default":false},"richText":{"type":"boolean","description":"Whether to enable rich text input (for text type)","default":false},"regex":{"type":"string","nullable":true,"description":"Regular expression for text validation (for text type)"},"parentOptionId":{"type":"string","nullable":true,"description":"Parent option ID for nested classifications"},"options":{"type":"array","description":"Available options (not used for text type)","items":{"$ref":"#/components/schemas/ClassificationOption"}},"treeOptions":{"type":"array","description":"Tree-structured options (for tree-dropdown types)","items":{"type":"object"}},"classifications":{"type":"array","description":"Nested child classifications","items":{"$ref":"#/components/schemas/Classification"}},"multiple":{"type":"boolean","description":"Allow multiple selections","default":false},"parentToolType":{"type":"string","description":"(PCT only) Parent tool type this classification belongs to"},"parentToolId":{"type":"string","description":"(PCT only) Parent tool schemaId this classification is associated with"},"attributeLevel":{"type":"string","description":"(PCT only) Level at which this attribute applies","enum":["Class Level","Instance Level"]},"defaultValue":{"description":"Default value for this classification (type varies based on classification tool type)","oneOf":[{"type":"boolean"},{"type":"string"},{"type":"number"}]},"exportName":{"type":"string","description":"(PCT only) Name used when exporting data"},"displayName":{"type":"string","description":"(PCT only) Display name shown in the annotation interface"},"abbreviatedName":{"type":"string","description":"(PCT only) Abbreviated name for compact UI views"},"attributeMode":{"type":"string","description":"(PCT only) Attribute mode determining how values persist across frames.\n- Time Varying: Value can change per frame\n- Constant: Single value for entire sequence\n- Sensor Specific: Different values per sensor\n","enum":["Time Varying","Constant","Sensor Specific"]},"associatedMarkingTool":{"type":"array","description":"(PCT only) Marking tools this classification is associated with.\nThis classification will only be available when using these marking tools.\n","items":{"type":"string","enum":["polygon","polygon2d","polyline","polyline2d","cuboid","rectangle"]}}}}}}}
```

## The Relation object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Relation":{"type":"object","description":"Relation type that can connect two annotations.\n\n**Relation Types:**\n- `one-to-one`: Direct connection between two annotations (Ango only)\n- `group`: Groups multiple annotations together (Ango only)\n- `one-to-many`: Parent-child hierarchical relationship (PCT only)\n\n**Note:** PCT projects support additional fields like `parentTool` and `childTools` for one-to-many relations.\n","required":["schemaId","title","tool"],"properties":{"schemaId":{"type":"string","description":"Unique identifier for this relation"},"title":{"type":"string","description":"Display name for the relation"},"tool":{"type":"string","description":"Type of relation tool:\n- `one-to-one`: Direct 1:1 connection between annotations (Ango only)\n- `group`: Non-directional grouping of multiple annotations (Ango only)\n- `one-to-many`: Hierarchical parent-child relationship (PCT only)\n","enum":["one-to-one","group","one-to-many"]},"color":{"type":"string","description":"Hex color code for this relation","pattern":"^#[0-9A-Fa-f]{6}$"},"required":{"type":"boolean","description":"Whether this relation must be used in annotations","default":false},"classifications":{"type":"array","description":"Nested classification questions attached to this relation.\nAllows adding metadata or attributes to the relationship itself.\n","default":[]},"multiple":{"type":"boolean","description":"Whether multiple instances of this relation can be created","default":false},"shortcutKey":{"type":"string","description":"Keyboard shortcut to quickly create this relation"},"parentTool":{"type":"string","description":"(PCT only) For one-to-many relations, specifies the schemaId of the parent tool.\nOnly applicable when `tool: \"one-to-many\"`.\n"},"childTools":{"type":"array","description":"(PCT only) For one-to-many relations, specifies the schemaIds of allowed child tools.\nOnly applicable when `tool: \"one-to-many\"`.\n","items":{"type":"string"}}}}}}}
```

## The PctConfig object

````json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PctConfig":{"type":"object","description":"Configuration specific to Point Cloud Tool (PCT) projects.\nThese settings control how 3D point cloud annotation behaves.\n\nExample:\n```json\n{\n  \"allowOverlapping\": false,\n  \"trackingMultipleSensors\": true,\n  \"segmentationMode\": false\n}\n```\n","properties":{"allowOverlapping":{"type":"boolean","description":"Allow overlapping 3D bounding boxes","default":false},"trackingMultipleSensors":{"type":"boolean","description":"Enable tracking across multiple LiDAR sensors","default":false},"segmentationMode":{"type":"boolean","description":"Enable segmentation mode for point clouds","default":false},"externalValidation":{"$ref":"#/components/schemas/ExternalValidation"},"segmentationValidation":{"$ref":"#/components/schemas/SegmentationValidation"}}},"ExternalValidation":{"type":"object","description":"Configuration for external API-based validation","properties":{"enabled":{"type":"boolean","description":"Enable external validation API calls","default":false},"apiUrl":{"type":"string","description":"URL of external validation API endpoint","default":""},"singleFrame":{"type":"boolean","description":"For video projects - validate only a single frame","default":false},"specificFrame":{"type":"boolean","description":"For video projects - validate specific frame(s)","default":false},"frameNumbers":{"type":"integer","nullable":true,"description":"Frame number to validate for video projects (string input is coerced to a number)"}}},"SegmentationValidation":{"type":"object","description":"Configuration for segmentation coverage validation","properties":{"enabled":{"type":"boolean","default":false},"completeCoverage":{"type":"number","default":100}}}}}}
````

## The Stage object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Stage":{"type":"object","description":"Workflow stage configuration. Different stage types have different properties.\n- Label: Manual annotation stage\n- Review: QA/review stage\n- Logic: Conditional routing stage\n- Plugin: ML model integration stage\n- Webhook: External API callback stage\n- Consensus: Multi-annotator agreement stage\n- Hold: Pause stage\n- Start: Entry point (auto-forwards)\n- Complete: Terminal success stage\n- Archive: Terminal archive stage\n","required":["id","type"],"properties":{"id":{"type":"string","description":"Unique identifier for this stage"},"name":{"type":"string","description":"Display name for this stage"},"type":{"type":"string","description":"Type of stage","enum":["Label","Review","Logic","Plugin","Webhook","Consensus","Hold","Start","Complete","Archive"]},"next":{"type":"array","items":{"type":"string"},"description":"Array of next stage IDs (for Logic stages, order matters)"},"position":{"type":"object","description":"Position in workflow diagram UI","properties":{"x":{"type":"number"},"y":{"type":"number"}}},"assignedTo":{"type":"array","description":"Users assigned to work on this stage (Label/Review stages)","items":{"type":"string"}},"rememberAssignee":{"type":"boolean","description":"Auto-assign to previous stage's user (sticky assignment)","default":false},"logic":{"$ref":"#/components/schemas/LogicConfig","description":"Logic routing configuration (Logic stages only)"},"pluginId":{"type":"string","description":"Plugin ID to execute (Plugin stages only)"},"pluginConfig":{"type":"object","description":"Plugin-specific configuration (Plugin stages only)"},"webhook":{"$ref":"#/components/schemas/WebhookConfig","description":"Webhook configuration (Webhook stages only)"},"consensusConfig":{"$ref":"#/components/schemas/ConsensusConfig","description":"Consensus configuration (Consensus stages only)"},"readOnly":{"type":"boolean","description":"Whether this stage is read-only (users can view but not edit)","default":false},"preventRequeue":{"type":"boolean","description":"Prevent tasks from being requeued to this stage","default":false},"autoForward":{"type":"boolean","description":"Automatically advance to next stage without user action","default":true},"consensusId":{"type":"string","description":"Links stage to a consensus stage (used in consensus workflows)"},"consensusDynamic":{"type":"boolean","description":"Dynamic vs static consensus stage","default":false}}},"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}},"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}},"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}}}}}
```

## The LogicConfig object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"LogicConfig":{"type":"object","description":"Logic stage routing configuration. Routes tasks based on conditions.\nConditions are evaluated in order, first match wins.\n","properties":{"type":{"type":"string","description":"Type of logic routing","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Default value (usually empty)"},"conditions":{"type":"array","description":"Array of routing conditions","items":{"$ref":"#/components/schemas/LogicCondition"}}}},"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}}}}}
```

## The LogicCondition object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"LogicCondition":{"type":"object","description":"Individual routing condition for Logic stages","properties":{"type":{"type":"string","description":"Type of condition","enum":["AnnotationType","Annotator","RandomSample","Duration","Batch","IssueErrorCode"]},"value":{"type":"object","description":"Condition-specific value","properties":{"tools":{"type":"array","description":"Tool filters (AnnotationType logic)","items":{"type":"object","properties":{"filter":{"type":"array","items":{"type":"string"},"description":"Annotation filters:\n- exists___<schemaId>: Annotation must exist\n- not-exist___<schemaId>: Annotation must NOT exist\n"}}}},"emails":{"type":"array","description":"User emails (Annotator logic)","items":{"type":"string"}},"sampleRate":{"type":"number","description":"Sample rate 0-1 (RandomSample logic)","minimum":0,"maximum":1},"duration":{"type":"number","description":"Duration in milliseconds (Duration logic)"},"operator":{"type":"string","description":"Comparison operator for Duration","enum":["lt","gt","eq"]},"batches":{"type":"array","description":"Batch names (Batch logic)","items":{"type":"string"}}}},"index":{"type":"number","description":"Index of next stage in parent's next array"}}}}}}
```

## The WebhookConfig object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"WebhookConfig":{"type":"object","description":"Webhook configuration for external API integration","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"Webhook endpoint URL"},"method":{"type":"string","description":"HTTP method","enum":["POST","PUT"],"default":"POST"},"authType":{"type":"string","description":"Authentication type","enum":["no_auth","secret","bearer_token"],"default":"no_auth"},"secret":{"type":"string","description":"Secret for HMAC signature (authType=secret)"},"token":{"type":"string","description":"Bearer token (authType=bearer_token)"},"timeout":{"type":"number","description":"Timeout in milliseconds","default":30000},"retryCount":{"type":"number","description":"Number of retry attempts","default":3}}}}}}
```

## The ConsensusConfig object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ConsensusConfig":{"type":"object","description":"Consensus configuration for multi-annotator agreement","properties":{"version":{"type":"number","description":"Consensus algorithm version (1 or 2, v2 recommended)","enum":[1,2],"default":2},"threshold":{"type":"number","description":"Minimum agreement score (0-1) required to pass","minimum":0,"maximum":1},"adjudicationMethod":{"type":"string","description":"Method for resolving disagreements","enum":["majority","union","intersection","first"],"default":"majority"},"dynamicConsensus":{"type":"boolean","description":"Add more copies if threshold not met","default":false},"minCopies":{"type":"number","description":"Minimum number of consensus copies","minimum":2,"default":2},"maxCopies":{"type":"number","description":"Maximum number of consensus copies (dynamic consensus)","default":5}}}}}}
```

## The Assignee object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Assignee":{"type":"object","properties":{"assignee":{"type":"string","description":"User email"},"role":{"type":"string","enum":["Manager","Labeler","Reviewer","Lead"]}}}}}}
```

## The Batch object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Batch":{"type":"object","required":["name"],"properties":{"_id":{"type":"string","description":"Batch ID (auto-generated if not provided)"},"name":{"type":"string","description":"Batch name"}}}}}}
```

## The AssigneeUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssigneeUpdateRequest":{"type":"object","required":["role","assignees"],"properties":{"role":{"type":"string","enum":["Manager","Labeler","Reviewer","Lead"]},"assignees":{"type":"array","items":{"type":"string"},"description":"Array of user emails"},"roleAssignments":{"type":"object","additionalProperties":{"type":"string","enum":["Manager","Labeler","Reviewer","Lead"]},"description":"Optional map of user email to role override. Example - {\"user1@example.com\":\"Reviewer\"}"}}}}}}
```

## The AssetBuilderTemplateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetBuilderTemplateRequest":{"type":"object","required":["name","template"],"properties":{"name":{"type":"string"},"template":{"type":"string","description":"Template HTML"}}}}}}
```

## The AssetBuilderTemplateResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetBuilderTemplateResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"template":{"type":"object","description":"Echoes the submitted fields; any extra body fields are stored and returned verbatim.","additionalProperties":true,"properties":{"_id":{"type":"string"},"name":{"type":"string"},"template":{"type":"string","description":"Template HTML"}}}}}}}}}}
```

## The PerformanceRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PerformanceRequest":{"type":"object","properties":{"interval":{"type":"array","description":"Date-time range as [startISO, endISO].","minItems":2,"maxItems":2,"items":{"type":"string","format":"date-time"}},"batches":{"type":"array","items":{"type":"string"}}}}}}}
```

## The PerformanceResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PerformanceResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"performance":{"type":"array","description":"Per-user performance metrics.","items":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"completedLabels":{"type":"number"},"totalLabelingDuration":{"type":"number"},"avgLabelingDuration":{"type":"number"},"avgBenchmark":{"type":"number"},"totalLabelingIdleDuration":{"type":"number"},"totalLabelingBlurDuration":{"type":"number"},"completedReviews":{"type":"number"},"totalReviewDuration":{"type":"number"},"avgReviewDuration":{"type":"number"},"totalReviewIdleDuration":{"type":"number"},"totalReviewBlurDuration":{"type":"number"}}}}}}}}}}}
```

## The BatchUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BatchUpdateRequest":{"type":"object","required":["batches"],"properties":{"batches":{"type":"array","items":{"$ref":"#/components/schemas/Batch"}}}},"Batch":{"type":"object","required":["name"],"properties":{"_id":{"type":"string","description":"Batch ID (auto-generated if not provided)"},"name":{"type":"string","description":"Batch name"}}}}}}
```

## The LabelTask object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"LabelTask":{"type":"object","properties":{"_id":{"type":"string"},"project":{"type":"string"},"asset":{"oneOf":[{"type":"string"},{"$ref":"#/components/schemas/Asset"}],"description":"Populated Asset object on list/detail responses; id string on annotate/review responses."},"stage":{"type":"string"},"status":{"type":"string"},"assignee":{"type":"string"},"externalId":{"type":"string"},"batches":{"type":"array","items":{"type":"string"}},"priority":{"type":"number"},"answer":{"type":"object"},"createdAt":{"type":"string","format":"date-time"},"duration":{"type":"number","description":"Duration in seconds"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"tasks":{"type":"array","items":{"$ref":"#/components/schemas/LabelTask"}},"total":{"type":"integer"}}}}},"LabelTask":{"type":"object","properties":{"_id":{"type":"string"},"project":{"type":"string"},"asset":{"oneOf":[{"type":"string"},{"$ref":"#/components/schemas/Asset"}],"description":"Populated Asset object on list/detail responses; id string on annotate/review responses."},"stage":{"type":"string"},"status":{"type":"string"},"assignee":{"type":"string"},"externalId":{"type":"string"},"batches":{"type":"array","items":{"type":"string"}},"priority":{"type":"number"},"answer":{"type":"object"},"createdAt":{"type":"string","format":"date-time"},"duration":{"type":"number","description":"Duration in seconds"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"task":{"$ref":"#/components/schemas/LabelTask"}}}}},"LabelTask":{"type":"object","properties":{"_id":{"type":"string"},"project":{"type":"string"},"asset":{"oneOf":[{"type":"string"},{"$ref":"#/components/schemas/Asset"}],"description":"Populated Asset object on list/detail responses; id string on annotate/review responses."},"stage":{"type":"string"},"status":{"type":"string"},"assignee":{"type":"string"},"externalId":{"type":"string"},"batches":{"type":"array","items":{"type":"string"}},"priority":{"type":"number"},"answer":{"type":"object"},"createdAt":{"type":"string","format":"date-time"},"duration":{"type":"number","description":"Duration in seconds"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskFilters object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskFilters":{"type":"object","description":"Filter criteria for task operations","properties":{"taskIds":{"type":"array","items":{"type":"string"},"description":"Array of task IDs"},"externalIds":{"type":"array","items":{"type":"string"},"description":"Array of external IDs"},"assetIds":{"type":"array","items":{"type":"string"},"description":"Array of asset IDs"},"fromStageIds":{"type":"array","items":{"type":"string"},"description":"Array of source stage IDs"},"batches":{"type":"array","items":{"type":"string"},"description":"Array of batch IDs"}}}}}}
```

## The RequeueTasksRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"RequeueTasksRequest":{"type":"object","required":["toStageId","filters"],"properties":{"toStageId":{"type":"string","description":"Destination stage ID"},"filters":{"$ref":"#/components/schemas/TaskFilters"},"options":{"type":"object","description":"Options for task requeue operation","properties":{"removeAnnotations":{"type":"boolean","description":"Remove existing annotations when requeuing","default":false},"removeAssignee":{"type":"boolean","description":"Remove task assignee when requeuing","default":false},"removeStageHistory":{"type":"boolean","description":"Remove stage history when requeuing","default":false}}}}},"TaskFilters":{"type":"object","description":"Filter criteria for task operations","properties":{"taskIds":{"type":"array","items":{"type":"string"},"description":"Array of task IDs"},"externalIds":{"type":"array","items":{"type":"string"},"description":"Array of external IDs"},"assetIds":{"type":"array","items":{"type":"string"},"description":"Array of asset IDs"},"fromStageIds":{"type":"array","items":{"type":"string"},"description":"Array of source stage IDs"},"batches":{"type":"array","items":{"type":"string"},"description":"Array of batch IDs"}}}}}}
```

## The RequeueResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"RequeueResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"modifiedCount":{"type":"integer"}}}}}}}}
```

## The UpdatePriorityRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"UpdatePriorityRequest":{"type":"object","required":["priority","filters"],"properties":{"priority":{"type":"number","minimum":-1000,"maximum":1000,"description":"Priority value (-1000 to 1000)"},"filters":{"$ref":"#/components/schemas/TaskFilters"},"options":{"type":"object"}}},"TaskFilters":{"type":"object","description":"Filter criteria for task operations","properties":{"taskIds":{"type":"array","items":{"type":"string"},"description":"Array of task IDs"},"externalIds":{"type":"array","items":{"type":"string"},"description":"Array of external IDs"},"assetIds":{"type":"array","items":{"type":"string"},"description":"Array of asset IDs"},"fromStageIds":{"type":"array","items":{"type":"string"},"description":"Array of source stage IDs"},"batches":{"type":"array","items":{"type":"string"},"description":"Array of batch IDs"}}}}}}
```

## The PriorityUpdateResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PriorityUpdateResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"result":{"type":"object","properties":{"modifiedCount":{"type":"integer"},"priority":{"type":"number"}}}}}}}}}}
```

## The TaskAssignRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskAssignRequest":{"type":"object","required":["user","project","tasks","stage"],"properties":{"user":{"type":"string","description":"User email to assign to"},"project":{"type":"string","description":"Project ID"},"tasks":{"type":"array","items":{"type":"string"},"description":"Array of task IDs"},"stage":{"type":"string","description":"Stage ID"}}}}}}
```

## The TaskAssignResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskAssignResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"task":{"type":"object","properties":{"updatedCount":{"type":"integer"},"assignedTasks":{"type":"object","properties":{"count":{"type":"integer"}}},"message":{"type":"string"}}}}}}}}}}
```

## The AnnotateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AnnotateRequest":{"type":"object","required":["answer"],"properties":{"answer":{"type":"object","description":"Annotation answer object (structure depends on project categorySchema)"}}}}}}
```

## The ReviewRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ReviewRequest":{"type":"object","required":["reviewStatus"],"properties":{"reviewStatus":{"type":"string","enum":["Accepted","Rejected"],"description":"Review decision for the task.\n- `Accepted`: Approve the task and move it to the next stage\n- `Rejected`: Reject the task (typically sends it back for correction)\n"},"answer":{"type":"object","description":"Optional annotation modifications (structure depends on project categorySchema)"},"duration":{"type":"number","description":"Time spent reviewing in seconds"},"idleDuration":{"type":"number","description":"Idle time during review in seconds"},"blurDuration":{"type":"number","description":"Time window was blurred/unfocused in seconds"}}}}}}
```

## The LabelResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"LabelResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"label":{"$ref":"#/components/schemas/LabelTask"}}}}},"LabelTask":{"type":"object","properties":{"_id":{"type":"string"},"project":{"type":"string"},"asset":{"oneOf":[{"type":"string"},{"$ref":"#/components/schemas/Asset"}],"description":"Populated Asset object on list/detail responses; id string on annotate/review responses."},"stage":{"type":"string"},"status":{"type":"string"},"assignee":{"type":"string"},"externalId":{"type":"string"},"batches":{"type":"array","items":{"type":"string"}},"priority":{"type":"number"},"answer":{"type":"object"},"createdAt":{"type":"string","format":"date-time"},"duration":{"type":"number","description":"Duration in seconds"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskHistory object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskHistory":{"type":"object","properties":{"_id":{"type":"string"},"labelTaskId":{"type":"string","description":"Reference to the label task"},"project":{"type":"string"},"organization":{"type":"string"},"asset":{"$ref":"#/components/schemas/Asset"},"stage":{"type":"string"},"assignee":{"type":"string"},"prevAssignee":{"type":"string"},"reviewStatus":{"type":"string","enum":["Accepted","Rejected"]},"rework":{"type":"boolean"},"isSkipped":{"type":"boolean"},"type":{"type":"string"},"answer":{"type":"object"},"duration":{"type":"number"},"idleDuration":{"type":"number"},"blurDuration":{"type":"number"},"batches":{"type":"array","items":{"type":"string"}},"consensusAverage":{"type":"number"},"consensusDetailed":{"type":"array","items":{"type":"object"}},"consensusIteration":{"type":"integer"},"benchmarkAverage":{"type":"number"},"benchmarkDetailed":{"type":"array","items":{"type":"object"}},"brushDataUrl":{"type":"string"},"medicalBrushDataUrl":{"type":"string"},"rootStageId":{"type":"string"},"deleted":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskHistoryListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskHistoryListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"taskHistory":{"type":"array","items":{"$ref":"#/components/schemas/TaskHistory"}},"total":{"type":"integer"}}}}},"TaskHistory":{"type":"object","properties":{"_id":{"type":"string"},"labelTaskId":{"type":"string","description":"Reference to the label task"},"project":{"type":"string"},"organization":{"type":"string"},"asset":{"$ref":"#/components/schemas/Asset"},"stage":{"type":"string"},"assignee":{"type":"string"},"prevAssignee":{"type":"string"},"reviewStatus":{"type":"string","enum":["Accepted","Rejected"]},"rework":{"type":"boolean"},"isSkipped":{"type":"boolean"},"type":{"type":"string"},"answer":{"type":"object"},"duration":{"type":"number"},"idleDuration":{"type":"number"},"blurDuration":{"type":"number"},"batches":{"type":"array","items":{"type":"string"}},"consensusAverage":{"type":"number"},"consensusDetailed":{"type":"array","items":{"type":"object"}},"consensusIteration":{"type":"integer"},"benchmarkAverage":{"type":"number"},"benchmarkDetailed":{"type":"array","items":{"type":"object"}},"brushDataUrl":{"type":"string"},"medicalBrushDataUrl":{"type":"string"},"rootStageId":{"type":"string"},"deleted":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The TaskHistoryResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"TaskHistoryResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"taskHistory":{"$ref":"#/components/schemas/TaskHistory"}}}}},"TaskHistory":{"type":"object","properties":{"_id":{"type":"string"},"labelTaskId":{"type":"string","description":"Reference to the label task"},"project":{"type":"string"},"organization":{"type":"string"},"asset":{"$ref":"#/components/schemas/Asset"},"stage":{"type":"string"},"assignee":{"type":"string"},"prevAssignee":{"type":"string"},"reviewStatus":{"type":"string","enum":["Accepted","Rejected"]},"rework":{"type":"boolean"},"isSkipped":{"type":"boolean"},"type":{"type":"string"},"answer":{"type":"object"},"duration":{"type":"number"},"idleDuration":{"type":"number"},"blurDuration":{"type":"number"},"batches":{"type":"array","items":{"type":"string"}},"consensusAverage":{"type":"number"},"consensusDetailed":{"type":"array","items":{"type":"object"}},"consensusIteration":{"type":"integer"},"benchmarkAverage":{"type":"number"},"benchmarkDetailed":{"type":"array","items":{"type":"object"}},"brushDataUrl":{"type":"string"},"medicalBrushDataUrl":{"type":"string"},"rootStageId":{"type":"string"},"deleted":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The Asset object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The AssetListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/Asset"}},"total":{"type":"integer"}}}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The AssetResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"asset":{"$ref":"#/components/schemas/Asset"}}}}},"Asset":{"type":"object","description":"When an asset is private, carries a `storage`, or is NRRD, and its `data` is a URL, the read endpoints replace `data`, `dataset` and `overlay` with pre-signed URLs and set `head` to a signed HEAD URL. Otherwise `head` equals `data`.","properties":{"_id":{"type":"string"},"id":{"type":"string","description":"Same value as `_id`"},"data":{"type":"string","description":"Asset URL"},"dataset":{"type":"array","items":{"type":"string"}},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"head":{"type":"string","description":"Signed HEAD URL for the asset, or the same value as `data`"},"project":{"type":"string","description":"Project ID, or the project object when `populate=project` is used"},"organization":{"type":"string"},"storage":{"type":"string","description":"Storage integration ID, null for assets in the platform bucket","nullable":true},"externalId":{"type":"string"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"]},"uploadStatus":{"type":"string","enum":["READY","PCT_WAITING","METADATA_WAITING","PCT_FAILED","METADATA_FAILED"],"description":"An asset is READY once it can be annotated. PCT and preprocessing assets get their task only after the waiting state clears."},"isPrivate":{"type":"boolean"},"isPreLabeled":{"type":"boolean"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs the asset belongs to"},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}}},"contextData":{"type":"object"},"labelTasks":{"type":"array","description":"Returned only when populated, as objects carrying `_id`, `id`, `stage` and `assignee`. The project assets list always populates it.","items":{"type":"object","properties":{"_id":{"type":"string"},"id":{"type":"string"},"stage":{"type":"string"},"assignee":{"type":"string"}}}},"deleted":{"type":"boolean","description":"Deleted assets are excluded from responses by default, so this is false"},"preprocessEnqueuedAt":{"type":"string","format":"date-time","description":"When the asset was queued for preprocessing"},"createdAt":{"type":"string","format":"date-time"},"createdBy":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The UploadUrlResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"UploadUrlResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"uploadUrl":{"type":"string"}}}}}}}}
```

## The SignedUrlResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"SignedUrlResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"signedUrl":{"type":"string"}}}}}}}}
```

## The AssetMetadata object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The CloudImportAsset object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"CloudImportAsset":{"type":"object","required":["data"],"properties":{"data":{"type":"string","description":"Cloud storage URL or path to the asset.\n- For images/videos: Full URL (e.g., `https://bucket.s3.amazonaws.com/image.jpg`)\n- For PCT (Point Cloud): Folder path in format `bucket-name/folder-path/` (must end with `/`)\n"},"dataset":{"type":"array","items":{"type":"string"},"description":"Alternative to data - array of URLs for multi-file assets (e.g., videos with frames)"},"_id":{"type":"string","description":"Asset ID to create the asset with, as a 24 character hex string. Must be unused and unique within the request; a duplicate inside one request returns 400. `id` is accepted as an alias."},"externalId":{"type":"string","description":"External identifier for the asset. Defaults to `data` when omitted."},"storage":{"type":"string","description":"Storage integration ID (required for accessing private cloud buckets and PCT imports)"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"],"description":"Asset editor type. Determines how the asset is processed and displayed.\n- `ango`: Standard AngoHub editor (default) - supports images, videos, PDFs, and more\n- `pct`: Point Cloud Tool - 3D point cloud annotation (requires folder path in `data`)\n- `llm`: LLM/Chat annotation editor\n- `nrrd`: Medical imaging (DICOM to NRRD conversion)\n- `iframe`: Custom iframe-based editor\n"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs to assign this asset to. Use the `_id` values from the project's `batches` array, not batch names."},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]},"description":"Overlay images, either URLs or `{id, url}` objects"},"contextData":{"type":"object","description":"Additional context data for the asset"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}},"description":"Extra material shown next to the asset"},"priority":{"type":"number","minimum":-1000,"maximum":1000,"description":"Task priority for this asset, used only when the request-level `priority` is absent. It is keyed by `externalId`, so assets sharing one `externalId` share one priority, and it reaches only the tasks created at import time."},"tools":{"type":"array","items":{"type":"object"},"description":"Pre-label annotation objects (bounding boxes, polygons, and so on). Each object carries the `schemaId` of a tool in the project category schema. Pre-labels are applied only to assets that are ready at import time; an asset queued for preprocessing (a video without `metadata.width`, `metadata.height` and `metadata.frameTotal`, a DICOM series, or a PCT asset) gets its task later and keeps no pre-label."},"objects":{"type":"array","items":{"type":"object"},"description":"Alias for `tools`, read only when `tools` is absent."},"classifications":{"type":"array","items":{"type":"object"},"description":"Pre-label classification answers"},"relations":{"type":"array","items":{"type":"object"},"description":"Pre-label relation objects"},"brushDataUrl":{"type":"string","description":"URL of an uploaded brush mask to pre-label a brush annotation"},"medicalBrushDataUrl":{"type":"string","description":"URL of an uploaded medical brush mask"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The CloudImportRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"CloudImportRequest":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","items":{"$ref":"#/components/schemas/CloudImportAsset"}},"uploadLocal":{"type":"string","enum":["true","false"],"description":"\"true\" marks the created assets private. Nothing is downloaded, the files stay where they are. Read endpoints return pre-signed URLs when an asset is private, carries a `storage`, or is NRRD, so an asset with a `storage` gets signed URLs either way.","default":"false"},"priority":{"type":"number","minimum":-1000,"maximum":1000,"description":"Task priority for queue ordering (higher values first). Applies to every asset in the request and wins over a per-asset `priority`, including when it is 0.","default":0}}},"CloudImportAsset":{"type":"object","required":["data"],"properties":{"data":{"type":"string","description":"Cloud storage URL or path to the asset.\n- For images/videos: Full URL (e.g., `https://bucket.s3.amazonaws.com/image.jpg`)\n- For PCT (Point Cloud): Folder path in format `bucket-name/folder-path/` (must end with `/`)\n"},"dataset":{"type":"array","items":{"type":"string"},"description":"Alternative to data - array of URLs for multi-file assets (e.g., videos with frames)"},"_id":{"type":"string","description":"Asset ID to create the asset with, as a 24 character hex string. Must be unused and unique within the request; a duplicate inside one request returns 400. `id` is accepted as an alias."},"externalId":{"type":"string","description":"External identifier for the asset. Defaults to `data` when omitted."},"storage":{"type":"string","description":"Storage integration ID (required for accessing private cloud buckets and PCT imports)"},"editorType":{"type":"string","enum":["ango","pct","llm","nrrd","iframe"],"description":"Asset editor type. Determines how the asset is processed and displayed.\n- `ango`: Standard AngoHub editor (default) - supports images, videos, PDFs, and more\n- `pct`: Point Cloud Tool - 3D point cloud annotation (requires folder path in `data`)\n- `llm`: LLM/Chat annotation editor\n- `nrrd`: Medical imaging (DICOM to NRRD conversion)\n- `iframe`: Custom iframe-based editor\n"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs to assign this asset to. Use the `_id` values from the project's `batches` array, not batch names."},"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]},"description":"Overlay images, either URLs or `{id, url}` objects"},"contextData":{"type":"object","description":"Additional context data for the asset"},"attachments":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"},"label":{"type":"object"}}},"description":"Extra material shown next to the asset"},"priority":{"type":"number","minimum":-1000,"maximum":1000,"description":"Task priority for this asset, used only when the request-level `priority` is absent. It is keyed by `externalId`, so assets sharing one `externalId` share one priority, and it reaches only the tasks created at import time."},"tools":{"type":"array","items":{"type":"object"},"description":"Pre-label annotation objects (bounding boxes, polygons, and so on). Each object carries the `schemaId` of a tool in the project category schema. Pre-labels are applied only to assets that are ready at import time; an asset queued for preprocessing (a video without `metadata.width`, `metadata.height` and `metadata.frameTotal`, a DICOM series, or a PCT asset) gets its task later and keeps no pre-label."},"objects":{"type":"array","items":{"type":"object"},"description":"Alias for `tools`, read only when `tools` is absent."},"classifications":{"type":"array","items":{"type":"object"},"description":"Pre-label classification answers"},"relations":{"type":"array","items":{"type":"object"},"description":"Pre-label relation objects"},"brushDataUrl":{"type":"string","description":"URL of an uploaded brush mask to pre-label a brush annotation"},"medicalBrushDataUrl":{"type":"string","description":"URL of an uploaded medical brush mask"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The AssetImportResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetImportResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"assets":{"type":"object","properties":{"assetsCreated":{"type":"integer"},"tasksCreated":{"type":"integer"},"preLabelsCount":{"type":"integer"},"validPreLabelsCount":{"type":"integer"}}}}}}}}}}
```

## The ChatAssetUploadRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ChatAssetUploadRequest":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"JSON file holding the conversations to import"},"storageId":{"type":"string","description":"Storage integration ID. Send an empty value to use the platform bucket."},"bucket":{"type":"string"},"batches":{"type":"string","description":"JSON stringified array of batch IDs, applied to every conversation asset created by this request."},"llmConfig":{"type":"string","description":"LLM configuration JSON"},"numberOfConversations":{"type":"number","description":"How many conversations to create when no file is uploaded"},"namingStrategy":{"type":"string","description":"Accepted for backward compatibility, has no effect"},"priority":{"type":"number"}}}}}}
```

## The AssetUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssetUpdateRequest":{"type":"object","description":"The fields below are the supported ones. The endpoint applies the request body to the asset without validation, so any other Asset field is writable as well. The response carries the updated asset with its URLs re-signed.","properties":{"metadata":{"$ref":"#/components/schemas/AssetMetadata"},"contextData":{"type":"object"},"data":{"type":"string"},"overlay":{"type":"array","items":{"oneOf":[{"type":"string"},{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"}}}]}},"externalId":{"type":"string"}}},"AssetMetadata":{"type":"object","description":"Technical asset metadata. Only these fields are stored; any other key is dropped on write. For a video asset, supply width, height and frameTotal to skip server-side preprocessing.","properties":{"width":{"type":"integer"},"height":{"type":"integer"},"size":{"type":"integer"},"frameStep":{"type":"integer"},"frameTotal":{"type":"integer"},"frameRate":{"type":"number"},"numOfPages":{"type":"integer"},"numOfWords":{"type":"integer"},"duration":{"type":"integer","description":"Duration in milliseconds"},"hasVariableFrameRate":{"type":"boolean"}}}}}}
```

## The BulkDeleteAssetsRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkDeleteAssetsRequest":{"type":"object","required":["assets"],"properties":{"assets":{"type":"array","items":{"type":"string"}}}}}}}
```

## The BulkDeleteResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkDeleteResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"assets":{"type":"array","description":"The asset IDs from the request, echoed back, including IDs that did not exist","items":{"type":"string"}}}}}}}}}
```

## The AssignBatchesRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssignBatchesRequest":{"type":"object","required":["assets","batches","projectId"],"properties":{"assets":{"type":"array","items":{"type":"string"},"description":"Asset IDs to update"},"batches":{"type":"array","items":{"type":"string"},"description":"Batch IDs to set on the assets. Use the `_id` values from the project's `batches` array, not batch names; an unknown ID fails the whole request with 400."},"projectId":{"type":"string","description":"Project the batches belong to"}}}}}}
```

## The AssignBatchesResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"AssignBatchesResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"assets":{"type":"object","properties":{"count":{"type":"integer","description":"Number of assets updated"},"message":{"type":"string"}}}}}}}}}}
```

## The Issue object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Issue":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"project":{"type":"string"},"asset":{"type":"string"},"labelTask":{"type":"string"},"status":{"type":"string","enum":["Open","Resolved","Closed"]},"createdBy":{"type":"string"},"assignee":{"type":"string"},"errorType":{"type":"string"},"errorCode":{"type":"string"},"position":{"type":"string"},"points":{"type":"array","items":{"type":"object"}},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}},"comments":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"content":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}}}}},"errorCodes":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"}}}},"pctDetails":{"type":"object","description":"PCT-specific issue details containing positional metadata, severity,\nreference source, and optional marker information for navigating to\na point inside a 3D/2D scene.\n","properties":{"attribute":{"type":"string","nullable":true,"description":"Attribute ID from configuration."},"class":{"type":"string","nullable":true,"description":"Class ID from configuration."},"frame":{"type":"integer","description":"Starting frame number of the issue."},"endInputFrame":{"type":"integer","description":"Last frame where the issue persists."},"instance":{"type":"integer","description":"Class instance index."},"severity":{"type":"integer","enum":[2,3,4],"description":"Issue severity: 2=High, 3=Medium, 4=Low"},"referenceIndex":{"type":"integer","description":"-1 for 3D sensor, 0+ for 2D camera sensor index"},"marker":{"type":"object","description":"Marker for navigating to the issue location.","properties":{"type":{"type":"string","enum":["Marker 3D","Marker 2D"]},"value":{"type":"object","properties":{"geometry":{"type":"object","properties":{"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"rotation":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"boxSize":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}}}}}}}}}},"resolvedBy":{"type":"string"},"resolvedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The IssueListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"IssueListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"issue":{"type":"array","items":{"$ref":"#/components/schemas/Issue"}}}}}},"Issue":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"project":{"type":"string"},"asset":{"type":"string"},"labelTask":{"type":"string"},"status":{"type":"string","enum":["Open","Resolved","Closed"]},"createdBy":{"type":"string"},"assignee":{"type":"string"},"errorType":{"type":"string"},"errorCode":{"type":"string"},"position":{"type":"string"},"points":{"type":"array","items":{"type":"object"}},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}},"comments":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"content":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}}}}},"errorCodes":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"}}}},"pctDetails":{"type":"object","description":"PCT-specific issue details containing positional metadata, severity,\nreference source, and optional marker information for navigating to\na point inside a 3D/2D scene.\n","properties":{"attribute":{"type":"string","nullable":true,"description":"Attribute ID from configuration."},"class":{"type":"string","nullable":true,"description":"Class ID from configuration."},"frame":{"type":"integer","description":"Starting frame number of the issue."},"endInputFrame":{"type":"integer","description":"Last frame where the issue persists."},"instance":{"type":"integer","description":"Class instance index."},"severity":{"type":"integer","enum":[2,3,4],"description":"Issue severity: 2=High, 3=Medium, 4=Low"},"referenceIndex":{"type":"integer","description":"-1 for 3D sensor, 0+ for 2D camera sensor index"},"marker":{"type":"object","description":"Marker for navigating to the issue location.","properties":{"type":{"type":"string","enum":["Marker 3D","Marker 2D"]},"value":{"type":"object","properties":{"geometry":{"type":"object","properties":{"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"rotation":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"boxSize":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}}}}}}}}}},"resolvedBy":{"type":"string"},"resolvedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The IssueResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"IssueResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"issue":{"$ref":"#/components/schemas/Issue"}}}}},"Issue":{"type":"object","properties":{"_id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string"},"project":{"type":"string"},"asset":{"type":"string"},"labelTask":{"type":"string"},"status":{"type":"string","enum":["Open","Resolved","Closed"]},"createdBy":{"type":"string"},"assignee":{"type":"string"},"errorType":{"type":"string"},"errorCode":{"type":"string"},"position":{"type":"string"},"points":{"type":"array","items":{"type":"object"}},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}},"comments":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"content":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}}}}},"errorCodes":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"}}}},"pctDetails":{"type":"object","description":"PCT-specific issue details containing positional metadata, severity,\nreference source, and optional marker information for navigating to\na point inside a 3D/2D scene.\n","properties":{"attribute":{"type":"string","nullable":true,"description":"Attribute ID from configuration."},"class":{"type":"string","nullable":true,"description":"Class ID from configuration."},"frame":{"type":"integer","description":"Starting frame number of the issue."},"endInputFrame":{"type":"integer","description":"Last frame where the issue persists."},"instance":{"type":"integer","description":"Class instance index."},"severity":{"type":"integer","enum":[2,3,4],"description":"Issue severity: 2=High, 3=Medium, 4=Low"},"referenceIndex":{"type":"integer","description":"-1 for 3D sensor, 0+ for 2D camera sensor index"},"marker":{"type":"object","description":"Marker for navigating to the issue location.","properties":{"type":{"type":"string","enum":["Marker 3D","Marker 2D"]},"value":{"type":"object","properties":{"geometry":{"type":"object","properties":{"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"rotation":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"boxSize":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}}}}}}}}}},"resolvedBy":{"type":"string"},"resolvedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The IssueCreateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"IssueCreateRequest":{"type":"object","required":["labelTask"],"properties":{"labelTask":{"type":"string","description":"Task ID to create issue for"},"title":{"type":"string"},"content":{"type":"string"},"contentMentions":{"type":"array","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}},"position":{"type":"string"},"points":{"type":"array","items":{"type":"object"}},"errorType":{"type":"string"},"errorCode":{"type":"string"},"pctDetails":{"type":"object","description":"PCT-specific issue details containing positional metadata, severity,\nreference source, and optional marker information for navigating to\na point inside a 3D/2D scene.\n","properties":{"attribute":{"type":"string","nullable":true,"description":"Attribute ID from configuration. Can be null or omitted if not assigned."},"class":{"type":"string","nullable":true,"description":"Class ID from configuration. Can be null or omitted if not available."},"frame":{"type":"integer","default":1,"description":"Starting frame number of the issue. Defaults to 1."},"endInputFrame":{"type":"integer","default":1,"description":"Last frame where the issue persists. Defaults to 1."},"instance":{"type":"integer","default":-1,"description":"Class instance index. Defaults to -1."},"severity":{"type":"integer","enum":[2,3,4],"description":"Issue severity: 2=High, 3=Medium, 4=Low"},"referenceIndex":{"type":"integer","default":-1,"description":"-1 for 3D sensor, 0+ for 2D camera sensor index"},"marker":{"type":"object","description":"Optional marker for navigating to the issue location.","properties":{"type":{"type":"string","enum":["Marker 3D","Marker 2D"]},"value":{"type":"object","properties":{"geometry":{"type":"object","properties":{"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"rotation":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"boxSize":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}}}}}}}}}}}}}}}
```

## The IssueUpdateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"IssueUpdateRequest":{"type":"object","description":"Request body for updating an issue. All fields are optional.","properties":{"content":{"type":"string","description":"Updated issue content/description"},"contentMentions":{"type":"array","description":"Users mentioned in the content","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}},"status":{"type":"string","enum":["Open","Resolved"],"description":"Issue status (Open or Resolved)"},"pctDetails":{"type":"object","description":"PCT-specific issue details containing positional metadata, severity,\nreference source, and optional marker information for navigating to\na point inside a 3D/2D scene.\n","properties":{"attribute":{"type":"string","nullable":true,"description":"Attribute ID from configuration. Can be null or omitted if not assigned."},"class":{"type":"string","nullable":true,"description":"Class ID from configuration. Can be null or omitted if not available."},"frame":{"type":"integer","default":1,"description":"Starting frame number of the issue. Defaults to 1."},"endInputFrame":{"type":"integer","default":1,"description":"Last frame where the issue persists. Defaults to 1."},"instance":{"type":"integer","default":-1,"description":"Class instance index. Defaults to -1."},"severity":{"type":"integer","enum":[2,3,4],"description":"Issue severity: 2=High, 3=Medium, 4=Low"},"referenceIndex":{"type":"integer","default":-1,"description":"-1 for 3D sensor, 0+ for 2D camera sensor index"},"marker":{"type":"object","description":"Optional marker for navigating to the issue location.","properties":{"type":{"type":"string","enum":["Marker 3D","Marker 2D"]},"value":{"type":"object","properties":{"geometry":{"type":"object","properties":{"position":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"rotation":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}},"boxSize":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"z":{"type":"number"}}}}}}}}}}},"errorCodes":{"type":"array","description":"Error codes associated with the issue","items":{"type":"object","properties":{"category":{"type":"string"},"name":{"type":"string"},"key":{"type":"string"}}}}}}}}}
```

## The IssueCommentRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"IssueCommentRequest":{"type":"object","required":["content"],"properties":{"content":{"type":"string","description":"The comment text content"},"contentMentions":{"type":"array","description":"Users mentioned in the comment","items":{"type":"object","properties":{"userEmail":{"type":"string"},"userName":{"type":"string"}}}}}}}}}
```

## The Storage object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Storage":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string","enum":["AWS","GCP","AZURE","CUSTOM_S3"]},"region":{"type":"string"},"s3AccessType":{"type":"string","enum":["IAM_USER","IAM_DELEGATED"]},"s3RoleArn":{"type":"string"},"s3ExternalId":{"type":"string"},"s3UserArn":{"type":"string"},"host":{"type":"string"},"azureAuthType":{"type":"string","enum":["ACCOUNT_KEY","SERVICE_PRINCIPAL","MULTI_TENANT"]},"azureTenantId":{"type":"string"},"azureClientId":{"type":"string"},"publicKey":{"type":"string"},"useAccelerateEndpoint":{"type":"boolean"},"organization":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The StorageListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"StorageListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"storages":{"type":"array","items":{"$ref":"#/components/schemas/Storage"}}}}}},"Storage":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string","enum":["AWS","GCP","AZURE","CUSTOM_S3"]},"region":{"type":"string"},"s3AccessType":{"type":"string","enum":["IAM_USER","IAM_DELEGATED"]},"s3RoleArn":{"type":"string"},"s3ExternalId":{"type":"string"},"s3UserArn":{"type":"string"},"host":{"type":"string"},"azureAuthType":{"type":"string","enum":["ACCOUNT_KEY","SERVICE_PRINCIPAL","MULTI_TENANT"]},"azureTenantId":{"type":"string"},"azureClientId":{"type":"string"},"publicKey":{"type":"string"},"useAccelerateEndpoint":{"type":"boolean"},"organization":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The StorageResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"StorageResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"storage":{"$ref":"#/components/schemas/Storage"}}}}},"Storage":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"provider":{"type":"string","enum":["AWS","GCP","AZURE","CUSTOM_S3"]},"region":{"type":"string"},"s3AccessType":{"type":"string","enum":["IAM_USER","IAM_DELEGATED"]},"s3RoleArn":{"type":"string"},"s3ExternalId":{"type":"string"},"s3UserArn":{"type":"string"},"host":{"type":"string"},"azureAuthType":{"type":"string","enum":["ACCOUNT_KEY","SERVICE_PRINCIPAL","MULTI_TENANT"]},"azureTenantId":{"type":"string"},"azureClientId":{"type":"string"},"publicKey":{"type":"string"},"useAccelerateEndpoint":{"type":"boolean"},"organization":{"type":"string"},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The StorageCreateRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"StorageCreateRequest":{"type":"object","required":["name","provider"],"properties":{"name":{"type":"string","description":"Storage configuration display name"},"provider":{"type":"string","enum":["AWS","GCP","AZURE","CUSTOM_S3"]},"region":{"type":"string","default":"eu-central-1","description":"AWS only. Bucket region."},"publicKey":{"type":"string","description":"Access key ID for AWS (IAM user) and CUSTOM_S3. For AZURE this is the storage account name (required for all Azure auth types)."},"privateKey":{"type":"string","description":"Secret access key for AWS (IAM user) and CUSTOM_S3. For AZURE (ACCOUNT_KEY) this is the account key. Write-only, never returned."},"s3AccessType":{"type":"string","enum":["IAM_USER","IAM_DELEGATED"],"default":"IAM_USER","description":"AWS only. IAM_DELEGATED uses STS AssumeRole instead of static keys."},"s3RoleArn":{"type":"string","description":"AWS IAM_DELEGATED only. Role ARN to assume."},"s3ExternalId":{"type":"string","description":"AWS IAM_DELEGATED only. External ID for the AssumeRole trust policy."},"host":{"type":"string","description":"CUSTOM_S3 only (required). S3-compatible endpoint URL."},"credentials":{"type":"object","description":"GCP only. Service-account JSON object. Write-only, never returned."},"azureAuthType":{"type":"string","enum":["ACCOUNT_KEY","SERVICE_PRINCIPAL","MULTI_TENANT"],"default":"ACCOUNT_KEY","description":"AZURE only."},"azureTenantId":{"type":"string","description":"AZURE SERVICE_PRINCIPAL and MULTI_TENANT."},"azureClientId":{"type":"string","description":"AZURE SERVICE_PRINCIPAL only."},"azureClientSecret":{"type":"string","description":"AZURE SERVICE_PRINCIPAL only. Write-only, never returned."},"useAccelerateEndpoint":{"type":"boolean","default":false,"description":"AWS only. Use S3 Transfer Acceleration."}}}}}}
```

## The StorageFilesResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"StorageFilesResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"files":{"type":"array","description":"Flat list of object keys, or pre-signed URLs when getSignedUrls=true (default).","items":{"type":"string"}}}}}}}}}
```

## The User object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"User":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The UserListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"UserListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}},"User":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"name":{"type":"string"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"createdAt":{"type":"string","format":"date-time"}}}}}}
```

## The BulkUpdateMembersRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkUpdateMembersRequest":{"type":"object","required":["users"],"properties":{"users":{"type":"array","items":{"type":"object","required":["email","organizationRole"],"properties":{"email":{"type":"string","format":"email"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]}}}}}}}}}
```

## The BulkUpdateResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkUpdateResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"users":{"type":"object","properties":{"updated":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string"},"status":{"type":"string"}}}}}}}}}}}}}
```

## The BulkDeleteMembersRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkDeleteMembersRequest":{"type":"object","required":["users"],"properties":{"users":{"type":"array","items":{"type":"string","format":"email"}}}}}}}
```

## The Invitation object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"Invitation":{"type":"object","properties":{"_id":{"type":"string"},"to":{"type":"string","format":"email"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"status":{"type":"string","enum":["Pending","Sent","Accepted"]},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}}}}}
```

## The InviteListResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"InviteListResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"invites":{"type":"array","items":{"$ref":"#/components/schemas/Invitation"}}}}}},"Invitation":{"type":"object","properties":{"_id":{"type":"string"},"to":{"type":"string","format":"email"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"status":{"type":"string","enum":["Pending","Sent","Accepted"]},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}}}}}
```

## The InviteListResponseData object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"InviteListResponseData":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"invites":{"type":"array","items":{"$ref":"#/components/schemas/Invitation"}}}}}},"Invitation":{"type":"object","properties":{"_id":{"type":"string"},"to":{"type":"string","format":"email"},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"status":{"type":"string","enum":["Pending","Sent","Accepted"]},"createdBy":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}}}}}
```

## The InvitationRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"InvitationRequest":{"type":"object","required":["to","organizationRole"],"properties":{"to":{"type":"array","items":{"type":"string","format":"email"},"minItems":1},"organizationRole":{"type":"string","enum":["Admin","Member","Guest"]},"projectAssignments":{"type":"array","items":{"type":"object","required":["projectId","projectRole"],"properties":{"projectId":{"type":"string"},"projectRole":{"type":"string"}}}},"organizationRoleAssignments":{"type":"object","additionalProperties":{"type":"string"}},"projectRoleAssignments":{"type":"object","additionalProperties":{"type":"string"}}}}}}}
```

## The BulkDeleteInvitesRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"BulkDeleteInvitesRequest":{"type":"object","required":["invites"],"properties":{"invites":{"type":"array","items":{"type":"string"}}}}}}}
```

## The ImportAttachmentsRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ImportAttachmentsRequest":{"type":"object","required":["project","attachments"],"properties":{"project":{"type":"string"},"attachments":{"type":"array","items":{"type":"object","required":["attachmentUrl"],"properties":{"assetId":{"type":"string"},"externalId":{"type":"string"},"attachmentUrl":{"type":"string"},"attachmentType":{"type":"string"}}}}}}}}}
```

## The ImportAttachmentsResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ImportAttachmentsResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"project":{"type":"object","properties":{"attachmentsImported":{"type":"integer"},"assetsUpdated":{"type":"integer"}}}}}}}}}}
```

## The ImportLabelsRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ImportLabelsRequest":{"type":"object","required":["project","labels"],"properties":{"project":{"type":"string"},"labels":{"type":"array","items":{"type":"object","required":["answer"],"properties":{"assetId":{"type":"string"},"externalId":{"type":"string"},"answer":{"type":"object"},"status":{"type":"string"},"assignee":{"type":"string"}}}}}}}}}
```

## The ImportLabelsResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ImportLabelsResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"project":{"type":"string","description":"Success message indicating labeled task count"}}}}}}}}
```

## The ExportResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"ExportResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"exportPath":{"type":"string"}}}}}}}}
```

## The OverviewResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"OverviewResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"overview":{"oneOf":[{"type":"object"},{"type":"array"}]}}}}}}}}
```

## The PluginResponseRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PluginResponseRequest":{"type":"object","required":["pluginId","taskId","response","status"],"properties":{"pluginId":{"type":"string"},"taskId":{"type":"string"},"response":{"type":"object"},"status":{"type":"string"}}}}}}
```

## The PluginResponseAck object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PluginResponseAck":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"response":{"type":"object","properties":{"received":{"type":"boolean"},"taskId":{"type":"string"}}}}}}}}}}
```

## The PluginLogRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PluginLogRequest":{"type":"object","required":["pluginId","level","message"],"properties":{"pluginId":{"type":"string"},"taskId":{"type":"string"},"level":{"type":"string","enum":["info","warn","error"]},"message":{"type":"string"},"metadata":{"type":"object"}}}}}}
```

## The PluginLogAck object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"PluginLogAck":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"response":{"type":"object","properties":{"logged":{"type":"boolean"}}}}}}}}}}
```

## The RerunWebhookRequest object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"RerunWebhookRequest":{"type":"object","properties":{"stageId":{"type":"string","description":"Stage ID to rerun webhook for"}}}}}}
```

## The WebhookResponse object

```json
{"openapi":"3.0.3","info":{"title":"Ango Hub API v2","version":"2.0.0"},"components":{"schemas":{"WebhookResponse":{"type":"object","properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"webhook":{"type":"object","description":"Webhook rerun result"}}}}}}}}
```


---

# 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.imerit.net/api/docs/models.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.
