---
openapi: 3.1.0
info:
  title: Metafold REST API
  description: |
    REST API for running geometry processing operations on the web.
  version: 1.0.0
servers:
- url: https://api.metafold3d.com
  description: Production environment
- url: https://dev-api.metafold3d.com
  description: Bleeding-edge (unstable) environment
tags:
- name: Projects
- name: Assets
- name: Workflows
- name: Jobs
paths:
  /projects:
    get:
      summary: Get user projects
      description: List projects for authenticated user
      operationId: getProjects
      tags: ["Projects"]
      parameters:
      - name: sort
        in: query
        schema:
          type: string
        description: |
          Sort string. Must be in the form `field:order`.
          `field` may be one of: id, user, name, created, or modified.
          `order` may be one of -1 for descending or 1 for ascending.
          Resources are sorted in descending order by id by default.
        examples:
          nameAsc:
            value: "name:1"
          sortCreatedDesc:
            value: "created:-1"
      - name: q
        in: query
        schema:
          type: string
        description: |
          Query string. See [search query syntax](/topic/topic-search-query-syntax) for
          details. Supported search fields are: id, user, and name.
        examples:
          findName:
            value: "name:\"my-project\""
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/project"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["projects:read"]
    post:
      summary: Create project
      description: Create project with the given data
      operationId: createProject
      tags: ["Projects"]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                access:
                  $ref: "#/components/schemas/projectAccess"
              required: ["name"]
              example:
                name: "My Project"
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/project"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["projects:write"]
  /projects/{projectId}:
    parameters:
    - $ref: "#/components/parameters/projectId"
    get:
      summary: Get user project
      description: Get project by ID
      operationId: getProject
      tags: ["Projects"]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/project"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["projects:read"]
    patch:
      summary: Update user project
      description: Update project by ID
      operationId: updateProject
      tags: ["Projects"]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                access:
                  $ref: "#/components/schemas/projectAccess"
              example:
                name: "My Project"
                access: "public"
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/project"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["projects:write"]
    delete:
      summary: Delete user project
      description: Delete project by ID
      operationId: deleteProject
      tags: ["Projects"]
      responses:
        "200":
          description: OK
          content:
            text/plain:
              schema: {"const": "OK"}
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["projects:write"]
  /projects/{projectId}/assets:
    parameters:
    - $ref: "#/components/parameters/projectId"
    get:
      summary: Get project assets
      description: List assets in project
      operationId: getAssets
      tags: ["Assets"]
      parameters:
      - name: sort
        in: query
        schema:
          type: string
        description: |
          Sort string. Must be in the form `field:order`.
          `field` may be one of: id, filename, size, created, or modified.
          `order` may be one of -1 for descending or 1 for ascending.
          Resources are sorted in descending order by id by default.
        examples:
          filenameAsc:
            value: "filename:1"
          sizeDesc:
            value: "size:-1"
      - name: q
        in: query
        schema:
          type: string
        description: |
          Query string. See [search query syntax](/topic/topic-search-query-syntax) for
          details. Supported search fields are: id, and filename.
        examples:
          findFilename:
            value: "filename:\"part.stl\""
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/asset"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["assets:read"]
    post:
      summary: Upload project asset
      description: Upload asset to project with the given data
      operationId: createAsset
      tags: ["Assets"]
      requestBody:
        required: true
        content:
          multipart/form-data: {}
      responses:
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/asset"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["assets:write"]
  /projects/{projectId}/assets/{assetId}:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/assetId"
    get:
      summary: Get project asset
      description: Get project asset by ID
      operationId: getAsset
      tags: ["Assets"]
      parameters:
      - name: download
        in: query
        schema:
          type: string
        description: |
          Boolean. Either “true” or “1” is accepted.
          Response will include a link URL to download asset from.
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/asset"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["assets:read"]
    delete:
      summary: Delete project asset
      description: Delete project asset by ID
      operationId: deleteAsset
      tags: ["Assets"]
      responses:
        "200":
          description: OK
          content:
            text/plain:
              schema: {"const": "OK"}
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["assets:write"]
  /projects/{projectId}/workflows:
    parameters:
    - $ref: "#/components/parameters/projectId"
    get:
      summary: Get project workflows
      description: List workflows in project
      operationId: getWorkflows
      tags: ["Workflows"]
      parameters:
      - name: sort
        in: query
        schema:
          type: string
        description: |
          Sort string. Must be in the form `field:order`.
          `field` may be one of: id, created, started, or finished.
          `order` may be one of -1 for descending or 1 for ascending.
          Resources are sorted in descending order by id by default.
        examples:
          createdDesc:
            value: "created:-1"
          finishedDesc:
            value: "finished:-1"
      - name: q
        in: query
        schema:
          type: string
        description: |
          Query string. See [search query syntax](/topic/topic-search-query-syntax) for
          details. Supported search fields are: id, and state.
        examples:
          findSuccess:
            value: "state:\"success\""
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/workflow"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["workflows:read"]
    post:
      summary: Run project workflow
      description: Dispatch workflow with given definition
      operationId: createWorkflow
      tags: ["Workflows"]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                definition:
                  type: string
                  description: YAML-encoded definition
                assets:
                  $ref: "#/components/schemas/workflowInput"
                parameters:
                  $ref: "#/components/schemas/workflowInput"
              required: ["definition"]
              example:
                definition: |
                  ---
                  jobs:
                    preprocess-mesh:
                      type: mesh/preprocess
                    compute-bvh:
                      type: mesh/compute-bvh
                      needs:
                      - preprocess-mesh
                      assets:
                        mesh: preprocess-mesh
                    sample-mesh:
                      type: implicit/from-mesh
                      needs:
                      - preprocess-mesh
                      - compute-bvh
                      assets:
                        mesh: preprocess-mesh
                        bvh: compute-bvh
                  ...
                assets:
                  preprocess-mesh.mesh: part.stl
                parameters:
                  sample-mesh.resolution: "256"
      responses:
        "202":
          description: Accepted
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/workflow"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["workflows:write", "jobs:write", "definitions:read"]
  /projects/{projectId}/workflows/{workflowId}:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/workflowId"
    get:
      summary: Get project workflow
      description: Get project workflow by ID
      operationId: getWorkflow
      tags: ["Workflows"]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/workflow"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["workflows:read"]
    delete:
      summary: Delete project workflow
      description: Delete project workflow by ID
      operationId: deleteWorkflow
      tags: ["Workflows"]
      responses:
        "200":
          description: OK
          content:
            text/plain:
              schema: {"const": "OK"}
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["workflows:write"]
  /projects/{projectId}/workflows/{workflowId}/status:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/workflowId"
    get:
      summary: Get project workflow status
      description: Get status of project workflow by ID
      operationId: getWorkflowStatus
      tags: ["Workflows"]
      responses:
        "202":
          description: Accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  state:
                    $ref: "#/components/schemas/workflowState"
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/workflow"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["workflows:read"]
  /projects/{projectId}/workflows/{workflowId}/cancel:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/workflowId"
    post:
      summary: Cancel project workflow
      description: Cancel project workflow by ID
      operationId: cancelWorkflow
      tags: ["Workflows"]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/workflow"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["workflows:write"]
  /projects/{projectId}/jobs:
    parameters:
    - $ref: "#/components/parameters/projectId"
    get:
      summary: Get project jobs
      description: List jobs in project
      operationId: getJobs
      tags: ["Jobs"]
      parameters:
      - name: sort
        in: query
        schema:
          type: string
        description: |
          Sort string. Must be in the form `field:order`.
          `field` may be one of: id, name, created, started, or finished.
          `order` may be one of -1 for descending or 1 for ascending.
          Resources are sorted in descending order by id by default.
        examples:
          nameAsc:
            value: "name:1"
          createdDesc:
            value: "created:-1"
      - name: q
        in: query
        schema:
          type: string
        description: |
          Query string. See [search query syntax](/topic/topic-search-query-syntax) for
          details. Supported search fields are: id, name, type, and state.
        examples:
          findName:
            value: "name:\"my-job\""
          findSuccess:
            value: "state:\"success\""
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/job"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
      security:
      - oauth2: ["jobs:read"]
  /projects/{projectId}/jobs/{jobId}:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/jobId"
    get:
      summary: Get project job
      description: Get project job by ID
      operationId: getJob
      tags: ["Jobs"]
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/job"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["jobs:read"]
    delete:
      summary: Delete project job
      description: Delete project job by ID
      operationId: deleteJob
      tags: ["Jobs"]
      responses:
        "200":
          description: OK
          content:
            text/plain:
              schema: {"const": "OK"}
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["jobs:write"]
  /projects/{projectId}/jobs/{jobId}/status:
    parameters:
    - $ref: "#/components/parameters/projectId"
    - $ref: "#/components/parameters/jobId"
    get:
      summary: Get project job status
      description: Get status of project job by ID
      operationId: getJobStatus
      tags: ["Jobs"]
      responses:
        "202":
          description: Accepted
          content:
            application/json:
              schema:
                type: object
                properties:
                  state:
                    $ref: "#/components/schemas/jobState"
        "201":
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/job"
        "400":
          $ref: "#/components/responses/badRequest"
        "401":
          $ref: "#/components/responses/unauthorized"
        "404":
          $ref: "#/components/responses/notFound"
      security:
      - oauth2: ["jobs:read"]
