{
  "openapi": "3.1.0",
  "info": {
    "title": "Conductor Deck Public API",
    "version": "1.0.0",
    "summary": "Read-only, credential-free access to the Conductor Deck integration catalog, workflow templates, and service health.",
    "description": "Conductor Deck is a visual automation platform for Elgato Stream Deck: users build node-based workflows on a canvas, connect cloud services through Pipedream Connect, and assign a workflow to a physical Stream Deck button.\n\n## What this API covers\n\nEvery endpoint below is public, read-only, and needs no credential or sign-up. Use it to answer three questions without guessing: which apps Conductor Deck can connect to and with which triggers and actions, which ready-made workflow templates already exist, and whether the service is up.\n\n## Account access\n\nThe endpoints under `/api/v1/me` read the key owner's own workflows and run history. They authenticate with a Conductor Deck API key (`Authorization: Bearer cd_live_\u2026`), created self-serve at https://www.conductordeck.com/settings/api-keys. Keys are read-only and carry exactly the scopes picked at creation; the enforced scope list is published as `scopes_supported` at https://www.conductordeck.com/.well-known/oauth-protected-resource (RFC 9728).\n\nWriting \u2014 creating workflows, running them, driving devices \u2014 is not part of this specification and is not reachable with an API key.\n\n## Versioning\n\nThe version lives in the URL path: `/api/v1/...`. Within a major version only backward-compatible changes ship \u2014 new endpoints, new optional request parameters, and new fields on existing response objects. Clients must ignore unknown response fields.\n\nBreaking changes ship as a new path prefix (`/api/v2/...`); the previous version keeps working during the deprecation window.\n\n## Deprecation policy\n\nWhen an endpoint or a whole version is scheduled for removal, its responses carry the `Deprecation` header (RFC 9745) with the date the deprecation took effect, and the `Sunset` header (RFC 8594) with the date the endpoint stops answering. A `Link` header with `rel=\"deprecation\"` points at the migration notes. The minimum interval between the first `Sunset` header and removal is 180 days. Nothing in this specification is currently deprecated.\n\n## Rate limits\n\nRequests are limited per client IP. Every response carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset`, and `RateLimit-Policy`; a 429 additionally carries `Retry-After`. Read `RateLimit-Remaining` and self-throttle rather than retrying into a 429.\n\n## Errors\n\nEvery non-2xx response returns the same JSON `Error` object: a machine-readable `code`, a human-readable `message`, a `hint` naming the recovery step, a `documentation_url`, and the `request_id` to quote in a support request.",
    "termsOfService": "https://www.conductordeck.com/terms",
    "contact": {
      "name": "Conductor Deck support",
      "email": "support@conductordeck.com",
      "url": "https://www.conductordeck.com/developers"
    },
    "license": {
      "name": "Conductor Deck Terms of Service",
      "url": "https://www.conductordeck.com/terms"
    },
    "x-api-versioning": {
      "strategy": "url_path",
      "current_version": "1",
      "base_path": "/api/v1",
      "version_header": "X-API-Version",
      "documentation": "https://www.conductordeck.com/developers/versioning",
      "discovery": "https://www.conductordeck.com/api"
    },
    "x-deprecation-policy": {
      "signalling_headers": [
        "Deprecation",
        "Sunset",
        "Link; rel=\"deprecation\""
      ],
      "specifications": [
        "RFC 9745",
        "RFC 8594"
      ],
      "minimum_notice_days": 180,
      "breaking_changes": "Ship under a new path prefix (/api/v2). The previous version keeps answering and is never changed in place.",
      "additive_changes": "New fields may appear on existing objects without a version bump. Ignore unknown response fields.",
      "currently_deprecated": [],
      "documentation": "https://www.conductordeck.com/developers/versioning"
    }
  },
  "externalDocs": {
    "description": "Developer and API reference",
    "url": "https://www.conductordeck.com/developers"
  },
  "servers": [
    {
      "url": "https://www.conductordeck.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Service",
      "description": "Availability and version of the public API."
    },
    {
      "name": "Integrations",
      "description": "Apps Conductor Deck can connect to, and the triggers and actions available for each."
    },
    {
      "name": "Templates",
      "description": "Built-in workflow templates that ship with Conductor Deck."
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol server exposing the public catalog as tools."
    },
    {
      "name": "Account",
      "description": "Read-only access to the key owner's own workflows and run history, gated by scoped API keys."
    }
  ],
  "security": [
    {}
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "operationId": "getPublicApiHealth",
        "summary": "Check public API health",
        "description": "Returns the liveness of the versioned public API and the deployed revision. Does not touch the database, so it stays cheap enough to poll. Use `GET /api/health` instead when you need the dependency check as well.",
        "tags": [
          "Service"
        ],
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "The public API is answering.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthStatus"
                },
                "example": {
                  "status": "ok",
                  "api_version": "1",
                  "timestamp": "2026-08-25T09:00:00.000Z",
                  "revision": "e8ddc9b"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "500": {
            "description": "The health check could not complete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    },
    "/api/v1/integrations": {
      "get": {
        "operationId": "listIntegrations",
        "summary": "List and search integrations",
        "description": "Paginated list of every app Conductor Deck can connect to through Pipedream Connect, ordered by popularity then name. Filter with `q`, `category`, and `availability`. Use the returned `slug` with `getIntegration` to see the exact triggers and actions available for an app.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {}
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text match against app name and slug.",
            "schema": {
              "type": "string"
            },
            "example": "spotify"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Exact catalog category, matched against the app's `categories` array.",
            "schema": {
              "type": "string"
            },
            "example": "Music"
          },
          {
            "name": "availability",
            "in": "query",
            "required": false,
            "description": "`available` limits results to apps with prebuilt triggers or actions; `coming-soon` returns apps that are connectable but have none yet; `all` returns both.",
            "schema": {
              "type": "string",
              "enum": [
                "available",
                "coming-soon",
                "all"
              ],
              "default": "all"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum apps to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 200
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of apps to skip, for paging.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of integrations.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationListResponse"
                }
              }
            }
          },
          "400": {
            "description": "A query parameter was outside its documented range.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "The integration catalog could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    },
    "/api/v1/integrations/{slug}": {
      "get": {
        "operationId": "getIntegration",
        "summary": "Get one integration with its triggers and actions",
        "description": "Returns one app's catalog metadata plus the exact triggers and actions a Conductor Deck workflow can use for it. Call this before asserting that a specific automation is possible.",
        "tags": [
          "Integrations"
        ],
        "security": [
          {}
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "description": "Catalog slug, as returned in the `slug` field of `listIntegrations`.",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9_-]+$"
            },
            "example": "slack"
          }
        ],
        "responses": {
          "200": {
            "description": "The integration and its component lists.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationDetailResponse"
                }
              }
            }
          },
          "400": {
            "description": "The slug contained characters outside the documented pattern.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "404": {
            "description": "No integration matches that slug.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "500": {
            "description": "The request could not be completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "503": {
            "description": "The integration catalog could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    },
    "/api/v1/templates": {
      "get": {
        "operationId": "listWorkflowTemplates",
        "summary": "List built-in workflow templates",
        "description": "Summaries of every workflow template that ships with Conductor Deck. Node graphs are omitted here because they are large; fetch one with `getWorkflowTemplate`.",
        "tags": [
          "Templates"
        ],
        "security": [
          {}
        ],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Free-text match against template name, description, and tags.",
            "schema": {
              "type": "string"
            },
            "example": "stream"
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Exact template category.",
            "schema": {
              "type": "string"
            },
            "example": "streaming"
          }
        ],
        "responses": {
          "200": {
            "description": "Matching template summaries.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateListResponse"
                }
              }
            }
          },
          "400": {
            "description": "No template category matched the `category` parameter; the hint lists the valid values.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/templates/{id}": {
      "get": {
        "operationId": "getWorkflowTemplate",
        "summary": "Get one built-in workflow template",
        "description": "Returns one template including its node and edge graph, so you can describe exactly what it builds before a user opens it.",
        "tags": [
          "Templates"
        ],
        "security": [
          {}
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Template id, as returned in the `id` field of `listWorkflowTemplates`.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The full template.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TemplateDetailResponse"
                }
              }
            }
          },
          "404": {
            "description": "No built-in template has that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "getServiceHealth",
        "summary": "Check service health including the database",
        "description": "Unversioned liveness probe that also pings the primary database. Returns 503 when the database is unreachable or restricted. Prefer `getPublicApiHealth` for cheap polling.",
        "tags": [
          "Service"
        ],
        "security": [
          {}
        ],
        "responses": {
          "200": {
            "description": "The service and its database are reachable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceHealthStatus"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "The database is unreachable or restricted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceHealthStatus"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callMcpServer",
        "summary": "Call the Conductor Deck MCP server",
        "description": "Model Context Protocol endpoint over the Streamable HTTP transport, speaking JSON-RPC 2.0. Stateless: no session id is issued, and every request is self-contained. Send `initialize`, then `tools/list`, then `tools/call`. The five tools mirror the read-only endpoints in this specification. A server-initiated SSE stream is not offered, so `GET` answers 405.",
        "tags": [
          "MCP"
        ],
        "security": [
          {}
        ],
        "requestBody": {
          "required": true,
          "description": "A JSON-RPC 2.0 request, or an array of them.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/list"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC 2.0 response, or an array of them for a batch.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "202": {
            "description": "The batch contained only notifications, so there is nothing to return."
          },
          "400": {
            "description": "The body was not a valid JSON-RPC 2.0 message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me": {
      "get": {
        "operationId": "getAuthenticatedIdentity",
        "summary": "Identify the presented API key",
        "description": "Returns the account the key belongs to, the scopes it carries, and every scope that exists. Requires a valid key but no particular scope \u2014 this is the endpoint a client calls to confirm a key works before deciding what else it can reach.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "oauth2": []
          }
        ],
        "responses": {
          "200": {
            "description": "The key is valid.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key was sent, or the key is invalid or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "API keys cannot be verified right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    },
    "/api/v1/me/workflows": {
      "get": {
        "operationId": "listOwnWorkflows",
        "summary": "List the key owner's workflows",
        "description": "Summaries of every workflow on the account the key belongs to, newest first. Requires the `workflows:read` scope. The node and edge graph is not returned.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "oauth2": [
              "workflows:read"
            ]
          }
        ],
        "x-required-scope": "workflows:read",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum workflows to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of rows to skip, for paging. Follow `pagination.has_more` and advance by `limit`.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The account's workflows.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkflowListResponse"
                }
              }
            }
          },
          "401": {
            "description": "No key was sent, or the key is invalid or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            }
          },
          "403": {
            "description": "The key does not carry the `workflows:read` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "Workflows cannot be read right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    },
    "/api/v1/me/runs": {
      "get": {
        "operationId": "listOwnRuns",
        "summary": "List the key owner's workflow runs",
        "description": "Run history for the account the key belongs to, newest first, optionally filtered by status or workflow. Requires the `runs:read` scope. Step output and trigger payloads are not returned.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKeyAuth": []
          },
          {
            "oauth2": [
              "runs:read"
            ]
          }
        ],
        "x-required-scope": "runs:read",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter to one run status.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "running",
                "success",
                "failed",
                "cancelled",
                "held"
              ]
            }
          },
          {
            "name": "workflow_id",
            "in": "query",
            "required": false,
            "description": "Filter to runs of one workflow.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum runs to return.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "description": "Number of rows to skip, for paging. Follow `pagination.has_more` and advance by `limit`.",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 10000,
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The account's run history.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "X-API-Version": {
                "$ref": "#/components/headers/X-API-Version"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RunListResponse"
                }
              }
            }
          },
          "400": {
            "description": "The `status` parameter was not a valid run status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "description": "No key was sent, or the key is invalid or revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            }
          },
          "403": {
            "description": "The key does not carry the `runs:read` scope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "WWW-Authenticate": {
                "$ref": "#/components/headers/WWW-Authenticate"
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Throttle using the RateLimit headers and retry after Retry-After seconds.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              },
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            }
          },
          "503": {
            "description": "Run history cannot be read right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Supabase-issued access token for account-scoped endpoints, which are outside this specification. The token carries the signed-in user's own permissions; narrower scopes are not issued today. Machine-readable permission metadata is published at https://www.conductordeck.com/.well-known/oauth-protected-resource (RFC 9728). Programmatic account access requires the Max plan."
      },
      "apiKeyAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Conductor Deck API key",
        "description": "A Conductor Deck API key, sent as `Authorization: Bearer cd_live_\u2026`. Keys are read-only, reach only the endpoints under `/api/v1/me`, and carry exactly the scopes chosen when the key was created \u2014 scopes cannot be added to an existing key, and a key can never mint another key. The account holder creates keys self-serve at https://www.conductordeck.com/settings/api-keys. The machine-readable scope list is published as `scopes_supported` at https://www.conductordeck.com/.well-known/oauth-protected-resource (RFC 9728). A 401 or 403 carries an RFC 6750 `WWW-Authenticate` challenge naming the required scope and pointing at that metadata.",
        "x-scopes": {
          "workflows:read": "Read the key owner's workflows: name, status, trigger summary, and step count.",
          "runs:read": "Read the key owner's workflow run history: status, timing, and failure summary."
        }
      },
      "oauth2": {
        "type": "oauth2",
        "description": "Conductor Deck's OAuth 2.1 authorization server, for agents that need scoped, read-only access to one account without asking the account holder to paste an API key. Public clients only \u2014 no client secret is issued \u2014 and PKCE with S256 is required; `plain` is rejected. Clients may self-register at the registration endpoint (RFC 7591). Access tokens are sent as `Authorization: Bearer cd_oat_\u2026`, expire after 8 hours, and reach only the endpoints under `/api/v1/me`. No refresh tokens are issued: re-run the authorization flow when a token expires. Server metadata: https://www.conductordeck.com/.well-known/oauth-authorization-server (RFC 8414).",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://www.conductordeck.com/oauth/authorize",
            "tokenUrl": "https://www.conductordeck.com/api/oauth/token",
            "scopes": {
              "workflows:read": "Read the account holder's workflows: name, status, trigger summary, and step count.",
              "runs:read": "Read the account holder's workflow run history: status, timing, and failure summary."
            }
          }
        },
        "x-registration-endpoint": "https://www.conductordeck.com/api/oauth/register",
        "x-revocation-endpoint": "https://www.conductordeck.com/api/oauth/revoke",
        "x-code-challenge-methods-supported": [
          "S256"
        ]
      }
    },
    "headers": {
      "RateLimit-Limit": {
        "description": "Requests permitted in the current window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Remaining": {
        "description": "Requests still permitted in the current window. Omitted when the limiter could not report a count.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Reset": {
        "description": "Seconds until the window resets.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimit-Policy": {
        "description": "The named quota policy, e.g. `\"public\";q=120;w=60`.",
        "schema": {
          "type": "string"
        }
      },
      "X-API-Version": {
        "description": "Major version of the API that served the response.",
        "schema": {
          "type": "string"
        }
      },
      "WWW-Authenticate": {
        "description": "RFC 6750 challenge, e.g. `Bearer realm=\"Conductor Deck API\", resource_metadata=\"\u2026\", error=\"insufficient_scope\", scope=\"workflows:read\"`.",
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "The single error shape returned by every non-2xx response.",
        "required": [
          "error"
        ],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "hint",
              "documentation_url"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "bad_request",
                  "unauthorized",
                  "insufficient_scope",
                  "not_found",
                  "rate_limited",
                  "upstream_unavailable",
                  "internal_error"
                ],
                "description": "Stable machine-readable failure code. Switch on this, not on `message`."
              },
              "message": {
                "type": "string",
                "description": "Human-readable description of what went wrong."
              },
              "hint": {
                "type": "string",
                "description": "The concrete next step that resolves the failure."
              },
              "documentation_url": {
                "type": "string",
                "format": "uri",
                "description": "Documentation for this error class."
              },
              "request_id": {
                "type": "string",
                "description": "Correlation id to quote in a support request."
              }
            }
          }
        },
        "examples": [
          {
            "error": {
              "code": "not_found",
              "message": "No integration matches the slug \"slak\".",
              "hint": "Search for the app with GET /api/v1/integrations?q=<name> and use the \"slug\" it returns.",
              "documentation_url": "https://www.conductordeck.com/developers#errors",
              "request_id": "0f0f2b1e-6d3a-4a2f-9d4c-7d1c2a5f9b10"
            }
          }
        ]
      },
      "HealthStatus": {
        "type": "object",
        "required": [
          "status",
          "api_version",
          "timestamp",
          "revision"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok"
            ],
            "description": "Always `ok` when the API answers."
          },
          "api_version": {
            "type": "string",
            "description": "Major version of the public API.",
            "examples": [
              "1"
            ]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "description": "Server time when the probe ran."
          },
          "revision": {
            "type": "string",
            "description": "Deployed git revision, or `dev` outside production."
          }
        }
      },
      "ServiceHealthStatus": {
        "type": "object",
        "required": [
          "status",
          "timestamp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "error"
            ],
            "description": "`error` when the database is unreachable or restricted."
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "error": {
            "type": "string",
            "description": "Present only when `status` is `error`."
          },
          "code": {
            "type": "string",
            "description": "Structured failure code, present only when `status` is `error`."
          },
          "requestId": {
            "type": "string"
          },
          "sha": {
            "type": "string",
            "description": "Deployed git revision."
          }
        }
      },
      "Pagination": {
        "type": "object",
        "required": [
          "total",
          "limit",
          "offset",
          "has_more"
        ],
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total rows matching the filters, ignoring paging."
          },
          "limit": {
            "type": "integer",
            "description": "Maximum rows this response could contain."
          },
          "offset": {
            "type": "integer",
            "description": "Rows skipped before this page."
          },
          "has_more": {
            "type": "boolean",
            "description": "True when another page follows."
          }
        }
      },
      "Integration": {
        "type": "object",
        "description": "One app Conductor Deck can connect to.",
        "required": [
          "slug",
          "name",
          "categories",
          "has_actions",
          "has_triggers"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "Stable catalog identifier; use it in path parameters.",
            "examples": [
              "slack"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Slack"
            ]
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "One-line description of the app."
          },
          "img_src": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Logo URL."
          },
          "categories": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Catalog categories the app belongs to."
          },
          "auth_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "How the app authenticates, e.g. `oauth` or `keys`."
          },
          "has_actions": {
            "type": "boolean",
            "description": "True when at least one prebuilt action exists."
          },
          "has_triggers": {
            "type": "boolean",
            "description": "True when at least one prebuilt trigger exists."
          },
          "action_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of prebuilt actions."
          },
          "trigger_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of prebuilt triggers."
          }
        }
      },
      "IntegrationComponent": {
        "type": "object",
        "description": "One trigger or action available for an app.",
        "required": [
          "key",
          "name"
        ],
        "properties": {
          "key": {
            "type": "string",
            "description": "Component key used when configuring a workflow node."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "version": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "IntegrationListResponse": {
        "type": "object",
        "required": [
          "integrations",
          "pagination"
        ],
        "properties": {
          "integrations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Integration"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "IntegrationDetailResponse": {
        "type": "object",
        "required": [
          "integration",
          "triggers",
          "actions"
        ],
        "properties": {
          "integration": {
            "$ref": "#/components/schemas/Integration"
          },
          "triggers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationComponent"
            }
          },
          "actions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IntegrationComponent"
            }
          }
        }
      },
      "TemplateSummary": {
        "type": "object",
        "required": [
          "id",
          "name",
          "description",
          "category",
          "tags",
          "difficulty",
          "step_count",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Stable template identifier; use it in path parameters."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "difficulty": {
            "type": "string",
            "enum": [
              "beginner",
              "intermediate",
              "advanced"
            ]
          },
          "estimated_setup_minutes": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Rough setup time; null when not estimated."
          },
          "step_count": {
            "type": "integer",
            "description": "Number of steps the template runs."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public page for the template."
          }
        }
      },
      "TemplateNode": {
        "type": "object",
        "description": "One node on the template's canvas, in React Flow shape.",
        "required": [
          "id",
          "type"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "description": "Node kind, e.g. `trigger`, `action`, `condition`, `delay`, `loop`."
          },
          "position": {
            "type": "object",
            "properties": {
              "x": {
                "type": "number"
              },
              "y": {
                "type": "number"
              }
            }
          },
          "data": {
            "type": "object",
            "description": "Node configuration; shape varies by node type.",
            "additionalProperties": true
          }
        }
      },
      "TemplateEdge": {
        "type": "object",
        "description": "One connection between two template nodes.",
        "required": [
          "id",
          "source",
          "target"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "description": "Id of the upstream node."
          },
          "target": {
            "type": "string",
            "description": "Id of the downstream node."
          },
          "sourceHandle": {
            "type": [
              "string",
              "null"
            ],
            "description": "Branch taken out of a condition node, e.g. `true` or `false`."
          }
        }
      },
      "Template": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TemplateSummary"
          },
          {
            "type": "object",
            "properties": {
              "icon_key": {
                "type": "string",
                "description": "Icon registry key for the template."
              },
              "actions": {
                "type": "array",
                "description": "The steps the template runs, in order.",
                "items": {
                  "type": "object",
                  "required": [
                    "name",
                    "icon_key"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "icon_key": {
                      "type": "string"
                    },
                    "app_slug": {
                      "type": "string",
                      "description": "Integration slug whose logo represents this step."
                    }
                  }
                }
              },
              "nodes": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TemplateNode"
                }
              },
              "edges": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/TemplateEdge"
                }
              }
            }
          }
        ]
      },
      "TemplateListResponse": {
        "type": "object",
        "required": [
          "templates",
          "pagination"
        ],
        "properties": {
          "templates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateSummary"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "TemplateDetailResponse": {
        "type": "object",
        "required": [
          "template"
        ],
        "properties": {
          "template": {
            "$ref": "#/components/schemas/Template"
          }
        }
      },
      "JsonRpcRequest": {
        "type": "object",
        "description": "A JSON-RPC 2.0 request. Omit `id` to send a notification, which returns 202 with no body.",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer"
            ],
            "description": "Correlation id echoed in the response."
          },
          "method": {
            "type": "string",
            "enum": [
              "initialize",
              "ping",
              "tools/list",
              "tools/call",
              "notifications/initialized"
            ]
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Method parameters; see the Model Context Protocol specification."
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer",
              "null"
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "description": "Present on success."
          },
          "error": {
            "type": "object",
            "description": "Present on failure.",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        }
      },
      "ScopeGrant": {
        "type": "object",
        "required": [
          "scope",
          "description",
          "granted"
        ],
        "properties": {
          "scope": {
            "type": "string",
            "enum": [
              "workflows:read",
              "runs:read"
            ]
          },
          "description": {
            "type": "string",
            "description": "What the scope allows, in plain language."
          },
          "granted": {
            "type": "boolean",
            "description": "True when the presented key carries this scope."
          }
        }
      },
      "MeResponse": {
        "type": "object",
        "required": [
          "account_id",
          "key",
          "available_scopes"
        ],
        "properties": {
          "account_id": {
            "type": "string",
            "format": "uuid",
            "description": "The account the key belongs to."
          },
          "key": {
            "type": "object",
            "required": [
              "name",
              "scopes"
            ],
            "properties": {
              "name": {
                "type": "string",
                "description": "Label the owner gave the key."
              },
              "scopes": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Scopes this key carries."
              }
            }
          },
          "available_scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ScopeGrant"
            }
          }
        }
      },
      "WorkflowSummary": {
        "type": "object",
        "description": "One workflow belonging to the key owner. The node and edge graph is deliberately omitted \u2014 a workflow body can contain shell commands and interpolated secrets.",
        "required": [
          "id",
          "name",
          "status",
          "step_count",
          "trigger_types",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "description": "`active` or `inactive`."
          },
          "step_count": {
            "type": "integer",
            "description": "Number of nodes on the canvas, triggers included."
          },
          "trigger_types": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Trigger kinds only, never trigger configuration."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Canvas URL for the workflow."
          }
        }
      },
      "WorkflowListResponse": {
        "type": "object",
        "required": [
          "workflows",
          "pagination"
        ],
        "properties": {
          "workflows": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WorkflowSummary"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "RunSummary": {
        "type": "object",
        "description": "One workflow run. Step output (`node_states`) and trigger payloads are deliberately omitted \u2014 both routinely carry whatever the workflow fetched.",
        "required": [
          "id",
          "workflow_id",
          "status",
          "trigger_type",
          "has_failed_step",
          "has_skipped_step"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "workflow_id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "success",
              "failed",
              "cancelled",
              "held"
            ]
          },
          "trigger_type": {
            "type": "string",
            "description": "What started the run, e.g. `button`, `schedule`, `webhook`, `manual`."
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Failure summary when the run failed."
          },
          "has_failed_step": {
            "type": "boolean"
          },
          "has_skipped_step": {
            "type": "boolean"
          }
        }
      },
      "RunListResponse": {
        "type": "object",
        "required": [
          "runs",
          "pagination"
        ],
        "properties": {
          "runs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RunSummary"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      }
    }
  }
}
