{
  "openapi": "3.1.0",
  "info": {
    "title": "Harmony REST API",
    "version": "1.0",
    "summary": "Work with your AI Agents in Harmony.",
    "description": "Harmony is the shared surface for human–agent teams: one board where people\nand agents take an idea to a shipped PR.\n\n## Authentication\n\nTwo credentials reach this API, both in a request header. Every endpoint\nbelow needs one, except `GET /v1` and `GET /v1/health`, which are public.\n\n- `X-API-Key: hmy_...` — an API key created at https://gethmy.com/user/keys.\n  It acts for the user who created it, across every workspace that user\n  belongs to.\n- `Authorization: Bearer hmy_at_...` — an OAuth 2.1 access token issued by\n  https://app.gethmy.com. Harmony issues one named scope, `mcp`, and binds\n  each grant to the set of workspaces the user selected at consent time. A\n  request outside that set is refused with `403`, so the workspace binding\n  is the least-privilege boundary, not the scope string. The matching\n  RFC 9728 metadata is published at\n  https://gethmy.com/.well-known/oauth-protected-resource/api.\n\n## Errors\n\nEvery failure answers a JSON body of the shape `{\"error\": \"...\"}` with the\nstatus code listed on the operation.\n\n## Rate limiting\n\nRequests are rate limited per user. Over the limit answers `429`.\n\n## Links\n\n- Marketing: https://gethmy.com\n- Quick setup: https://gethmy.com/llms.txt\n- Full docs: https://gethmy.com/llms-full.txt\n- Connect guide (install, sign-in, API key): https://gethmy.com/connect.md\n- CLI package: https://www.npmjs.com/package/@gethmy/cli\n- MCP package: https://www.npmjs.com/package/@gethmy/mcp\n- Create an API key: https://gethmy.com/user/keys\n",
    "termsOfService": "https://gethmy.com/terms",
    "contact": {
      "name": "Harmony",
      "email": "hello@gethmy.com",
      "url": "https://gethmy.com"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://gethmy.com/terms"
    }
  },
  "externalDocs": {
    "description": "Full documentation for agents",
    "url": "https://gethmy.com/llms-full.txt"
  },
  "servers": [
    {
      "url": "https://gethmy.com/api",
      "description": "Production (marketing domain)"
    },
    {
      "url": "https://app.gethmy.com/api",
      "description": "Production (app domain)"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    },
    {
      "OAuth2": [
        "mcp"
      ]
    }
  ],
  "tags": [
    {
      "name": "Discovery",
      "description": "Public endpoints that need no credential."
    },
    {
      "name": "Workspaces",
      "description": "Workspaces the credential can reach."
    },
    {
      "name": "Projects",
      "description": "Projects inside a workspace."
    },
    {
      "name": "Board",
      "description": "The full board state for a project."
    },
    {
      "name": "Cards",
      "description": "Create, read, update, move, and search cards."
    },
    {
      "name": "Columns",
      "description": "The columns a card moves through."
    },
    {
      "name": "Labels",
      "description": "Labels on a board and on a card."
    },
    {
      "name": "Subtasks",
      "description": "Checklist items on a card."
    },
    {
      "name": "Links",
      "description": "Relationships between cards."
    },
    {
      "name": "Agents",
      "description": "Prompts generated from a card for an agent to work from."
    },
    {
      "name": "NLU",
      "description": "Natural-language commands against the board."
    },
    {
      "name": "Desktop",
      "description": "Published Harmony Quickbar builds and their download."
    },
    {
      "name": "Intake",
      "description": "A public feedback channel. One token files one card into one board\ncolumn, and reaches nothing else in this document.\n"
    }
  ],
  "paths": {
    "/v1": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getApiIndex",
        "summary": "API index",
        "description": "Public index of this API — the spec URL, the accepted credentials, and\nthe endpoint list. Needs no credential, so an agent can confirm the\nsurface exists before it asks a user for a key.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "The API index.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiIndex"
                }
              }
            }
          }
        }
      }
    },
    "/v1/health": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "operationId": "getHealth",
        "summary": "Liveness probe",
        "description": "Public and unrated. A rate-limited liveness probe reports a false\noutage under exactly the load you need it during.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "The service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      }
    },
    "/v1/intake": {
      "post": {
        "tags": [
          "Intake"
        ],
        "operationId": "createIntakeCard",
        "summary": "File a card through a public feedback channel",
        "description": "Fire and forget. A `201` says the submission was accepted and nothing\nelse — no card id, no short id, no board name — so this endpoint cannot\nbe used to read a board.\n\nEvery credential outcome answers the same `401`: unknown, revoked,\nexpired, and a column that has since moved to another project are\ndeliberately indistinguishable, or the endpoint would be a probe for\ntoken state. The channel's owner reads the reason on the key instead.\n\nAn optional `Idempotency-Key` makes a retry safe: the same value on the\nsame channel files one card and answers the same blind `201`.\n",
        "security": [
          {
            "IntakeKey": []
          }
        ],
        "parameters": [
          {
            "in": "header",
            "name": "Idempotency-Key",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "description": "A caller-chosen id. Repeating it on the same channel files nothing\nthe second time. Omit it and every call files.\n"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "title"
                ],
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 500
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 10000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The submission was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The body is malformed or the title is missing."
          },
          "401": {
            "description": "The token is not usable. One message for every reason, by design.\n"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaces",
        "summary": "List workspaces accessible to the credential",
        "description": "An OAuth token lists only the workspaces its grant covers. An API key\nlists every workspace its user belongs to.\n",
        "responses": {
          "200": {
            "description": "The workspaces this credential can reach.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Workspace"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{id}/projects": {
      "get": {
        "tags": [
          "Projects"
        ],
        "operationId": "listProjects",
        "summary": "List projects in a workspace",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The projects in the workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Project"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workspaces/{id}/members": {
      "get": {
        "tags": [
          "Workspaces"
        ],
        "operationId": "listWorkspaceMembers",
        "summary": "Get workspace members",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The members of the workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WorkspaceMember"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/board/{projectId}": {
      "get": {
        "tags": [
          "Board"
        ],
        "operationId": "getBoard",
        "summary": "Get the full board state for a project",
        "parameters": [
          {
            "in": "path",
            "name": "projectId",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Columns, cards, and labels for the project.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Board"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/cards": {
      "post": {
        "tags": [
          "Cards"
        ],
        "operationId": "createCard",
        "summary": "Create a card",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CardCreate"
              },
              "example": {
                "projectId": "6590761b-5b8e-4909-a8d2-c47bc920fbfc",
                "columnId": "c5b4fa13-1db3-40c7-a3ca-8e9426f7b8b8",
                "title": "Return a real 404 for unknown paths",
                "priority": "high"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/cards/{id}": {
      "get": {
        "tags": [
          "Cards"
        ],
        "operationId": "getCard",
        "summary": "Get a card",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Cards"
        ],
        "operationId": "updateCard",
        "summary": "Update a card",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CardUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Cards"
        ],
        "operationId": "deleteCard",
        "summary": "Delete a card",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "204": {
            "description": "The card was deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/cards/{id}/move": {
      "post": {
        "tags": [
          "Cards"
        ],
        "operationId": "moveCard",
        "summary": "Move a card to a different column",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "columnId"
                ],
                "properties": {
                  "columnId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "position": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The moved card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/search": {
      "get": {
        "tags": [
          "Cards"
        ],
        "operationId": "searchCards",
        "summary": "Search cards",
        "description": "Searches titles and descriptions. An OAuth token only ever matches\ncards inside the workspaces its grant covers.\n",
        "parameters": [
          {
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "agent readiness"
          }
        ],
        "responses": {
          "200": {
            "description": "The matching cards.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/Card"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/columns": {
      "post": {
        "tags": [
          "Columns"
        ],
        "operationId": "createColumn",
        "summary": "Create a column",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId",
                  "name"
                ],
                "properties": {
                  "projectId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  },
                  "position": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created column.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Column"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/v1/columns/{id}": {
      "patch": {
        "tags": [
          "Columns"
        ],
        "operationId": "updateColumn",
        "summary": "Update a column",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "position": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated column.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Column"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Columns"
        ],
        "operationId": "deleteColumn",
        "summary": "Delete a column",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "204": {
            "description": "The column was deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/labels": {
      "post": {
        "tags": [
          "Labels"
        ],
        "operationId": "createLabel",
        "summary": "Create a label",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "projectId",
                  "name"
                ],
                "properties": {
                  "projectId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "name": {
                    "type": "string"
                  },
                  "color": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created label.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Label"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/cards/{id}/labels": {
      "post": {
        "tags": [
          "Labels"
        ],
        "operationId": "addLabelToCard",
        "summary": "Add a label to a card",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "labelId"
                ],
                "properties": {
                  "labelId": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The label is on the card."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/cards/{id}/labels/{labelId}": {
      "delete": {
        "tags": [
          "Labels"
        ],
        "operationId": "removeLabelFromCard",
        "summary": "Remove a label from a card",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "in": "path",
            "name": "labelId",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "The label is off the card."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/subtasks": {
      "post": {
        "tags": [
          "Subtasks"
        ],
        "operationId": "createSubtask",
        "summary": "Create a subtask",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cardId",
                  "title"
                ],
                "properties": {
                  "cardId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "title": {
                    "type": "string"
                  },
                  "position": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created subtask.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subtask"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/subtasks/{id}/toggle": {
      "post": {
        "tags": [
          "Subtasks"
        ],
        "operationId": "toggleSubtask",
        "summary": "Toggle subtask completion",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The subtask, with its new completion state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Subtask"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/subtasks/{id}": {
      "delete": {
        "tags": [
          "Subtasks"
        ],
        "operationId": "deleteSubtask",
        "summary": "Delete a subtask",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "204": {
            "description": "The subtask was deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/cards/{id}/links": {
      "get": {
        "tags": [
          "Links"
        ],
        "operationId": "listCardLinks",
        "summary": "Get card links",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The links on the card.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/CardLink"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "Links"
        ],
        "operationId": "createCardLink",
        "summary": "Create a card link",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "targetId",
                  "linkType"
                ],
                "properties": {
                  "targetId": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "linkType": {
                    "type": "string",
                    "enum": [
                      "relates_to",
                      "blocks",
                      "duplicates",
                      "is_part_of"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/links/{id}": {
      "delete": {
        "tags": [
          "Links"
        ],
        "operationId": "deleteCardLink",
        "summary": "Delete a card link",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "204": {
            "description": "The link was deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/projects/{projectId}/links": {
      "get": {
        "tags": [
          "Links"
        ],
        "operationId": "listProjectLinks",
        "summary": "List the project's stored links",
        "description": "The project link store, newest first, each row with its evaluated\nrelevance. `relevance=unrated` names rows nothing has evaluated yet.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "in": "query",
            "name": "relevance",
            "schema": {
              "$ref": "#/components/schemas/ProjectLinkRelevance"
            }
          },
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          },
          {
            "in": "query",
            "name": "offset",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the store.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "links",
                    "total",
                    "limit",
                    "offset"
                  ],
                  "properties": {
                    "links": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ProjectLink"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "Links"
        ],
        "operationId": "submitProjectLink",
        "summary": "Submit a link to the project",
        "description": "Stores the URL and evaluates its relevance against the board before\nanswering — the same URL on a card, the same host as existing\nreferences, shared terms with cards and labels. The server never\nfetches the URL; supply the title and a note. The same page submitted\ntwice (tracking parameters, fragment and trailing slash ignored)\nanswers the existing row with `created: false` and status 200.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "maxLength": 2048
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "tags": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The page was already stored; this is the existing row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectLinkSubmission"
                }
              }
            }
          },
          "201": {
            "description": "The link was stored and evaluated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProjectLinkSubmission"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/projects/{projectId}/links/{linkId}": {
      "patch": {
        "tags": [
          "Links"
        ],
        "operationId": "reviewProjectLink",
        "summary": "Review a stored link",
        "description": "Edits the title, note or tags, or overrules the evaluated relevance.\nA reviewed `relevance` is recorded with `evaluation_source: human`\nand the reviewer; the heuristic's score and evidence are cleared.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/LinkId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 200,
                    "nullable": true
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 2000,
                    "nullable": true
                  },
                  "tags": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "maxLength": 50
                    }
                  },
                  "relevance": {
                    "type": "string",
                    "enum": [
                      "none",
                      "low",
                      "medium",
                      "high"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Why you decided that relevance. Requires `relevance`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated link.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "link"
                  ],
                  "properties": {
                    "link": {
                      "$ref": "#/components/schemas/ProjectLink"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "tags": [
          "Links"
        ],
        "operationId": "deleteProjectLink",
        "summary": "Remove a stored link",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/LinkId"
          }
        ],
        "responses": {
          "200": {
            "description": "The link was removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/projects/{projectId}/links/{linkId}/evaluate": {
      "post": {
        "tags": [
          "Links"
        ],
        "operationId": "evaluateProjectLink",
        "summary": "Evaluate a stored link again",
        "description": "Runs the board evaluation again — the board has moved since the link\nwas submitted, or a human review should give way to the heuristic.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/ProjectId"
          },
          {
            "$ref": "#/components/parameters/LinkId"
          }
        ],
        "responses": {
          "200": {
            "description": "The re-evaluated link.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "link"
                  ],
                  "properties": {
                    "link": {
                      "$ref": "#/components/schemas/ProjectLink"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/cards/{id}/prompt": {
      "get": {
        "tags": [
          "Agents"
        ],
        "operationId": "generateCardPrompt",
        "summary": "Generate an AI-ready prompt from a card",
        "description": "Builds role framing, focus areas, subtasks, and linked cards into one\nprompt an agent can work from.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "in": "query",
            "name": "variant",
            "description": "`analysis` to understand and plan, `draft` to design a solution,\n`execute` to implement fully. Defaults to `execute`.\n",
            "schema": {
              "type": "string",
              "enum": [
                "analysis",
                "draft",
                "execute"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The generated prompt.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "prompt": {
                      "type": "string"
                    },
                    "variant": {
                      "type": "string",
                      "enum": [
                        "analysis",
                        "draft",
                        "execute"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/nlu": {
      "post": {
        "tags": [
          "NLU"
        ],
        "operationId": "processCommand",
        "summary": "Process a natural-language command",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "command"
                ],
                "properties": {
                  "command": {
                    "type": "string"
                  }
                }
              },
              "example": {
                "command": "move card 42 to review"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The interpreted command and what it did.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/desktop/releases/latest": {
      "get": {
        "tags": [
          "Desktop"
        ],
        "operationId": "getLatestDesktopRelease",
        "summary": "Latest published desktop build",
        "description": "The manifest for the newest Harmony Quickbar build. The desktop app\npolls this at launch and every 24 hours to decide whether to offer an\nupdate.\n\n`version` is always bare three-segment semver — no `v` prefix, no\nsurrounding whitespace, never four segments. The desktop client refuses\nanything else instead of cleaning it up, and refusing shows as \"no\nupdate\" rather than as an error, so the shape is part of the contract\nrather than a formatting preference.\n\nThe manifest carries no download URL on purpose. Use\n`GET /v1/desktop/download` for the bytes, or send a person to\n`/user/apps`.\n",
        "parameters": [
          {
            "in": "query",
            "name": "platform",
            "required": false,
            "schema": {
              "type": "string",
              "default": "darwin-arm64"
            },
            "description": "Which build to describe. Only `darwin-arm64` is published today."
          }
        ],
        "responses": {
          "200": {
            "description": "The newest build for that platform.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "version",
                    "notes",
                    "sha256",
                    "sizeBytes",
                    "publishedAt"
                  ],
                  "properties": {
                    "version": {
                      "type": "string",
                      "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$"
                    },
                    "notes": {
                      "type": "string"
                    },
                    "sha256": {
                      "type": "string",
                      "pattern": "^[0-9a-f]{64}$"
                    },
                    "sizeBytes": {
                      "type": "integer"
                    },
                    "publishedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "version": "0.2.0",
                  "notes": "Faster panel.",
                  "sha256": "b847cd8b6fc9742740b5cc5773c89abd4b4b177147fedabeb120a51fd8788175",
                  "sizeBytes": 119086531,
                  "publishedAt": "2026-09-10T18:00:00.000Z"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Nothing is published for that platform yet."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/desktop/download": {
      "get": {
        "tags": [
          "Desktop"
        ],
        "operationId": "downloadDesktopRelease",
        "summary": "Download the latest desktop build",
        "description": "Redirects to a short-lived signed URL for the build's bytes. The bytes\nnever pass through the API.\n\nTwo response shapes, because a browser and a command line cannot use\nthe same one. By default the answer is a `302`, which is what `curl -L`\nwants. A browser cannot put a credential header on a top-level\nnavigation, so it cannot follow a `302` on an authenticated route at\nall; `?redirect=false` returns the signed URL as JSON for it to\nnavigate to instead.\n",
        "parameters": [
          {
            "in": "query",
            "name": "platform",
            "required": false,
            "schema": {
              "type": "string",
              "default": "darwin-arm64"
            }
          },
          {
            "in": "query",
            "name": "redirect",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "false"
              ]
            },
            "description": "Set to `false` to receive the signed URL as JSON instead of a 302."
          }
        ],
        "responses": {
          "200": {
            "description": "The signed URL, when `redirect=false` was passed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "url",
                    "expiresIn",
                    "version",
                    "sha256",
                    "sizeBytes"
                  ],
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "expiresIn": {
                      "type": "integer",
                      "description": "Seconds the URL stays valid."
                    },
                    "version": {
                      "type": "string"
                    },
                    "sha256": {
                      "type": "string"
                    },
                    "sizeBytes": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "302": {
            "description": "Redirect to the signed URL for the build.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "Nothing is published for that platform yet."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/desktop/updates/{platform}/{file}": {
      "get": {
        "tags": [
          "Desktop"
        ],
        "operationId": "getDesktopUpdateFile",
        "summary": "The auto-update feed",
        "description": "The base URL electron-updater's generic provider reads, as a redirect to\na short-lived signed URL. This is a subtree, not a single object: the\nupdater fetches `latest-mac.yml` at the base and then resolves each\nartifact reference in that file against the same base, so both the\nchannel file and `<version>/<artifact>` come through here.\n\nIt exists because the generic provider cannot read the JSON manifest at\n`/v1/desktop/releases/latest` — it wants YAML and `sha512`, while that\nroute answers JSON with `sha256`. What the two share is the storage\nbucket and the credential, not the manifest. The bucket is private with\nno read policy, so this route is the only way a desktop client can\nreach it.\n\nOnly paths that look like an update feed resolve: at most\n`<version>/<file>` deep, and only `.yml`, `.zip`, `.blockmap` and\n`.dmg`. Anything else is a `404`, which is also what the updater reads\nas \"nothing published for this platform\".\n",
        "parameters": [
          {
            "in": "path",
            "name": "platform",
            "required": true,
            "schema": {
              "type": "string",
              "default": "darwin-arm64"
            },
            "description": "Lowercase alphanumerics, `-` and `_`. Only `darwin-arm64` is published today."
          },
          {
            "in": "path",
            "name": "file",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`latest-mac.yml`, or `<version>/<artifact>` for the bytes.\n"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to the signed URL for the file.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such file for that platform."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "IntakeKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Intake-Key",
        "description": "An intake token (starts with `hmy_in_`). It is minted against one board\ncolumn and can do exactly one thing: file a card into that column. It\nis not an API key, it never becomes a session, and it is refused on\nevery other endpoint in this document.\n\n**The token must never ship in client code.** `Access-Control-Allow-Origin`\nis a fixed list, so a browser on an arbitrary origin cannot read the\nresponse — but a token in a bundle is a token anyone can read and use\nfrom anywhere. Call `/v1/intake` from a server, a webhook, or a script.\n"
      },
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key generated at https://gethmy.com/user/keys (starts with `hmy_`).\nIt acts for the user who created it, across every workspace that user\nbelongs to.\n"
      },
      "OAuth2": {
        "type": "oauth2",
        "description": "OAuth 2.1 with PKCE. Dynamic client registration (RFC 7591) and\nauthorization server metadata (RFC 8414) are published at\nhttps://app.gethmy.com/.well-known/oauth-authorization-server. The\nprotected-resource metadata for this API (RFC 9728) is at\nhttps://gethmy.com/.well-known/oauth-protected-resource/api.\n\nBeyond the `mcp` scope, each grant is bound at consent time to the set\nof workspaces the user selected. A request outside that set is refused\nwith `403`.\n",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://app.gethmy.com/oauth/authorize",
            "tokenUrl": "https://app.gethmy.com/oauth/token",
            "refreshUrl": "https://app.gethmy.com/oauth/token",
            "scopes": {
              "mcp": "Read and write the cards, columns, labels, subtasks, links, and\nagent sessions of the workspaces this grant covers.\n"
            }
          }
        }
      }
    },
    "parameters": {
      "Id": {
        "in": "path",
        "name": "id",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ProjectId": {
        "in": "path",
        "name": "projectId",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "LinkId": {
        "in": "path",
        "name": "linkId",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request was malformed or missing a required field.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No credential, or the credential is invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Missing API key or Authorization header"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The credential is valid but does not cover this workspace. An OAuth\ntoken scoped to one set of workspaces cannot act on another.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "OAuth token is scoped to a different workspace"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such resource, or the credential cannot see it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Card not found"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests for this user.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "error": "Rate limit exceeded. Please try again later."
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A human-readable description of what went wrong."
          }
        }
      },
      "Health": {
        "type": "object",
        "required": [
          "status",
          "service"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "service": {
            "type": "string",
            "const": "harmony-api"
          }
        }
      },
      "ApiIndex": {
        "type": "object",
        "description": "The public index of this API. Lists the spec, the accepted credentials,\nand the endpoints.\n",
        "required": [
          "status",
          "service",
          "name",
          "baseUrl"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "service": {
            "type": "string",
            "const": "harmony-api"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "baseUrl": {
            "type": "string",
            "format": "uri"
          },
          "documentation": {
            "type": "object",
            "additionalProperties": {
              "type": "string",
              "format": "uri"
            }
          },
          "authentication": {
            "type": "object",
            "properties": {
              "required": {
                "type": "boolean"
              },
              "schemes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "publicEndpoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EndpointSummary"
            }
          },
          "endpoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EndpointSummary"
            }
          },
          "contact": {
            "type": "object",
            "properties": {
              "email": {
                "type": "string",
                "format": "email"
              },
              "url": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "EndpointSummary": {
        "type": "object",
        "required": [
          "method",
          "path"
        ],
        "properties": {
          "method": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "summary": {
            "type": "string"
          }
        }
      },
      "Workspace": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "role": {
            "type": "string",
            "description": "The calling user's role in this workspace."
          }
        }
      },
      "WorkspaceMember": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "format": "uuid"
          },
          "role": {
            "type": "string"
          },
          "full_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "avatar_url": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "Project": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workspace_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Column": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "position": {
            "type": "integer"
          }
        }
      },
      "Label": {
        "type": "object",
        "required": [
          "id",
          "name"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string"
          }
        }
      },
      "Subtask": {
        "type": "object",
        "required": [
          "id",
          "title"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "card_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "completed": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          }
        }
      },
      "CardLink": {
        "type": "object",
        "required": [
          "id",
          "link_type"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "source_card_id": {
            "type": "string",
            "format": "uuid"
          },
          "target_card_id": {
            "type": "string",
            "format": "uuid"
          },
          "link_type": {
            "type": "string",
            "enum": [
              "relates_to",
              "blocks",
              "duplicates",
              "is_part_of"
            ]
          }
        }
      },
      "ProjectLinkRelevance": {
        "type": "string",
        "enum": [
          "unrated",
          "none",
          "low",
          "medium",
          "high"
        ]
      },
      "ProjectLink": {
        "type": "object",
        "description": "A URL submitted to a project and its evaluation. `relevance_evidence`\nnames the cards and labels the evaluation matched, so the level can\nbe checked against the board rather than taken on trust.\n",
        "required": [
          "id",
          "project_id",
          "url",
          "normalized_url",
          "tags",
          "source",
          "relevance",
          "relevance_evidence",
          "created_at",
          "updated_at"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "normalized_url": {
            "type": "string",
            "description": "The dedup key — lowercase host without `www.`, no fragment, no tracking parameters, no trailing slash."
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "note": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "source": {
            "type": "string",
            "enum": [
              "jwt",
              "api_key",
              "oauth"
            ],
            "description": "The credential the submission arrived with."
          },
          "relevance": {
            "$ref": "#/components/schemas/ProjectLinkRelevance"
          },
          "relevance_score": {
            "type": "number",
            "nullable": true,
            "minimum": 0,
            "maximum": 1
          },
          "relevance_reason": {
            "type": "string",
            "nullable": true
          },
          "relevance_evidence": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "evaluation_source": {
            "type": "string",
            "nullable": true,
            "enum": [
              "heuristic",
              "model",
              "human"
            ]
          },
          "evaluated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "evaluated_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_by": {
            "type": "string",
            "format": "uuid",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProjectLinkSubmission": {
        "type": "object",
        "required": [
          "link",
          "created"
        ],
        "properties": {
          "link": {
            "$ref": "#/components/schemas/ProjectLink"
          },
          "created": {
            "type": "boolean",
            "description": "False when the page was already stored and the existing row is returned."
          }
        }
      },
      "Priority": {
        "type": "string",
        "enum": [
          "low",
          "medium",
          "high",
          "urgent"
        ]
      },
      "Card": {
        "type": "object",
        "description": "A card. The API returns the stored row plus its hydrated relations, so\nfields beyond the ones named here may appear.\n",
        "additionalProperties": true,
        "required": [
          "id",
          "title",
          "project_id",
          "column_id"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "short_id": {
            "type": "integer",
            "description": "The per-project number a card is referenced by, e.g. 42."
          },
          "project_id": {
            "type": "string",
            "format": "uuid"
          },
          "column_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "assignee_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "due_date": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "estimate_hours": {
            "type": [
              "number",
              "null"
            ]
          },
          "position": {
            "type": "number"
          },
          "done": {
            "type": "boolean"
          },
          "archived_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "labelIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "subtasks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Subtask"
            }
          },
          "column": {
            "$ref": "#/components/schemas/Column"
          }
        }
      },
      "CardCreate": {
        "type": "object",
        "required": [
          "projectId",
          "title"
        ],
        "properties": {
          "projectId": {
            "type": "string",
            "format": "uuid"
          },
          "columnId": {
            "type": "string",
            "format": "uuid",
            "description": "The column to create the card in. Must belong to `projectId` — a column from another project is refused with 400, and an unknown one with 404. Omit it to use the project's default column (its `is_default` column, else the leftmost)."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          }
        }
      },
      "CardUpdate": {
        "type": "object",
        "description": "Only the fields present are changed.",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "priority": {
            "$ref": "#/components/schemas/Priority"
          },
          "done": {
            "type": "boolean"
          },
          "assigneeId": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "dueDate": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Board": {
        "type": "object",
        "description": "The full board state for one project.",
        "properties": {
          "project": {
            "$ref": "#/components/schemas/Project"
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Column"
            }
          },
          "cards": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Card"
            }
          },
          "labels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Label"
            }
          }
        }
      }
    }
  }
}