components:
  parameters:
    projectId:
      description: Project ID
      name: projectId
      in: path
      required: true
      schema: {"type": "string"}
    assetId:
      description: Asset ID
      name: assetId
      in: path
      required: true
      schema: {"type": "string"}
    workflowId:
      description: Workflow ID
      name: workflowId
      in: path
      required: true
      schema: {"type": "string"}
    jobId:
      description: Job ID
      name: jobId
      in: path
      required: true
      schema: {"type": "string"}
  schemas:
    datetime:
      type: string
      description: "ISO 8601 datetime"
      example: "2006-01-02T22:04:05+00:00"
    errorResponse:
      type: object
      description: JSON-encoded HTTP error
      properties:
        code:
          type: integer
          description: HTTP response code
        name:
          type: string
          description: Status text corresponding to the HTTP response code
        description:
          type: string
          description: Detailed error message
    projectAccess:
      type: string
      description: Access control
      enum: ["private", "public"]
    project:
      type: object
      description: Project resource
      properties:
        id: {"type": "string"}
        user:
          type: string
          description: Owner ID
        name: {"type": "string"}
        access:
          $ref: "#/components/schemas/projectAccess"
        created:
          $ref: "#/components/schemas/datetime"
        modified:
          $ref: "#/components/schemas/datetime"
      required:
      - id
      - user
      - name
      - created
      - modified
      example:
        id: "123"
        user: auth0|668d4279b22e4ed36b598305
        name: my-project
        access: private
        created: "2006-01-02T22:04:05+00:00"
        modified: "2006-01-02T22:04:05+00:00"
    asset:
      type: object
      description: Asset resource
      properties:
        id: {"type": "string"}
        filename:
          type: string
          example: part.stl
        size:
          type: integer
          minimum: 0
          description: Size of file in bytes
        checksum:
          type: string
          description: SHA-256 checksum of file contents
        created:
          $ref: "#/components/schemas/datetime"
        modified:
          $ref: "#/components/schemas/datetime"
        project_id:
          type: string
          description: Project ID
        job_id:
          type: string
          nullable: true
          description: Job ID that created this asset, if any
        link:
          type: string
          description: Download URL
      required:
      - id
      - filename
      - size
      - checksum
      - created
      - modified
      - project_id
      - job_id
      example:
        id: "123"
        filename: part.stl
        size: 262144
        checksum: "sha256:2d063a84b13e5b23730a509cbb6ba42534acde451249a0b7409172a4f8814ef0"
        created: "2006-01-02T22:04:05+00:00"
        modified: "2006-01-02T22:04:05+00:00"
        project_id: "123"
        job_id: null
    workflowState:
      type: string
      enum:
      - pending
      - started
      - success
      - failure
      - canceled
      description: Current workflow state
    workflow:
      type: object
      description: Workflow resource
      properties:
        id: {"type": "string"}
        jobs:
          type: array
          items:
            type: string
          description: Job IDs
        state:
          $ref: "#/components/schemas/workflowState"
        created:
          $ref: "#/components/schemas/datetime"
        started:
          $ref: "#/components/schemas/datetime"
          nullable: true
        finished:
          $ref: "#/components/schemas/datetime"
          nullable: true
        definition:
          type: string
          description: Raw definition string
        project_id:
          type: string
          description: Project ID
        link:
          type: string
          description: Status query URL
      required:
      - id
      - jobs
      - state
      - created
      - started
      - finished
      - definition
      - project_id
      example:
        id: "123"
        jobs: ["1", "2", "3"]
        state: "success"
        created: "2006-01-02T22:04:05+00:00"
        started: "2006-01-02T22:04:10+00:00"
        finished: "2006-01-02T22:04:40+00:00"
        definition: |
          ---
          jobs:
            preprocess-mesh:
              type: mesh/preprocess
            compute-bvh:
              type: mesh/compute-bvh
              needs:
              - preprocess-mesh
              assets:
                mesh: preprocess-mesh
            sample-mesh:
              type: implicit/from-mesh
              needs:
              - preprocess-mesh
              - compute-bvh
              assets:
                mesh: preprocess-mesh
                bvh: compute-bvh
          ...
        project_id: "123"
    workflowInput:
      type: object
      description: |
        Input asset or parameter assignments.
        Assignments should be in the form `job.input`,
        with a `.` dot separating the job name and asset/parameter name.
      patternProperties:
        "^[a-zA-Z0-9-_]+\\.[a-zA-Z0-9-_]+$":
          type: string
          description: Asset filename or parameter value.
    jobState:
      type: string
      description: Current job state
      enum:
      - pending
      - started
      - success
      - failure
      - canceled
    jobIO:
      type: object
      description: Job assets and parameters
      properties:
        assets:
          type: object
          nullable: true
          description: Asset mapping
          patternProperties:
            .:
              $ref: "#/components/schemas/asset"
        params:
          type: object
          nullable: true
          description: Parameter mapping
          patternProperties:
            .:
              type: string
              description: Parameter value serialized to string
      required:
      - params
    job:
      type: object
      description: Job resource
      properties:
        id: {"type": "string"}
        name:
          type: string
          nullable: true
        type:
          type: "string"
          description: Type name
        state:
          $ref: "#/components/schemas/jobState"
        created:
          $ref: "#/components/schemas/datetime"
        started:
          $ref: "#/components/schemas/datetime"
          nullable: true
        finished:
          $ref: "#/components/schemas/datetime"
          nullable: true
        error:
          type: string
          nullable: true
          description: Error message for failed jobs
        inputs:
          $ref: "#/components/schemas/jobIO"
          description: Input assets and parameters
        outputs:
          $ref: "#/components/schemas/jobIO"
          description: Output assets and parameters
        needs:
          type: array
          items:
            type: string
          description: IDs of upstream dependencies
        project_id:
          type: string
          description: Project ID
        workflow_id:
          type: string
          nullable: true
          description: Workflow ID, if part of a workflow
      required:
      - id
      - name
      - type
      - state
      - created
      - started
      - finished
      - error
      - inputs
      - outputs
      - needs
      - project_id
      - workflow_id
      example:
        id: "123"
        name: sample-mesh
        type: implicit/from-mesh
        state: "success"
        created: "2006-01-02T22:04:05+00:00"
        started: "2006-01-02T22:04:10+00:00"
        finished: "2006-01-02T22:04:40+00:00"
        inputs:
          assets:
            mesh:
              id: "1"
              filename: part.stl
              size: 262144
              checksum: "sha256:2d063a84b13e5b23730a509cbb6ba42534acde451249a0b7409172a4f8814ef0"
              created: "2006-01-02T22:04:05+00:00"
              modified: "2006-01-02T22:04:05+00:00"
          params:
            resolution: "256"
        outputs:
          assets:
            volume:
              id: "2"
              filename: 18ac5faec0625a35.bin
              size: 262144
              checksum: "sha256:d8a0c9a50db61d021c311ef1a57e4531a75f30a3bea44d1db20d82d12d1bb2df"
              created: "2006-01-02T22:04:05+00:00"
              modified: "2006-01-02T22:04:05+00:00"
          params:
            patch: |
              {"size": [2.0, 2.0, 2.0], "offset": [-1.0, -1.0, -1.0], "resolution": [256, 256, 256]}
            vertex_count: "3000"
            face_count: "1000"
            bounds: |
              {"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]}
        needs: ["1", "2"]
        project_id: "123"
        workflow_id: "123"
  responses:
    badRequest:
      description: Bad Request
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/errorResponse"
            example:
              code: 400
              name: Bad Request
              description: Expected parameter "foo"
    unauthorized:
      description: Unauthorized
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/errorResponse"
            example:
              code: 401
              name: Unauthorzed
              description: Token has expired
    notFound:
      description: Not Found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/errorResponse"
            example:
              code: 404
              name: Not Found
              description: Resource does not exist
  securitySchemes:
    oauth2:
      type: oauth2
      description: "OAuth 2.0 access token"
      flows:
        clientCredentials:
          tokenUrl: https://metafold3d.us.auth0.com/oauth/token
          scopes:
            projects:read: Read user projects
            projects:write: Modify user projects
            assets:read: Read user assets
            assets:write: Modify user assets
            workflows:read: Read user workflows
            workflows:write: Modify user workflows
            definitions:read: Read job definitions this user is authorized to run
            jobs:read: Read user jobs
            jobs:write: Modify user jobs
x-topics:
- title: Getting Started
  content:
    $ref: "./docs/start.md"
- title: Authentication
  content:
    $ref: "./docs/auth.md"
- title: Workflows
  content:
    $ref: "./docs/workflows.md"
- title: Search Query Syntax
  content:
    $ref: "./docs/search.md"
...
