{
  "openapi": "3.1.0",
  "info": {
    "title": "Struvera Integration API",
    "version": "1.2.0",
    "summary": "Read and write the architecture model, push events, propose changes for approval, and manage workspaces.",
    "description": "Token-authenticated API for integration platforms (for example Workato), ITSM tools such as ServiceDesk Plus or ServiceNow, and work trackers such as Azure DevOps or Jira. Create tokens in the workspace page (admins only). Tokens work only under /api/v1; session cookies are not accepted there. Reads stay available when a trial has expired; writes follow the same rule as model edits. Version 1.1 added write endpoints (upsert, delete, CSV import), OAuth 2.0 client credentials and a public status check. Version 1.2 (the platform API) covers every element type, including comments, benefits, controls, custom types, baselines and workflows; adds paging, filters, ETags with If-Match and rate-limit headers; adds proposals (changes that wait for a person to approve them, also available as MCP write tools); and documents the signed-in endpoints for sandboxes, save hooks, custom panels and per-sheet partial saves. Every /v1 answer carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset.",
    "license": {
      "name": "Proprietary",
      "identifier": "LicenseRef-Proprietary"
    }
  },
  "servers": [
    {
      "url": "/api",
      "description": "This deployment"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Model",
      "description": "Read the tenant model."
    },
    {
      "name": "Events",
      "description": "Incidents, changes and work items mapped to systems."
    },
    {
      "name": "Write",
      "description": "Create, update and delete model elements. Needs a write token."
    },
    {
      "name": "Import",
      "description": "Bulk load from a CSV, for example a CMDB export."
    },
    {
      "name": "Auth",
      "description": "OAuth 2.0 client credentials."
    },
    {
      "name": "Status",
      "description": "Public health check."
    },
    {
      "name": "Processes",
      "description": "BPMN process models, L0 value chain to L5 work instruction: list, read, create or update, link shapes to the model, lay out, and import or export BPMN 2.0. The same models the app canvas draws."
    },
    {
      "name": "Governance",
      "description": "Comments, baselines and proposals."
    },
    {
      "name": "Benefits and controls",
      "description": "Benefits, measurements, frameworks, controls and control mappings."
    },
    {
      "name": "Custom types",
      "description": "Types, fields, relationship types, elements and relationships you define."
    },
    {
      "name": "Workflows",
      "description": "Workflow definitions and runs (read only)."
    },
    {
      "name": "Workspace",
      "description": "Signed-in (cookie) endpoints used by the app: partial saves, sandboxes, save hooks, custom panels and the Review queue."
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol server for AI agents."
    }
  ],
  "paths": {
    "/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "operationId": "mcp",
        "summary": "Model Context Protocol (JSON-RPC 2.0 over HTTP)",
        "description": "initialize, tools/list and tools/call. Read tools: list_capabilities, list_systems, get_system, impact_of_retiring_system, search_model, list_open_events, list_elements, get_element, list_processes, get_process, export_process_bpmn. A write token also sees propose_change, list_proposals and the process tools propose_process, link_process_step, layout_process and import_process_bpmn: each files a proposal that waits in the Review queue; none writes. See docs/MCP.md.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/call",
                "params": {
                  "name": "propose_change",
                  "arguments": {
                    "type": "systems",
                    "action": "upsert",
                    "item": {
                      "id": "SYS-100",
                      "lifecycle_status": "Retire"
                    },
                    "reason": "End of support announced"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/model": {
      "patch": {
        "tags": [
          "Workspace"
        ],
        "operationId": "patchWorkspaceModel",
        "summary": "Save only the sheets you changed",
        "description": "Per-sheet partial save. Each sheet carries the version it was loaded at; a sheet someone else changed meanwhile is refused (409, nothing saved) but changes to other sheets are kept. The whole-document PUT /model stays available and is the fallback. Version of a sheet = sheetHash(rows), shown in the response as versions.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Malformed patch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Trial ended.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "sheet_conflict: names the sheets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "A save hook refused the save.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartialSave"
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Workspace"
        ],
        "operationId": "putWorkspaceModel",
        "summary": "Save the whole model",
        "description": "The original whole-document save. Send baseUpdatedAt to be refused (409) if someone saved since. Add ?sandbox=<id> to save a sandbox copy instead.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "data"
                ],
                "properties": {
                  "data": {
                    "type": "object"
                  },
                  "baseUpdatedAt": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "sandbox",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "getWorkspaceModel",
        "summary": "Load the whole model",
        "description": "Add ?sandbox=<id> to load a sandbox copy.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "parameters": [
          {
            "name": "sandbox",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/oauth/token": {
      "post": {
        "tags": [
          "Auth"
        ],
        "operationId": "oauthToken",
        "summary": "Get an access token (client credentials)",
        "security": [],
        "description": "Send grant_type=client_credentials with client_id and client_secret in the form body, or the pair as HTTP Basic. Returns a 1-hour bearer token that /api/v1 and /mcp accept like an API token. Optional scope (read or write) can only narrow the client's scope. Revoking the client ends its tokens at once.",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "client_credentials"
                    ]
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "client_secret": {
                    "type": "string"
                  },
                  "scope": {
                    "type": "string",
                    "enum": [
                      "read",
                      "write"
                    ]
                  }
                }
              },
              "example": "grant_type=client_credentials&client_id=svc_AbCd1234&client_secret=svs_..."
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                },
                "example": {
                  "access_token": "svo_Zm9vYmFyYmF6cXV4",
                  "token_type": "Bearer",
                  "expires_in": 3600,
                  "scope": "write"
                }
              }
            }
          },
          "400": {
            "description": "unsupported_grant_type or invalid_scope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_client.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/panels": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "listPanels",
        "summary": "List installed custom panels",
        "description": "Any signed-in member. Names only; the page is served by /panels/{id}/frame.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "installPanel",
        "summary": "Install or update a custom panel",
        "description": "Admin only. html is one self-contained page (inline script and style, up to 200 KB; no iframe, object, embed or base tags). It runs in an iframe with sandbox=\"allow-scripts\" and a Content-Security-Policy that blocks all network access, and talks to the app only through window.Struvera (postMessage): getContext, sheets, listRows, getRow, navigate, resize, toast. Read only. Send id to update. Up to 10 panels.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "Installed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "description": "Over 200 KB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "html"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "label": {
                    "type": "string"
                  },
                  "html": {
                    "type": "string"
                  },
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/panels/{id}/frame": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "panelFrame",
        "summary": "The panel page (for the iframe)",
        "description": "Served with Content-Security-Policy: default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; connect-src 'none'; sandbox allow-scripts, and X-Frame-Options: SAMEORIGIN.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "HTML.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/panels/remove": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "removePanel",
        "summary": "Remove a custom panel",
        "description": "Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/proposals": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "reviewQueue",
        "summary": "Proposals waiting in the Review queue",
        "description": "Editors and admins. canDecide says whether you may approve.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "applied",
                "rejected",
                "failed"
              ]
            }
          }
        ]
      }
    },
    "/proposals/decide": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "decideProposal",
        "summary": "Approve or reject a proposal",
        "description": "Admin, or an editor named in the Config approvers row. Approving runs the normal write path as the approver (roles, snapshot, audit, workflows, webhooks apply). 409 if already decided.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id",
                  "decision"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "decision": {
                    "enum": [
                      "approve",
                      "reject"
                    ]
                  },
                  "note": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sandboxes": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "listSandboxes",
        "summary": "List sandbox copies",
        "description": "Each says whether the real workspace changed since it was cloned.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "createSandbox",
        "summary": "Clone the workspace into a sandbox",
        "description": "Editors and admins. At most 3 sandboxes. Open it in the app with ?sandbox=<id>; nothing in a sandbox reaches the real workspace (no webhooks, alerts, workflows or save hooks).",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Limit reached.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 60
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sandboxes/delete": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "deleteSandbox",
        "summary": "Delete a sandbox",
        "description": "Admin, or the person who made it.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/sandboxes/diff": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "diffSandbox",
        "summary": "What a sandbox changes",
        "description": "Per sheet: what the sandbox changed, what the real workspace changed since the clone, and sheets changed on both sides.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/sandboxes/promote": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "promoteSandbox",
        "summary": "Promote a sandbox into the real workspace",
        "description": "Admin only. Per-sheet three-way merge: sheets changed only in the sandbox are taken, sheets changed only in the real workspace are kept. A sheet changed on both sides is a 409 until you choose with resolve ({\"Systems\":\"sandbox\"|\"main\"}) or send force. The normal save path runs: snapshot, audit, roles, workflows, webhooks. The sandbox is removed afterwards.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Conflicting sheets; nothing written.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  },
                  "resolve": {
                    "type": "object",
                    "additionalProperties": {
                      "enum": [
                        "sandbox",
                        "main"
                      ]
                    }
                  },
                  "force": {
                    "type": "boolean"
                  },
                  "dry_run": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/save-hooks": {
      "get": {
        "tags": [
          "Workspace"
        ],
        "operationId": "listSaveHooks",
        "summary": "List save hooks",
        "description": "Admin only. Shows the last status, response time and failure count of each.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "createSaveHook",
        "summary": "Register a save hook",
        "description": "Admin only. phase before: called before the save is stored with the sheets and ids that change (never row contents); {\"allow\":false,\"message\":\"...\"} refuses the save (422). A timeout or error follows on_error (allow, the default, or block). phase after: called in the background after the save. timeout_ms 500 to 5000 (default 3000). Calls are signed (X-Struvera-Signature: t=<unix>,v1=<HMAC-SHA256 of t.body>). Up to 5 hooks. The secret is shown once.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "phase"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "phase": {
                    "enum": [
                      "before",
                      "after"
                    ]
                  },
                  "on_error": {
                    "enum": [
                      "allow",
                      "block"
                    ]
                  },
                  "timeout_ms": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/save-hooks/revoke": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "revokeSaveHook",
        "summary": "Remove a save hook",
        "description": "Admin only.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/save-hooks/test": {
      "post": {
        "tags": [
          "Workspace"
        ],
        "operationId": "testSaveHook",
        "summary": "Send a sample call to a save hook",
        "description": "Admin only. Answers with what the hook said and how long it took.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "description": "Not signed in.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "id"
                ],
                "properties": {
                  "id": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/status": {
      "get": {
        "tags": [
          "Status"
        ],
        "operationId": "getStatus",
        "summary": "Health check",
        "security": [],
        "description": "Public, no token. 200 when the database answers, 503 when it does not. Point an uptime monitor here.",
        "responses": {
          "200": {
            "description": "Healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "down"
                      ]
                    },
                    "db": {
                      "type": "object",
                      "properties": {
                        "ok": {
                          "type": "boolean"
                        },
                        "ms": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        }
                      }
                    },
                    "version": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "time": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "db": {
                    "ok": true,
                    "ms": 12
                  },
                  "version": "0.2.0",
                  "time": "2026-11-06T09:02:50.439Z"
                }
              }
            }
          },
          "503": {
            "description": "Database unreachable."
          }
        }
      }
    },
    "/v1/baselines": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "listBaselines",
        "summary": "List baselines and scenarios",
        "description": "Name, date, author and note of each snapshot. The snapshot content is not included.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "The snapshots.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "rows": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Baseline"
                      }
                    },
                    "updatedAt": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Governance"
        ],
        "operationId": "createBaseline",
        "summary": "Save a baseline of the model as it is now",
        "description": "Requires a write token. Stores a full copy of the model inside the model (the same as Baselines & Compare in the app). At most 12 baselines and scenarios; names are unique per kind.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "note": {
                    "type": "string",
                    "maxLength": 1000
                  },
                  "kind": {
                    "enum": [
                      "baseline",
                      "scenario"
                    ],
                    "default": "baseline"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "baseline_id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "kind": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Name missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "Name taken, or 12 snapshots already.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "The model would pass the size cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/baselines/{id}": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "getBaseline",
        "summary": "One baseline, or one sheet of its snapshot",
        "description": "Add include=snapshot&sheet=Systems to read the rows of one sheet as they were in the snapshot.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The baseline id, for example BL-001."
          },
          {
            "name": "include",
            "in": "query",
            "schema": {
              "enum": [
                "snapshot"
              ]
            }
          },
          {
            "name": "sheet",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Required with include=snapshot."
          }
        ],
        "responses": {
          "200": {
            "description": "The baseline, or the snapshot rows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "sheet missing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Governance"
        ],
        "operationId": "deleteBaseline",
        "summary": "Delete a baseline",
        "description": "Requires a write token.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The baseline id, for example BL-001."
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/benefit-measures": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "listBenefitMeasures",
        "summary": "List benefit measurements",
        "description": "Sheet BenefitMeasures. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "upsertBenefitMeasures",
        "summary": "Create or update benefit measurements",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/BenefitMeasuresInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/BenefitMeasuresInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "benefit_id": "existing-id",
                "period": "Example period",
                "actual": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "BM-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/benefit-measures/{id}": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "getBenefitMeasure",
        "summary": "Get one benefit measurement",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "patchBenefitMeasure",
        "summary": "Change fields of one benefit measurement",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BenefitMeasuresInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "putBenefitMeasure",
        "summary": "Create or update one benefit measurement at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BenefitMeasuresInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "deleteBenefitMeasure",
        "summary": "Delete one benefit measurement",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/benefits": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "listBenefits",
        "summary": "List benefits",
        "description": "Sheet BC_Benefits. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "upsertBenefits",
        "summary": "Create or update benefits",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/BenefitsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/BenefitsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "benefit_name": "Example benefit name"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "BEN-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/benefits/{id}": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "getBenefit",
        "summary": "Get one benefit",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "patchBenefit",
        "summary": "Change fields of one benefit",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BenefitsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "putBenefit",
        "summary": "Create or update one benefit at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BenefitsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "deleteBenefit",
        "summary": "Delete one benefit",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/capabilities": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "listCapabilities",
        "summary": "List capabilitys",
        "description": "Sheet Capabilities. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Write"
        ],
        "operationId": "upsertCapabilities",
        "summary": "Create or update capabilities",
        "description": "Requires a write token. Upsert by id, or by external_id when id is absent. Send one object or {items:[...]} (up to 100). Unknown fields and unknown references are rejected per item. The write goes through the same snapshot, version history and audit trail as an app save, and answers 409 if the model changed meanwhile. 200 if any item was accepted, 422 if none.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ElementInput"
                  },
                  {
                    "$ref": "#/components/schemas/ElementBatch"
                  }
                ]
              },
              "example": {
                "id": "C10",
                "capability_name": "Recruiting",
                "capability_group": "People"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "C10",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or more than 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/capabilities/{id}": {
      "delete": {
        "tags": [
          "Write"
        ],
        "operationId": "deleteCapability",
        "summary": "Delete a capability",
        "description": "Requires a write token. Refused with 409 in_use while any other row still references the item (maps, integrations, projects, roadmap, gaps, design references, events). Remove or re-point those in the app first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The row id."
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Delete by your external_id instead (the path id is then ignored)."
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": "S10",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "in_use (still referenced) or conflict (the model changed meanwhile; send it again).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "in_use",
                  "message": "System S1 is still referenced. Remove or re-point those rows in the app first.",
                  "referenced_by": {
                    "Integrations": 1,
                    "CapabilitySystemMap": 2
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getCapability",
        "summary": "Get one capability",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Write"
        ],
        "operationId": "patchCapability",
        "summary": "Change fields of one capability",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CapabilitiesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Write"
        ],
        "operationId": "putCapability",
        "summary": "Create or update one capability at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CapabilitiesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/comments": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "listComments",
        "summary": "List comments",
        "description": "Sheet Comments. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Governance"
        ],
        "operationId": "upsertComments",
        "summary": "Create or update comments",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CommentsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CommentsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "element_type": "Example element type",
                "element_id": "Example element id",
                "text": "Example text"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "CM-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/comments/{id}": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "getComment",
        "summary": "Get one comment",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Governance"
        ],
        "operationId": "patchComment",
        "summary": "Change fields of one comment",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Governance"
        ],
        "operationId": "putComment",
        "summary": "Create or update one comment at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CommentsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Governance"
        ],
        "operationId": "deleteComment",
        "summary": "Delete one comment",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/control-map": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "listControlMap",
        "summary": "List control mappings",
        "description": "Sheet ControlMap. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "upsertControlMap",
        "summary": "Create or update control mappings",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ControlMapInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/ControlMapInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "control_id": "existing-id",
                "element_type": "Example element type",
                "element_id": "Example element id"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "CM-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/control-map/{id}": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "getControlMap",
        "summary": "Get one control mapping",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "patchControlMap",
        "summary": "Change fields of one control mapping",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControlMapInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "putControlMap",
        "summary": "Create or update one control mapping at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControlMapInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "deleteControlMap",
        "summary": "Delete one control mapping",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/controls": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "listControls",
        "summary": "List controls",
        "description": "Sheet Controls. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "upsertControls",
        "summary": "Create or update controls",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ControlsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/ControlsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "framework_id": "existing-id",
                "control_title": "Example control title"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "CTL-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/controls/{id}": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "getControl",
        "summary": "Get one control",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "patchControl",
        "summary": "Change fields of one control",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControlsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "putControl",
        "summary": "Create or update one control at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ControlsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "deleteControl",
        "summary": "Delete one control",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-elements": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "listCustomElements",
        "summary": "List custom elements",
        "description": "Sheet CustomElements. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Custom types"
        ],
        "operationId": "upsertCustomElements",
        "summary": "Create or update custom elements",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CustomElementsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CustomElementsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "type_id": "existing-id",
                "element_name": "Example element name"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "CE-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-elements/{id}": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "getCustomElement",
        "summary": "Get one custom element",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom types"
        ],
        "operationId": "patchCustomElement",
        "summary": "Change fields of one custom element",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomElementsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Custom types"
        ],
        "operationId": "putCustomElement",
        "summary": "Create or update one custom element at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomElementsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom types"
        ],
        "operationId": "deleteCustomElement",
        "summary": "Delete one custom element",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-fields": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "listCustomFields",
        "summary": "List custom fields",
        "description": "Sheet MetaFields. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Custom types"
        ],
        "operationId": "upsertCustomFields",
        "summary": "Create or update custom fields",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CustomFieldsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CustomFieldsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "owner": "Example owner",
                "field_name": "Example field name",
                "field_type": "Example field type"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "MF-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-fields/{id}": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "getCustomField",
        "summary": "Get one custom field",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom types"
        ],
        "operationId": "patchCustomField",
        "summary": "Change fields of one custom field",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomFieldsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Custom types"
        ],
        "operationId": "putCustomField",
        "summary": "Create or update one custom field at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomFieldsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom types"
        ],
        "operationId": "deleteCustomField",
        "summary": "Delete one custom field",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-relation-types": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "listCustomRelationTypes",
        "summary": "List custom relationship types",
        "description": "Sheet MetaRelTypes. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Custom types"
        ],
        "operationId": "upsertCustomRelationTypes",
        "summary": "Create or update custom relationship types",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CustomRelationTypesInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CustomRelationTypesInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "reltype_name": "Example reltype name",
                "from_type": "Example from type",
                "to_type": "Example to type"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "MR-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-relation-types/{id}": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "getCustomRelationType",
        "summary": "Get one custom relationship type",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom types"
        ],
        "operationId": "patchCustomRelationType",
        "summary": "Change fields of one custom relationship type",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRelationTypesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Custom types"
        ],
        "operationId": "putCustomRelationType",
        "summary": "Create or update one custom relationship type at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRelationTypesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom types"
        ],
        "operationId": "deleteCustomRelationType",
        "summary": "Delete one custom relationship type",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-relations": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "listCustomRelations",
        "summary": "List custom relationships",
        "description": "Sheet CustomRelations. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Custom types"
        ],
        "operationId": "upsertCustomRelations",
        "summary": "Create or update custom relationships",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CustomRelationsInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CustomRelationsInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "reltype_id": "existing-id",
                "from_id": "Example from id",
                "to_id": "Example to id"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "CR-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-relations/{id}": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "getCustomRelation",
        "summary": "Get one custom relationship",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom types"
        ],
        "operationId": "patchCustomRelation",
        "summary": "Change fields of one custom relationship",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRelationsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Custom types"
        ],
        "operationId": "putCustomRelation",
        "summary": "Create or update one custom relationship at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomRelationsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom types"
        ],
        "operationId": "deleteCustomRelation",
        "summary": "Delete one custom relationship",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-types": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "listCustomTypes",
        "summary": "List custom types",
        "description": "Sheet MetaTypes. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Custom types"
        ],
        "operationId": "upsertCustomTypes",
        "summary": "Create or update custom types",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CustomTypesInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/CustomTypesInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "type_name": "Example type name"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "MT-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/custom-types/{id}": {
      "get": {
        "tags": [
          "Custom types"
        ],
        "operationId": "getCustomType",
        "summary": "Get one custom type",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Custom types"
        ],
        "operationId": "patchCustomType",
        "summary": "Change fields of one custom type",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomTypesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Custom types"
        ],
        "operationId": "putCustomType",
        "summary": "Create or update one custom type at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomTypesInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Custom types"
        ],
        "operationId": "deleteCustomType",
        "summary": "Delete one custom type",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/data-objects": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "listDataObjects",
        "summary": "List dataobjects",
        "description": "Sheet DataObjects. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Write"
        ],
        "operationId": "upsertDataObjects",
        "summary": "Create or update data objects",
        "description": "Requires a write token. Upsert by id, or by external_id when id is absent. Send one object or {items:[...]} (up to 100). Unknown fields and unknown references are rejected per item. The write goes through the same snapshot, version history and audit trail as an app save, and answers 409 if the model changed meanwhile. 200 if any item was accepted, 422 if none.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ElementInput"
                  },
                  {
                    "$ref": "#/components/schemas/ElementBatch"
                  }
                ]
              },
              "example": {
                "id": "D10",
                "object_name": "Employee"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "D10",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or more than 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/data-objects/{id}": {
      "delete": {
        "tags": [
          "Write"
        ],
        "operationId": "deleteDataObject",
        "summary": "Delete a data object",
        "description": "Requires a write token. Refused with 409 in_use while any other row still references the item (maps, integrations, projects, roadmap, gaps, design references, events). Remove or re-point those in the app first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The row id."
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Delete by your external_id instead (the path id is then ignored)."
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": "S10",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "in_use (still referenced) or conflict (the model changed meanwhile; send it again).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "in_use",
                  "message": "System S1 is still referenced. Remove or re-point those rows in the app first.",
                  "referenced_by": {
                    "Integrations": 1,
                    "CapabilitySystemMap": 2
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getDataObject",
        "summary": "Get one dataobject",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Write"
        ],
        "operationId": "patchDataObject",
        "summary": "Change fields of one dataobject",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DataObjectsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Write"
        ],
        "operationId": "putDataObject",
        "summary": "Create or update one dataobject at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DataObjectsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/events": {
      "get": {
        "tags": [
          "Events"
        ],
        "operationId": "listEvents",
        "summary": "List events",
        "description": "Newest first by occurred_at. status=open returns events whose status is not closed, resolved, done or cancelled (case-insensitive).",
        "parameters": [
          {
            "name": "system_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only events for this system."
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "open, all, or an exact status (case-insensitive). Default all."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Events.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "events",
                    "count"
                  ],
                  "properties": {
                    "events": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Event"
                      }
                    },
                    "count": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Events"
        ],
        "operationId": "upsertEvents",
        "summary": "Upsert events",
        "description": "Requires a write token. Send one event object or {events:[...]} with up to 100. Each event is upserted on (source, external_id). An unknown system_id rejects that item. Responds 200 if any item was accepted, 422 if none. A workspace holds at most 5,000 open events.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/EventInput"
                  },
                  {
                    "$ref": "#/components/schemas/EventBatch"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or more than 100 events.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body over 1 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/frameworks": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "listFrameworks",
        "summary": "List frameworks",
        "description": "Sheet Frameworks. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "upsertFrameworks",
        "summary": "Create or update frameworks",
        "description": "Requires a write token. Upsert by id (or create without one). Send one object or {items:[...]} (up to 100). 200 if any item was accepted, 422 if none; per-item results say which.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/FrameworksInput"
                  },
                  {
                    "type": "object",
                    "required": [
                      "items"
                    ],
                    "properties": {
                      "items": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "$ref": "#/components/schemas/FrameworksInput"
                        }
                      },
                      "dry_run": {
                        "type": "boolean"
                      }
                    }
                  }
                ]
              },
              "example": {
                "framework_name": "Example framework name"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "FW-4F2A9C",
                      "external_id": null
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or over 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "The model changed while the request ran; re-send.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/frameworks/{id}": {
      "get": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "getFramework",
        "summary": "Get one framework",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "patchFramework",
        "summary": "Change fields of one framework",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FrameworksInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "putFramework",
        "summary": "Create or update one framework at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FrameworksInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "tags": [
          "Benefits and controls"
        ],
        "operationId": "deleteFramework",
        "summary": "Delete one framework",
        "description": "Requires a write token. Refused with 409 in_use while another row refers to it.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Still referenced.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/benefit-measures": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importBenefitMeasures",
        "summary": "Import benefit measurements from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/benefits": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importBenefits",
        "summary": "Import benefits from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/capabilities": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCapabilities",
        "summary": "Import capabilities from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write. Returns a per-row result (row = CSV line number). Rows are upserted by the mapped id or external_id; an empty cell leaves the field untouched. Same write path, limits and 409 behaviour as the upsert endpoints. Up to 5,000 rows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              },
              "example": {
                "csv": "Key,Name\nK1,Example\n",
                "mapping": {
                  "external_id": "Key",
                  "capability_name": "Name"
                },
                "dry_run": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result per row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": true,
                  "created": 2,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "row": 2,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-7B1E02",
                      "external_id": "CI-2001"
                    },
                    {
                      "row": 3,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-0C99AD",
                      "external_id": "CI-2002"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV, bad mapping or too many rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "413": {
            "description": "CSV too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Every row was rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/comments": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importComments",
        "summary": "Import comments from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/control-map": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importControlMap",
        "summary": "Import control mappings from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/controls": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importControls",
        "summary": "Import controls from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/custom-elements": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCustomElements",
        "summary": "Import custom elements from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/custom-fields": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCustomFields",
        "summary": "Import custom fields from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/custom-relation-types": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCustomRelationTypes",
        "summary": "Import custom relationship types from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/custom-relations": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCustomRelations",
        "summary": "Import custom relationships from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/custom-types": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importCustomTypes",
        "summary": "Import custom types from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/data-objects": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importDataObjects",
        "summary": "Import data-objects from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write. Returns a per-row result (row = CSV line number). Rows are upserted by the mapped id or external_id; an empty cell leaves the field untouched. Same write path, limits and 409 behaviour as the upsert endpoints. Up to 5,000 rows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              },
              "example": {
                "csv": "Key,Name\nK1,Example\n",
                "mapping": {
                  "external_id": "Key",
                  "object_name": "Name"
                },
                "dry_run": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result per row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": true,
                  "created": 2,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "row": 2,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-7B1E02",
                      "external_id": "CI-2001"
                    },
                    {
                      "row": 3,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-0C99AD",
                      "external_id": "CI-2002"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV, bad mapping or too many rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "413": {
            "description": "CSV too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Every row was rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/frameworks": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importFrameworks",
        "summary": "Import frameworks from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row results.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV or mapping.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "description": "No row accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/integrations": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importIntegrations",
        "summary": "Import integrations from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write. Returns a per-row result (row = CSV line number). Rows are upserted by the mapped id or external_id; an empty cell leaves the field untouched. Same write path, limits and 409 behaviour as the upsert endpoints. Up to 5,000 rows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              },
              "example": {
                "csv": "Key,Name\nK1,Example\n",
                "mapping": {
                  "external_id": "Key",
                  "integration_name": "Name"
                },
                "dry_run": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result per row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": true,
                  "created": 2,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "row": 2,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-7B1E02",
                      "external_id": "CI-2001"
                    },
                    {
                      "row": 3,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-0C99AD",
                      "external_id": "CI-2002"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV, bad mapping or too many rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "413": {
            "description": "CSV too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Every row was rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/import/systems": {
      "post": {
        "tags": [
          "Import"
        ],
        "operationId": "importSystems",
        "summary": "Import systems from a CSV",
        "description": "Requires a write token. Map CSV columns to fields, run with dry_run true first, then send again to write. Returns a per-row result (row = CSV line number). Rows are upserted by the mapped id or external_id; an empty cell leaves the field untouched. Same write path, limits and 409 behaviour as the upsert endpoints. Up to 5,000 rows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ImportRequest"
              },
              "example": {
                "csv": "CI ID,Name,Class\nCI-2001,Payroll Engine,Application\nCI-2002,Data Lake,Platform\n",
                "mapping": {
                  "external_id": "CI ID",
                  "system_name": "Name",
                  "system_category": "Class"
                },
                "dry_run": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Result per row.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": true,
                  "created": 2,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "row": 2,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-7B1E02",
                      "external_id": "CI-2001"
                    },
                    {
                      "row": 3,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-0C99AD",
                      "external_id": "CI-2002"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Bad CSV, bad mapping or too many rows.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "413": {
            "description": "CSV too large.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Every row was rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/integrations": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "listIntegrations",
        "summary": "List integrations",
        "description": "Sheet Integrations. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Write"
        ],
        "operationId": "upsertIntegrations",
        "summary": "Create or update integrations",
        "description": "Requires a write token. Upsert by id, or by external_id when id is absent. Send one object or {items:[...]} (up to 100). Unknown fields and unknown references are rejected per item. The write goes through the same snapshot, version history and audit trail as an app save, and answers 409 if the model changed meanwhile. 200 if any item was accepted, 422 if none.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ElementInput"
                  },
                  {
                    "$ref": "#/components/schemas/ElementBatch"
                  }
                ]
              },
              "example": {
                "id": "I2",
                "integration_name": "CRM to HR",
                "source_system_id": "S2",
                "target_system_id": "S10",
                "data_object_ids": "D1"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 0,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 1,
                  "results": [
                    {
                      "index": 0,
                      "ok": false,
                      "error": "target_system_id refers to unknown system 'S10'"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or more than 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/integrations/{id}": {
      "delete": {
        "tags": [
          "Write"
        ],
        "operationId": "deleteIntegration",
        "summary": "Delete a integration",
        "description": "Requires a write token. Refused with 409 in_use while any other row still references the item (maps, integrations, projects, roadmap, gaps, design references, events). Remove or re-point those in the app first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The row id."
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Delete by your external_id instead (the path id is then ignored)."
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": "S10",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "in_use (still referenced) or conflict (the model changed meanwhile; send it again).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "in_use",
                  "message": "System S1 is still referenced. Remove or re-point those rows in the app first.",
                  "referenced_by": {
                    "Integrations": 1,
                    "CapabilitySystemMap": 2
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getIntegration",
        "summary": "Get one integration",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Write"
        ],
        "operationId": "patchIntegration",
        "summary": "Change fields of one integration",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegrationsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Write"
        ],
        "operationId": "putIntegration",
        "summary": "Create or update one integration at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IntegrationsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/model": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getModel",
        "summary": "Whole model document",
        "description": "Requires a read or write token.",
        "responses": {
          "200": {
            "description": "The tenant model.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Model"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes": {
      "get": {
        "tags": [
          "Processes"
        ],
        "operationId": "listProcesses",
        "summary": "Process models with level, parent and step count",
        "parameters": [
          {
            "name": "level",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 5
            }
          },
          {
            "name": "parent",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "processes[] and the level names.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Processes"
        ],
        "operationId": "createProcess",
        "summary": "Create a process model (or update one: give process_id)",
        "description": "Needs a write token (write or write:model). Checked against the model: unknown links, levels that do not fit the parent and broken flow are refused. The diagram is laid out from the steps when it is next opened or exported.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "process_name": {
                    "type": "string"
                  },
                  "level": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5
                  },
                  "parent_process_id": {
                    "type": "string"
                  },
                  "process_group": {
                    "type": "string"
                  },
                  "owner_role": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "description": "A shape. ref is your own handle used by next[].to. elem_type: task, userTask, serviceTask, manualTask, businessRuleTask, sendTask, receiveTask, scriptTask, callActivity, exclusiveGateway, parallelGateway, inclusiveGateway, intermediateCatchEvent. Links: capability_id, system_id, object_id, risk_ids, control_ids, kpi_ids, child_process_id. next: [{to, label, prob}] (omit to flow to the next step).",
                      "properties": {
                        "ref": {
                          "type": "string"
                        },
                        "step_id": {
                          "type": "string"
                        },
                        "step_name": {
                          "type": "string"
                        },
                        "role": {
                          "type": "string"
                        },
                        "elem_type": {
                          "type": "string"
                        },
                        "capability_id": {
                          "type": "string"
                        },
                        "system_id": {
                          "type": "string"
                        },
                        "object_id": {
                          "type": "string"
                        },
                        "risk_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "control_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "kpi_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "child_process_id": {
                          "type": "string"
                        },
                        "cycle_time_days": {
                          "type": "number"
                        },
                        "cost": {
                          "type": "number"
                        },
                        "instruction": {
                          "type": "string"
                        },
                        "next": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "to": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "prob": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              }
                            }
                          }
                        }
                      },
                      "required": [
                        "step_name"
                      ]
                    }
                  }
                }
              },
              "example": {
                "process_name": "Handle a service request",
                "level": 2,
                "steps": [
                  {
                    "ref": "a",
                    "step_name": "Log the request",
                    "role": "Service desk",
                    "system_id": "S03"
                  },
                  {
                    "ref": "g",
                    "step_name": "Is it complete?",
                    "role": "Service desk",
                    "elem_type": "exclusiveGateway",
                    "next": [
                      {
                        "to": "b",
                        "label": "Yes",
                        "prob": 0.8
                      },
                      {
                        "to": "a",
                        "label": "No"
                      }
                    ]
                  },
                  {
                    "ref": "b",
                    "step_name": "Assess and decide",
                    "role": "Officer"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written (or unchanged). Returns the process as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "A new process was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Read-only or limited token."
          },
          "409": {
            "description": "The model changed meanwhile; nothing written. Re-send."
          },
          "422": {
            "description": "The change is not valid; nothing written. errors lists why."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes/{id}": {
      "get": {
        "tags": [
          "Processes"
        ],
        "operationId": "getProcess",
        "summary": "One process: path, child models, steps with flow and links",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "process_id"
          }
        ],
        "responses": {
          "200": {
            "description": "The process.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such process."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Processes"
        ],
        "operationId": "updateProcess",
        "summary": "Update a process model; steps, when sent, replace the step list",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "process_id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "process_name": {
                    "type": "string"
                  },
                  "level": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 5
                  },
                  "parent_process_id": {
                    "type": "string"
                  },
                  "process_group": {
                    "type": "string"
                  },
                  "owner_role": {
                    "type": "string"
                  },
                  "description": {
                    "type": "string"
                  },
                  "steps": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "description": "A shape. ref is your own handle used by next[].to. elem_type: task, userTask, serviceTask, manualTask, businessRuleTask, sendTask, receiveTask, scriptTask, callActivity, exclusiveGateway, parallelGateway, inclusiveGateway, intermediateCatchEvent. Links: capability_id, system_id, object_id, risk_ids, control_ids, kpi_ids, child_process_id. next: [{to, label, prob}] (omit to flow to the next step).",
                      "properties": {
                        "ref": {
                          "type": "string"
                        },
                        "step_id": {
                          "type": "string"
                        },
                        "step_name": {
                          "type": "string"
                        },
                        "role": {
                          "type": "string"
                        },
                        "elem_type": {
                          "type": "string"
                        },
                        "capability_id": {
                          "type": "string"
                        },
                        "system_id": {
                          "type": "string"
                        },
                        "object_id": {
                          "type": "string"
                        },
                        "risk_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "control_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "kpi_ids": {
                          "type": [
                            "string",
                            "array"
                          ]
                        },
                        "child_process_id": {
                          "type": "string"
                        },
                        "cycle_time_days": {
                          "type": "number"
                        },
                        "cost": {
                          "type": "number"
                        },
                        "instruction": {
                          "type": "string"
                        },
                        "next": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "to": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "prob": {
                                "type": "number",
                                "minimum": 0,
                                "maximum": 1
                              }
                            }
                          }
                        }
                      },
                      "required": [
                        "step_name"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written (or unchanged). Returns the process as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "A new process was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Read-only or limited token."
          },
          "409": {
            "description": "The model changed meanwhile; nothing written. Re-send."
          },
          "422": {
            "description": "The change is not valid; nothing written. errors lists why."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes/{id}/bpmn": {
      "get": {
        "tags": [
          "Processes"
        ],
        "operationId": "exportProcessBpmn",
        "summary": "BPMN 2.0 XML with diagram layout; links in struvera: extension elements",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "process_id"
          }
        ],
        "responses": {
          "200": {
            "description": "BPMN 2.0 XML.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "description": "No such process."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes/{id}/layout": {
      "post": {
        "tags": [
          "Processes"
        ],
        "operationId": "layoutProcess",
        "summary": "Lay the diagram out again from the steps (lanes by role)",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "process_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Written (or unchanged). Returns the process as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "A new process was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Read-only or limited token."
          },
          "409": {
            "description": "The model changed meanwhile; nothing written. Re-send."
          },
          "422": {
            "description": "The change is not valid; nothing written. errors lists why."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes/{id}/links": {
      "post": {
        "tags": [
          "Processes"
        ],
        "operationId": "linkProcessStep",
        "summary": "Link one shape to capabilities, systems, data objects, risks, controls, KPIs, a role or a child model",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "process_id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "step": {
                    "type": "string",
                    "description": "step_id, shape id or step name"
                  },
                  "links": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "step",
                  "links"
                ]
              },
              "example": {
                "step": "P01-S2",
                "links": {
                  "capability_id": "C01",
                  "risk_ids": [
                    "R-01"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written (or unchanged). Returns the process as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "A new process was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Read-only or limited token."
          },
          "409": {
            "description": "The model changed meanwhile; nothing written. Re-send."
          },
          "422": {
            "description": "The change is not valid; nothing written. errors lists why."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/processes/import": {
      "post": {
        "tags": [
          "Processes"
        ],
        "operationId": "importProcessBpmn",
        "summary": "Import BPMN 2.0 XML as a new process (or into process_id)",
        "description": "Send the XML with Content-Type application/xml (query: name, process_id, level, parent) or JSON {xml, process_name, process_id, level, parent_process_id}. Lanes become roles; tasks, gateways and intermediate events become steps; struvera:links come back as links; the file's own drawing is kept. DOCTYPE and entities are never expanded.",
        "requestBody": {
          "required": true,
          "content": {
            "application/xml": {
              "schema": {
                "type": "string"
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "xml": {
                    "type": "string"
                  },
                  "process_name": {
                    "type": "string"
                  },
                  "process_id": {
                    "type": "string"
                  },
                  "level": {
                    "type": "integer"
                  },
                  "parent_process_id": {
                    "type": "string"
                  }
                },
                "required": [
                  "xml"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written (or unchanged). Returns the process as stored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "201": {
            "description": "A new process was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "Read-only or limited token."
          },
          "409": {
            "description": "The model changed meanwhile; nothing written. Re-send."
          },
          "422": {
            "description": "The change is not valid; nothing written. errors lists why."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/projects": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "listProjects",
        "summary": "List projects",
        "description": "Sheet Projects. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/projects/{id}": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getProject",
        "summary": "Get one project",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/proposals": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "listProposals",
        "summary": "Proposals made with this token",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "enum": [
                "pending",
                "applied",
                "rejected",
                "failed"
              ]
            }
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Your proposals.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "proposals": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Proposal"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Governance"
        ],
        "operationId": "createProposal",
        "summary": "Propose a change; a person approves it",
        "description": "Requires a write token. The change is checked now against the live model (nothing is written) and then waits in the app's Review queue. Only an admin, or an editor named as an approver, can apply it. 422 lists the items that were not valid. At most 60 proposals an hour and 200 waiting per workspace.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProposalInput"
              },
              "example": {
                "type": "systems",
                "action": "upsert",
                "item": {
                  "id": "SYS-100",
                  "system_name": "Payroll Engine",
                  "lifecycle_status": "Retire"
                },
                "reason": "Found in the CMDB export"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The model already matches; nothing to propose.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "201": {
            "description": "Waiting for approval.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "proposal": {
                      "$ref": "#/components/schemas/Proposal"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unknown type or malformed body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Queue full.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Items not valid; nothing was proposed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/proposals/{id}": {
      "get": {
        "tags": [
          "Governance"
        ],
        "operationId": "getProposal",
        "summary": "One proposal and what happened to it",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          }
        ],
        "responses": {
          "200": {
            "description": "The proposal.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "proposal": {
                      "$ref": "#/components/schemas/Proposal"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/systems": {
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "listSystems",
        "summary": "List systems",
        "description": "Sheet Systems. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "tags": [
          "Write"
        ],
        "operationId": "upsertSystems",
        "summary": "Create or update systems",
        "description": "Requires a write token. Upsert by id, or by external_id when id is absent. Send one object or {items:[...]} (up to 100). Unknown fields and unknown references are rejected per item. The write goes through the same snapshot, version history and audit trail as an app save, and answers 409 if the model changed meanwhile. 200 if any item was accepted, 422 if none.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/ElementInput"
                  },
                  {
                    "$ref": "#/components/schemas/ElementBatch"
                  }
                ]
              },
              "example": {
                "external_id": "CI-1001",
                "system_name": "Payroll Engine",
                "system_category": "Application",
                "hosting": "SaaS",
                "run_cost_pa": 90000
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "At least one item accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                },
                "example": {
                  "dry_run": false,
                  "created": 1,
                  "updated": 0,
                  "unchanged": 0,
                  "rejected": 0,
                  "results": [
                    {
                      "index": 0,
                      "ok": true,
                      "action": "created",
                      "id": "SYS-4F2A9C",
                      "external_id": "CI-1001"
                    }
                  ],
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or more than 100 items.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "conflict: the model changed while the request ran. Nothing was written; send it again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "conflict",
                  "retry": true,
                  "message": "The workspace model changed while this request ran (someone saved in the app or another integration wrote). Nothing was written. Re-send the request.",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "422": {
            "description": "No item was accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/systems/{id}": {
      "delete": {
        "tags": [
          "Write"
        ],
        "operationId": "deleteSystem",
        "summary": "Delete a system",
        "description": "Requires a write token. Refused with 409 in_use while any other row still references the item (maps, integrations, projects, roadmap, gaps, design references, events). Remove or re-point those in the app first.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The row id."
          },
          {
            "name": "external_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Delete by your external_id instead (the path id is then ignored)."
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "deleted": {
                      "type": "string"
                    },
                    "updatedAt": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "ok": true,
                  "deleted": "S10",
                  "updatedAt": 1793955769344
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Trial ended; reactivate to write. Reads and exports stay free.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The token is read-only (insufficient_scope).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such item.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "in_use (still referenced) or conflict (the model changed meanwhile; send it again).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": "in_use",
                  "message": "System S1 is still referenced. Remove or re-point those rows in the app first.",
                  "referenced_by": {
                    "Integrations": 1,
                    "CapabilitySystemMap": 2
                  }
                }
              }
            }
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "get": {
        "tags": [
          "Model"
        ],
        "operationId": "getSystem",
        "summary": "Get one system",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "tags": [
          "Write"
        ],
        "operationId": "patchSystem",
        "summary": "Change fields of one system",
        "description": "Requires a write token. Merges the fields you send into the existing row (404 if there is none). Send If-Match with the ETag you read to refuse the write if the row changed meanwhile.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SystemsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "put": {
        "tags": [
          "Write"
        ],
        "operationId": "putSystem",
        "summary": "Create or update one system at this id",
        "description": "Requires a write token. Creates the row (201) or merges into it (200). If-None-Match: * means create only (412 if it exists); If-Match guards an update.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfMatch"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SystemsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved. The body has the row and its new ETag.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/X-RateLimit-Limit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/X-RateLimit-Remaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/X-RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "201": {
            "description": "Created.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "400": {
            "description": "Malformed body or id mismatch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "412": {
            "$ref": "#/components/responses/PreconditionFailed"
          },
          "422": {
            "description": "The item was not valid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ElementResults"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workflow-runs": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "operationId": "listWorkflowRuns",
        "summary": "List workflow runs",
        "description": "Sheet WorkflowRuns. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workflow-runs/{id}": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "operationId": "getWorkflowRun",
        "summary": "Get one workflow run",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workflows": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "operationId": "listWorkflows",
        "summary": "List workflows",
        "description": "Sheet Workflows. Supports paging (limit, cursor), filters, text search, sorting and field selection. Sends an ETag; send it back in If-None-Match to get 304 when nothing changed.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Q"
          },
          {
            "$ref": "#/components/parameters/Filter"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PagedRows"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "400": {
            "description": "Bad limit, cursor or sort.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/workflows/{id}": {
      "get": {
        "tags": [
          "Workflows"
        ],
        "operationId": "getWorkflow",
        "summary": "Get one workflow",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/ExternalId"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Item"
          },
          "304": {
            "$ref": "#/components/responses/NotModified"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API token (sv_...) created in the workspace page, or an OAuth access token (svo_...) from /oauth/token."
      },
      "oauth2": {
        "type": "oauth2",
        "description": "Client credentials. An admin creates a client in the workspace page; the secret is shown once.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/api/oauth/token",
            "scopes": {
              "read": "Read the model and events.",
              "write": "Also change the model and post events."
            }
          }
        }
      },
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "sv_session",
        "description": "The signed-in session of the Struvera app. Used by the Workspace endpoints only; /v1 does not accept it."
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, invalid or revoked token.",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "More than 600 requests a minute for this token.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "SheetRows": {
        "description": "Rows of one model sheet.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/SheetRows"
            }
          }
        }
      },
      "NotModified": {
        "description": "Unchanged since the ETag you sent.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          }
        }
      },
      "PreconditionFailed": {
        "description": "If-Match or If-None-Match did not hold: the item changed (or already exists). Read it again and re-apply your change.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "PagedRows": {
        "description": "A page of rows.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PagedRows"
            }
          }
        }
      },
      "Item": {
        "description": "One row.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/X-RateLimit-Limit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/X-RateLimit-Remaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/X-RateLimit-Reset"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ItemResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such item.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The token is read-only, or the signed-in role may not do this.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Baseline": {
        "type": "object",
        "properties": {
          "baseline_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "kind": {
            "enum": [
              "baseline",
              "scenario"
            ]
          },
          "created_on": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "note": {
            "type": "string"
          },
          "parts": {
            "type": "integer"
          },
          "complete": {
            "type": "boolean"
          }
        }
      },
      "BenefitMeasuresInput": {
        "type": "object",
        "description": "Benefit measurement fields. Send only what you own; omitted fields are kept. Required to create: benefit_id, period, actual.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (measure_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "benefit_id": {
            "type": "string",
            "description": "Must be the id of an existing BC_Benefits row."
          },
          "period": {
            "type": "string"
          },
          "actual": {
            "type": [
              "number",
              "string"
            ]
          },
          "note": {
            "type": "string"
          },
          "measured_by": {
            "type": "string"
          },
          "evidence_link": {
            "type": "string"
          },
          "approval_status": {
            "type": "string"
          },
          "approved_by": {
            "type": "string"
          },
          "approved_on": {
            "type": "string"
          },
          "variance_cause": {
            "type": "string"
          },
          "action": {
            "type": "string"
          },
          "expected_completion": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "BenefitsInput": {
        "type": "object",
        "description": "Benefit fields. Send only what you own; omitted fields are kept. Required to create: benefit_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (benefit_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "vertical_id": {
            "type": "string"
          },
          "benefit_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "value_pa": {
            "type": [
              "number",
              "string"
            ]
          },
          "start_year": {
            "type": [
              "number",
              "string"
            ]
          },
          "owner": {
            "type": "string"
          },
          "kpi": {
            "type": "string"
          },
          "baseline": {
            "type": "string"
          },
          "target": {
            "type": "string"
          },
          "linked_capability_ids": {
            "type": "string"
          },
          "fin_type": {
            "type": "string"
          },
          "cash_type": {
            "type": "string"
          },
          "unit": {
            "type": "string"
          },
          "baseline_num": {
            "type": [
              "number",
              "string"
            ]
          },
          "target_num": {
            "type": [
              "number",
              "string"
            ]
          },
          "ramp_years": {
            "type": [
              "number",
              "string"
            ]
          },
          "objective_ids": {
            "type": "string"
          },
          "project_ids": {
            "type": "string"
          },
          "benefit_type": {
            "type": "string"
          },
          "beneficiary": {
            "type": "string"
          },
          "outcome": {
            "type": "string"
          },
          "measure_owner": {
            "type": "string"
          },
          "data_source": {
            "type": "string"
          },
          "calc_method": {
            "type": "string"
          },
          "frequency": {
            "type": "string"
          },
          "interim_target_num": {
            "type": [
              "number",
              "string"
            ]
          },
          "interim_period": {
            "type": "string"
          },
          "confidence": {
            "type": "string"
          },
          "tolerance_pts": {
            "type": [
              "number",
              "string"
            ]
          },
          "assumptions": {
            "type": "string"
          },
          "lifecycle": {
            "type": "string"
          },
          "handover_to": {
            "type": "string"
          },
          "handover_on": {
            "type": "string"
          },
          "closure_note": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CapabilitiesInput": {
        "type": "object",
        "description": "Capability fields. Send only what you own; omitted fields are kept. Required to create: capability_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (capability_id). Optional when external_id is given."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "capability_name": {
            "type": "string"
          },
          "capability_group": {
            "type": "string"
          },
          "lifecycle_stage": {
            "type": "string"
          },
          "iso_reference": {
            "type": "string"
          },
          "criticality": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CommentsInput": {
        "type": "object",
        "description": "Comment fields. Send only what you own; omitted fields are kept. Required to create: element_type, element_id, text.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (comment_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "element_type": {
            "type": "string"
          },
          "element_id": {
            "type": "string"
          },
          "author": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "text": {
            "type": "string"
          },
          "resolved": {
            "type": "string"
          },
          "parent_id": {
            "type": "string",
            "description": "Must be the id of an existing Comments row."
          }
        },
        "additionalProperties": false
      },
      "ControlMapInput": {
        "type": "object",
        "description": "Control mapping fields. Send only what you own; omitted fields are kept. Required to create: control_id, element_type, element_id.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (map_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "control_id": {
            "type": "string",
            "description": "Must be the id of an existing Controls row."
          },
          "element_type": {
            "type": "string"
          },
          "element_id": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "maturity_level": {
            "type": [
              "number",
              "string"
            ]
          },
          "evidence": {
            "type": "string"
          },
          "evidence_link": {
            "type": "string"
          },
          "owner": {
            "type": "string"
          },
          "review_date": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ControlsInput": {
        "type": "object",
        "description": "Control fields. Send only what you own; omitted fields are kept. Required to create: framework_id, control_title.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (control_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "framework_id": {
            "type": "string",
            "description": "Must be the id of an existing Frameworks row."
          },
          "family": {
            "type": "string"
          },
          "control_title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "source_ref": {
            "type": "string"
          },
          "levels": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CustomElementsInput": {
        "type": "object",
        "description": "Custom element fields. Send only what you own; omitted fields are kept. Required to create: type_id, element_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (element_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "type_id": {
            "type": "string",
            "description": "Must be the id of an existing MetaTypes row."
          },
          "element_name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "owner_role": {
            "type": "string"
          },
          "cf_*": {
            "description": "Custom field values: any field named cf_<field_id> (text or number)."
          }
        },
        "additionalProperties": true
      },
      "CustomFieldsInput": {
        "type": "object",
        "description": "Custom field fields. Send only what you own; omitted fields are kept. Required to create: owner, field_name, field_type.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (field_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "owner": {
            "type": "string"
          },
          "field_name": {
            "type": "string"
          },
          "field_type": {
            "type": "string"
          },
          "required": {
            "type": "string"
          },
          "choices": {
            "type": "string"
          },
          "help": {
            "type": "string"
          },
          "formula": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CustomRelationsInput": {
        "type": "object",
        "description": "Custom relationship fields. Send only what you own; omitted fields are kept. Required to create: reltype_id, from_id, to_id.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (relation_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "reltype_id": {
            "type": "string",
            "description": "Must be the id of an existing MetaRelTypes row."
          },
          "from_id": {
            "type": "string"
          },
          "to_id": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CustomRelationTypesInput": {
        "type": "object",
        "description": "Custom relationship type fields. Send only what you own; omitted fields are kept. Required to create: reltype_name, from_type, to_type.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (reltype_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "reltype_name": {
            "type": "string"
          },
          "from_type": {
            "type": "string"
          },
          "to_type": {
            "type": "string"
          },
          "archimate_rel": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "pack": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "CustomTypesInput": {
        "type": "object",
        "description": "Custom type fields. Send only what you own; omitted fields are kept. Required to create: type_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (type_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "type_name": {
            "type": "string"
          },
          "plural": {
            "type": "string"
          },
          "icon": {
            "type": "string"
          },
          "colour": {
            "type": "string"
          },
          "archimate_type": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "pack": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "DataObjectsInput": {
        "type": "object",
        "description": "DataObject fields. Send only what you own; omitted fields are kept. Required to create: object_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (object_id). Optional when external_id is given."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "object_name": {
            "type": "string"
          },
          "data_steward_role": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "entity_id": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ElementBatch": {
        "type": "object",
        "required": [
          "items"
        ],
        "properties": {
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/ElementInput"
            }
          },
          "dry_run": {
            "type": "boolean",
            "description": "Validate and report, write nothing."
          }
        }
      },
      "ElementInput": {
        "type": "object",
        "description": "Fields of the target sheet. Send only the fields you own; omitted fields are kept. Systems: system_name, system_category, vendor_example, description, footprint, hosting, run_cost_pa (number), tech_debt (number), end_of_support, lifecycle_status. Capabilities: capability_name, capability_group, lifecycle_stage, iso_reference, criticality, description. Data objects: object_name, data_steward_role, description, entity_id. Integrations: integration_name, source_system_id and target_system_id (must exist), data_object_ids (comma list of existing ids), pattern, protocol, frequency, owner_role, status, design_ref_id, notes, vertical_id.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (system_id, capability_id, object_id or integration_id). Optional when external_id is given; a new id is generated on create."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120,
            "description": "Your key, for example the CMDB CI id. Rows are matched on it when id is absent."
          }
        },
        "additionalProperties": true
      },
      "ElementResults": {
        "type": "object",
        "required": [
          "created",
          "updated",
          "unchanged",
          "rejected",
          "results"
        ],
        "properties": {
          "dry_run": {
            "type": "boolean"
          },
          "created": {
            "type": "integer"
          },
          "updated": {
            "type": "integer"
          },
          "unchanged": {
            "type": "integer"
          },
          "rejected": {
            "type": "integer"
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Version stamp of the model after the write (also the value the app compares on save)."
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "row": {
                  "type": "integer",
                  "description": "CSV line number (imports only)."
                },
                "ok": {
                  "type": "boolean"
                },
                "action": {
                  "type": "string",
                  "enum": [
                    "created",
                    "updated",
                    "unchanged"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "external_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "error": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable code."
          },
          "message": {
            "type": "string"
          }
        }
      },
      "Event": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string"
          },
          "external_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "incident",
              "change",
              "work_item"
            ]
          },
          "system_id": {
            "type": "string"
          },
          "capability_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "priority": {
            "type": [
              "string",
              "null"
            ]
          },
          "occurred_at": {
            "type": "integer"
          },
          "updated_at": {
            "type": "integer"
          },
          "created_at": {
            "type": "integer"
          }
        }
      },
      "EventBatch": {
        "type": "object",
        "required": [
          "events"
        ],
        "properties": {
          "events": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/EventInput"
            }
          }
        }
      },
      "EventInput": {
        "type": "object",
        "required": [
          "source",
          "external_id",
          "type",
          "system_id"
        ],
        "properties": {
          "source": {
            "type": "string",
            "maxLength": 120,
            "description": "Originating tool, for example servicedesk-plus."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120,
            "description": "The record id in the source tool."
          },
          "type": {
            "type": "string",
            "enum": [
              "incident",
              "change",
              "work_item"
            ]
          },
          "system_id": {
            "type": "string",
            "description": "Must exist in the workspace model Systems sheet."
          },
          "capability_id": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 120
          },
          "title": {
            "type": "string",
            "maxLength": 300
          },
          "status": {
            "type": "string",
            "maxLength": 40,
            "default": "open"
          },
          "priority": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          },
          "occurred_at": {
            "description": "ISO 8601 string or epoch milliseconds. Defaults to now.",
            "oneOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "integer"
              }
            ]
          }
        }
      },
      "EventResults": {
        "type": "object",
        "required": [
          "results",
          "accepted",
          "rejected"
        ],
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "external_id",
                "ok"
              ],
              "properties": {
                "external_id": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "ok": {
                  "type": "boolean"
                },
                "error": {
                  "type": "string"
                }
              }
            }
          },
          "accepted": {
            "type": "integer"
          },
          "rejected": {
            "type": "integer"
          }
        }
      },
      "FrameworksInput": {
        "type": "object",
        "description": "Framework fields. Send only what you own; omitted fields are kept. Required to create: framework_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (framework_id). Optional on create: one is generated."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "framework_name": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "publisher": {
            "type": "string"
          },
          "source_ref": {
            "type": "string"
          },
          "licence_note": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "origin": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ImportRequest": {
        "type": "object",
        "required": [
          "csv",
          "mapping"
        ],
        "properties": {
          "csv": {
            "type": "string",
            "description": "CSV text with a header row (up to 8 MB, 5,000 rows)."
          },
          "mapping": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Struvera field to CSV column header. Map the id field or external_id so rows can be matched. Empty cells are skipped, never blanked."
          },
          "dry_run": {
            "type": "boolean"
          },
          "delimiter": {
            "type": "string",
            "enum": [
              ",",
              ";",
              "\t"
            ],
            "default": ","
          }
        }
      },
      "IntegrationsInput": {
        "type": "object",
        "description": "Integration fields. Send only what you own; omitted fields are kept. Required to create: integration_name, source_system_id, target_system_id.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (integration_id). Optional when external_id is given."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "vertical_id": {
            "type": "string"
          },
          "integration_name": {
            "type": "string"
          },
          "source_system_id": {
            "type": "string",
            "description": "Must be the id of an existing system."
          },
          "target_system_id": {
            "type": "string",
            "description": "Must be the id of an existing system."
          },
          "pattern": {
            "type": "string"
          },
          "protocol": {
            "type": "string"
          },
          "data_object_ids": {
            "type": "string",
            "description": "Comma list of existing data object ids."
          },
          "frequency": {
            "type": "string"
          },
          "owner_role": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "design_ref_id": {
            "type": "string"
          },
          "notes": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "ItemResponse": {
        "type": "object",
        "required": [
          "type",
          "item",
          "updatedAt"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "item": {
            "type": "object",
            "additionalProperties": true
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Model": {
        "type": "object",
        "required": [
          "data",
          "updatedAt"
        ],
        "properties": {
          "data": {
            "type": "object",
            "description": "Sheets keyed by name, each an array of row objects.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object",
                "additionalProperties": true
              }
            }
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Epoch milliseconds of the last save."
          }
        }
      },
      "PagedRows": {
        "type": "object",
        "required": [
          "sheet",
          "count",
          "total",
          "rows",
          "updatedAt"
        ],
        "properties": {
          "sheet": {
            "type": "string"
          },
          "count": {
            "type": "integer",
            "description": "Rows in this page."
          },
          "total": {
            "type": "integer",
            "description": "Rows matching the filters."
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Pass as cursor for the next page; null on the last page."
          },
          "model_changed_since_cursor": {
            "type": "boolean",
            "description": "Present when the model was saved after the cursor was made. Paging continues, but rows may have moved."
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "PartialSave": {
        "type": "object",
        "required": [
          "sheets"
        ],
        "properties": {
          "sheets": {
            "type": "object",
            "description": "Only the sheets you changed.",
            "additionalProperties": {
              "type": "object",
              "required": [
                "rows"
              ],
              "properties": {
                "rows": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "base": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "The sheet version you loaded (sheetHash of its rows); null when you are creating the sheet."
                }
              }
            }
          },
          "remove": {
            "type": "object",
            "description": "Sheets to delete, each with the version you loaded.",
            "additionalProperties": {
              "type": "string"
            }
          },
          "baseUpdatedAt": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Optional. Only used to tell you whether others saved other sheets meanwhile (others_changed)."
          }
        }
      },
      "Proposal": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "enum": [
              "pending",
              "applied",
              "rejected",
              "failed"
            ]
          },
          "type": {
            "type": "string"
          },
          "action": {
            "enum": [
              "upsert",
              "delete"
            ]
          },
          "summary": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          },
          "created_by": {
            "type": "string"
          },
          "created_at": {
            "type": "integer"
          },
          "decided_by": {
            "type": [
              "string",
              "null"
            ]
          },
          "decided_at": {
            "type": [
              "integer",
              "null"
            ]
          },
          "note": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "ProposalInput": {
        "type": "object",
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "enum": [
              "systems",
              "capabilities",
              "data-objects",
              "integrations",
              "comments",
              "benefits",
              "benefit-measures",
              "frameworks",
              "controls",
              "control-map",
              "custom-types",
              "custom-fields",
              "custom-relation-types",
              "custom-elements",
              "custom-relations"
            ]
          },
          "action": {
            "enum": [
              "upsert",
              "delete"
            ],
            "default": "upsert"
          },
          "item": {
            "type": "object",
            "additionalProperties": true
          },
          "items": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "id": {
            "type": "string",
            "description": "For action delete."
          },
          "reason": {
            "type": "string",
            "maxLength": 500
          }
        }
      },
      "SheetRows": {
        "type": "object",
        "required": [
          "sheet",
          "count",
          "rows",
          "updatedAt"
        ],
        "properties": {
          "sheet": {
            "type": "string"
          },
          "count": {
            "type": "integer"
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "updatedAt": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "SystemsInput": {
        "type": "object",
        "description": "System fields. Send only what you own; omitted fields are kept. Required to create: system_name.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The row id (system_id). Optional when external_id is given."
          },
          "external_id": {
            "type": "string",
            "maxLength": 120
          },
          "system_name": {
            "type": "string"
          },
          "system_category": {
            "type": "string"
          },
          "vendor_example": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "footprint": {
            "type": "string"
          },
          "hosting": {
            "type": "string"
          },
          "run_cost_pa": {
            "type": [
              "number",
              "string"
            ]
          },
          "tech_debt": {
            "type": [
              "number",
              "string"
            ]
          },
          "end_of_support": {
            "type": "string"
          },
          "lifecycle_status": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "TokenResponse": {
        "type": "object",
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "scope"
        ],
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "example": 3600
          },
          "scope": {
            "type": "string",
            "enum": [
              "read",
              "write"
            ]
          }
        }
      }
    },
    "parameters": {
      "Limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 1000
        },
        "description": "Page size (1 to 1000). Omit to get every row, as in version 1.1."
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "The next_cursor from the previous page."
      },
      "Sort": {
        "name": "sort",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "A field name; prefix with - for descending. Numbers sort as numbers."
      },
      "Fields": {
        "name": "fields",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Comma list of fields to return."
      },
      "Q": {
        "name": "q",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Case-insensitive text search over every field of each row."
      },
      "Filter": {
        "name": "filter[field]",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Exact match on one field, for example filter[lifecycle_status]=Retire. Comma-separate values for \"any of\". Repeat for more fields (all must match).",
        "style": "form",
        "explode": true
      },
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "schema": {
          "type": "string"
        },
        "description": "Send the ETag you hold; an unchanged result answers 304 with no body. On PUT, * means create only."
      },
      "IfMatch": {
        "name": "If-Match",
        "in": "header",
        "schema": {
          "type": "string"
        },
        "description": "Send the item ETag you read. If the item changed since, the write is refused with 412 and nothing changes."
      },
      "Id": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The row id."
      },
      "ExternalId": {
        "name": "external_id",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Match by your external_id instead of the id."
      }
    },
    "headers": {
      "ETag": {
        "description": "List: the model version. Item: a hash of the row (changes only when that row changes).",
        "schema": {
          "type": "string"
        }
      },
      "X-RateLimit-Limit": {
        "description": "Requests allowed per minute for this token.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests left in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix time (seconds) when the window resets.",
        "schema": {
          "type": "integer"
        }
      }
    }
  }
}
