openapi: 3.1.0 info: title: Box Manifest API version: 0.0.0 description: >- Pre-release API for the Box Manifest universal node tree. Breaking changes are allowed until a compatibility policy is adopted. servers: - url: / paths: /api/node-types: get: operationId: listNodeTypes summary: List user-defined node types responses: "200": description: Node types ordered by name content: application/json: schema: type: array items: { $ref: "#/components/schemas/NodeType" } default: { $ref: "#/components/responses/Error" } post: operationId: createNodeType summary: Create a node type requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/NodeTypeWrite" } responses: "201": description: Node type created content: application/json: schema: { $ref: "#/components/schemas/NodeType" } default: { $ref: "#/components/responses/Error" } /api/node-types/{typeId}: parameters: - name: typeId in: path required: true schema: { type: string } put: operationId: updateNodeType summary: Replace a node type requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/NodeTypeWrite" } responses: "200": description: Node type updated content: application/json: schema: { $ref: "#/components/schemas/NodeType" } default: { $ref: "#/components/responses/Error" } delete: operationId: deleteNodeType summary: Delete a type and leave assigned nodes untyped responses: "204": { description: Node type deleted } default: { $ref: "#/components/responses/Error" } /api/tags: get: operationId: listTags summary: List tags responses: "200": description: Tags ordered by name content: application/json: schema: type: array items: { $ref: "#/components/schemas/Tag" } default: { $ref: "#/components/responses/Error" } post: operationId: createTag summary: Create a tag requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/TagWrite" } responses: "201": description: Tag created content: application/json: schema: { $ref: "#/components/schemas/Tag" } default: { $ref: "#/components/responses/Error" } /api/tags/{tagId}: parameters: - name: tagId in: path required: true schema: { type: string } put: operationId: updateTag summary: Replace a tag requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/TagWrite" } responses: "200": description: Tag updated content: application/json: schema: { $ref: "#/components/schemas/Tag" } default: { $ref: "#/components/responses/Error" } delete: operationId: deleteTag summary: Delete a tag and remove its node assignments responses: "204": { description: Tag deleted } default: { $ref: "#/components/responses/Error" } /api/tree: get: operationId: getTree summary: Get the complete node tree responses: "200": description: The tree beginning at Root content: application/json: schema: $ref: "#/components/schemas/TreeNode" default: $ref: "#/components/responses/Error" /api/imports/tree/preview: post: operationId: previewTreeImport summary: Validate and preview a nested tree import requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/TreeImportPreviewRequest" responses: "200": description: Normalized import plan ready for review content: application/json: schema: $ref: "#/components/schemas/TreeImportPreview" default: $ref: "#/components/responses/Error" /api/imports/tree/commit: post: operationId: commitTreeImport summary: Atomically commit a reviewed tree import plan requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/TreeImportCommitRequest" responses: "201": description: Entire tree imported content: application/json: schema: $ref: "#/components/schemas/TreeImportCommitResponse" default: $ref: "#/components/responses/Error" /api/nodes: post: operationId: createNode summary: Create a node description: A missing parentId places the new node beneath Unsorted. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateNodeRequest" responses: "201": description: Node created content: application/json: schema: $ref: "#/components/schemas/Node" default: $ref: "#/components/responses/Error" /api/nodes/bulk: post: operationId: createNodesBulk summary: Create multiple sibling nodes atomically requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateNodesBulkRequest" responses: "201": description: All nodes created in request order content: application/json: schema: $ref: "#/components/schemas/CreateNodesBulkResponse" default: $ref: "#/components/responses/Error" /api/nodes/bulk/move: post: operationId: moveNodesBulk summary: Move sibling nodes atomically requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MoveNodesBulkRequest" responses: "200": description: All selected nodes moved content: application/json: schema: $ref: "#/components/schemas/MoveNodesBulkResponse" default: $ref: "#/components/responses/Error" /api/nodes/bulk/delete: post: operationId: deleteNodesBulk summary: Delete empty nodes atomically requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/DeleteNodesBulkRequest" responses: "204": description: All selected nodes deleted default: $ref: "#/components/responses/Error" /api/nodes/bulk/combine: post: operationId: combineNodes summary: Combine empty sibling nodes into one quantity-tracked node description: >- The retained node keeps its UUID and lookup code. Other selected nodes and their lookup identities are deleted atomically. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CombineNodesRequest" responses: "200": description: Combined quantity-tracked node content: application/json: schema: $ref: "#/components/schemas/Node" default: $ref: "#/components/responses/Error" /api/nodes/bulk/classification: post: operationId: classifyNodesBulk summary: Atomically assign a type and add or remove tags on multiple nodes requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/BulkClassificationRequest" } responses: "204": { description: Classification updated } default: { $ref: "#/components/responses/Error" } /api/nodes/{nodeId}: parameters: - $ref: "#/components/parameters/NodeId" get: operationId: getNode summary: Get one node responses: "200": description: Node found content: application/json: schema: $ref: "#/components/schemas/Node" default: $ref: "#/components/responses/Error" patch: operationId: updateNode summary: Update a node's name or quantity requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/UpdateNodeRequest" responses: "200": description: Node updated content: application/json: schema: $ref: "#/components/schemas/Node" default: $ref: "#/components/responses/Error" delete: operationId: deleteNode summary: Delete an empty node description: Root, Unsorted, and nodes with children cannot be deleted. responses: "204": description: Node deleted "409": description: The node is protected or is not empty content: application/json: schema: $ref: "#/components/schemas/Error" default: $ref: "#/components/responses/Error" /api/nodes/by-code/{lookupCode}: get: operationId: getNodeByLookupCode summary: Resolve a printed lookup code to its node parameters: - name: lookupCode in: path required: true schema: type: string pattern: "^[A-Z2-7]{6}$" responses: "200": description: Node found content: application/json: schema: $ref: "#/components/schemas/Node" default: $ref: "#/components/responses/Error" /api/nodes/{nodeId}/move: parameters: - $ref: "#/components/parameters/NodeId" post: operationId: moveNode summary: Move a node requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/MoveNodeRequest" responses: "200": description: Node moved content: application/json: schema: $ref: "#/components/schemas/Node" "409": description: The move is forbidden or would create a cycle content: application/json: schema: $ref: "#/components/schemas/Error" default: $ref: "#/components/responses/Error" /api/nodes/{nodeId}/individualize: parameters: - $ref: "#/components/parameters/NodeId" post: operationId: individualizeNode summary: Turn an empty quantity node into individually tracked siblings description: >- The original node becomes the first unit and retains its UUID and lookup code. The supplied names must match the existing quantity. requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/IndividualizeNodeRequest" responses: "200": description: Individually tracked nodes in unit order content: application/json: schema: $ref: "#/components/schemas/CreateNodesBulkResponse" default: $ref: "#/components/responses/Error" /api/nodes/{nodeId}/classification: parameters: - $ref: "#/components/parameters/NodeId" put: operationId: classifyNode summary: Replace a node's optional type and complete tag set requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/ClassificationRequest" } responses: "200": description: Classified node content: application/json: schema: { $ref: "#/components/schemas/Node" } default: { $ref: "#/components/responses/Error" } components: parameters: NodeId: name: nodeId in: path required: true schema: type: string responses: Error: description: Request failed content: application/json: schema: $ref: "#/components/schemas/Error" schemas: Node: type: object additionalProperties: false required: - id - lookupCode - parentId - name - description - quantity - typeId - tagIds properties: id: type: string lookupCode: type: string description: Stable human-enterable lookup key; not the internal identity. pattern: "^[A-Z2-7]{6}$" parentId: type: - string - "null" description: Null only for Root. name: type: string minLength: 1 description: type: - string - "null" quantity: type: - integer - "null" minimum: 0 typeId: type: [string, "null"] tagIds: type: array uniqueItems: true items: { type: string } ImportNode: type: object additionalProperties: false required: - name properties: name: type: string minLength: 1 description: type: string quantity: type: - integer - "null" minimum: 0 children: type: array items: $ref: "#/components/schemas/ImportNode" TreeImportManifest: type: object additionalProperties: false required: - nodes properties: nodes: type: array minItems: 1 maxItems: 10000 items: $ref: "#/components/schemas/ImportNode" TreeImportSummary: type: object additionalProperties: false required: - nodes - maximumDepth properties: nodes: type: integer minimum: 1 maximumDepth: type: integer minimum: 1 maximum: 64 TreeImportPreviewRequest: type: object additionalProperties: false required: - parentId - manifest properties: parentId: type: string manifest: $ref: "#/components/schemas/TreeImportManifest" TreeImportPreview: type: object additionalProperties: false required: - planId - summary - warnings - manifest properties: planId: type: string summary: $ref: "#/components/schemas/TreeImportSummary" warnings: type: array items: type: string manifest: $ref: "#/components/schemas/TreeImportManifest" TreeImportCommitRequest: type: object additionalProperties: false required: - planId properties: planId: type: string TreeImportCommitResponse: type: object additionalProperties: false required: - created properties: created: $ref: "#/components/schemas/TreeImportSummary" TreeNode: type: object additionalProperties: false required: - id - lookupCode - parentId - name - description - quantity - typeId - tagIds - children properties: id: type: string lookupCode: type: string pattern: "^[A-Z2-7]{6}$" parentId: type: - string - "null" description: Null only for Root. name: type: string minLength: 1 description: type: - string - "null" quantity: type: - integer - "null" minimum: 0 typeId: type: [string, "null"] tagIds: type: array uniqueItems: true items: { type: string } children: type: array items: $ref: "#/components/schemas/TreeNode" CreateNodeRequest: type: object additionalProperties: false required: - name properties: parentId: type: string description: Omit to place the node beneath Unsorted. name: type: string minLength: 1 description: type: - string - "null" quantity: type: - integer - "null" minimum: 0 CreateNodesBulkRequest: type: object additionalProperties: false required: - parentId - names properties: parentId: type: string names: type: array minItems: 1 items: type: string minLength: 1 description: type: - string - "null" CreateNodesBulkResponse: type: object additionalProperties: false required: - nodes properties: nodes: type: array items: $ref: "#/components/schemas/Node" MoveNodesBulkRequest: type: object additionalProperties: false required: - nodeIds - targetParentId properties: nodeIds: type: array minItems: 1 uniqueItems: true items: type: string targetParentId: type: string childHandling: type: string enum: - WITH_SUBTREE - PROMOTE_CHILDREN - CHILDREN_TO_UNSORTED default: WITH_SUBTREE MoveNodesBulkResponse: type: object additionalProperties: false required: - nodes properties: nodes: type: array items: $ref: "#/components/schemas/Node" DeleteNodesBulkRequest: type: object additionalProperties: false required: - nodeIds properties: nodeIds: type: array minItems: 1 uniqueItems: true items: type: string IndividualizeNodeRequest: type: object additionalProperties: false required: - names properties: names: type: array minItems: 2 maxItems: 1000 items: type: string minLength: 1 CombineNodesRequest: type: object additionalProperties: false required: - nodeIds - retainedNodeId - name properties: nodeIds: type: array minItems: 2 uniqueItems: true items: type: string retainedNodeId: type: string description: A member of nodeIds whose UUID and lookup code survive. name: type: string minLength: 1 UpdateNodeRequest: type: object additionalProperties: false minProperties: 1 properties: name: type: string minLength: 1 description: type: - string - "null" quantity: type: - integer - "null" minimum: 0 NodeType: type: object additionalProperties: false required: [id, name, description, iconKey, color] properties: id: { type: string } name: { type: string, minLength: 1 } description: { type: [string, "null"] } iconKey: { type: [string, "null"] } color: { type: [string, "null"] } NodeTypeWrite: type: object additionalProperties: false required: [name] properties: name: { type: string, minLength: 1 } description: { type: [string, "null"] } iconKey: { type: [string, "null"] } color: { type: [string, "null"] } Tag: type: object additionalProperties: false required: [id, name, color] properties: id: { type: string } name: { type: string, minLength: 1 } color: { type: [string, "null"] } TagWrite: type: object additionalProperties: false required: [name] properties: name: { type: string, minLength: 1 } color: { type: [string, "null"] } ClassificationRequest: type: object additionalProperties: false required: [typeId, tagIds] properties: typeId: { type: [string, "null"] } tagIds: type: array uniqueItems: true items: { type: string } BulkClassificationRequest: type: object additionalProperties: false required: [nodeIds, setType, typeId, addTagIds, removeTagIds] properties: nodeIds: type: array minItems: 1 uniqueItems: true items: { type: string } setType: { type: boolean } typeId: { type: [string, "null"] } addTagIds: type: array uniqueItems: true items: { type: string } removeTagIds: type: array uniqueItems: true items: { type: string } MoveNodeRequest: type: object additionalProperties: false required: - targetParentId properties: targetParentId: type: string childHandling: type: string enum: - WITH_SUBTREE - PROMOTE_CHILDREN - CHILDREN_TO_UNSORTED default: WITH_SUBTREE Error: type: object additionalProperties: false required: - code - message properties: code: type: string message: type: string