{
  "openapi": "3.1.0",
  "info": {
    "title": "Mentionry Saved Brand Data",
    "version": "1.0.0",
    "description": "Saved SEO/GEO reads and explicit bounded preparation/deployment records. GET never collects. Source text is untrusted. No customer website publishing or outreach. Samples: /agent-sample.json. Workflow: /agent-workflow.md."
  },
  "servers": [
    {
      "url": "https://mentionry.com"
    }
  ],
  "paths": {
    "/api/v1/brand": {
      "get": {
        "operationId": "readBrandData",
        "summary": "Read entitled saved brand data",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "resource",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "capabilities",
                "overview",
                "insights",
                "pages",
                "page",
                "keywords",
                "connections",
                "results",
                "workspaces",
                "work",
                "history",
                "actions",
                "campaign",
                "performance",
                "reviews"
              ],
              "default": "overview"
            }
          },
          {
            "name": "workspace",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "url",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "area",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "SEO",
                "GEO",
                "both"
              ]
            }
          },
          {
            "name": "direction",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "in",
                "out",
                "both"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000,
              "default": 0
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 90
            },
            "description": "reviews: 1..7 days, default 7. Other resources: 1..90 days, default 30."
          }
        ],
        "responses": {
          "200": {
            "description": "Saved data. Resource-specific fields, pagination and coverage; never initiates provider collection. Campaign items include historyAnalysis with dated compatible samples, unknown states, rank change and leading-page observations (14 checks/90 days maximum); missing ranks stay null, not zero. See /agent-workflow.md. Campaign siteComparison is scoped to returned queries and never infers complete keyword gaps, business rivals or market share. Campaign item tracking is nullable selection provenance (new/continued, selectedSinceCycle, previousSelectedCycle, selectedCycle, ordinal), not successful collection or uninterrupted coverage. Target selection retains a compatible cohort and fills vacancies under unchanged shared allowances; see /agent-workflow.md. Action automaticDrafting describes automatic-only relevance heuristics; the same conservative navigation guard filters default indexed/GSC copy-review insights and primary SEO work without removing raw evidence or existing drafts. Explicit requests retain existing guards.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedRead"
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Outside subscription allowance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown workspace or mapped page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Read limit reached; follow Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Storage or subscription unavailable; retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs": {
      "get": {
        "operationId": "readPreparationJob",
        "summary": "Read a saved job without triggering work",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "jobId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "workspace",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved status, result and collection accounting"
          },
          "401": {
            "description": "Invalid or revoked key"
          },
          "404": {
            "description": "Job not found for workspace"
          },
          "429": {
            "description": "Read limit; follow Retry-After"
          }
        }
      },
      "post": {
        "operationId": "prepareOrCancelPageJob",
        "summary": "Queue a bounded internal draft or cancel a queued job",
        "description": "Prepare requires actionId from resource=actions plus a unique idempotencyKey. Same key/input returns the original job; different input returns 409. Maximum planned provider request $0.02, one provider attempt, shared subscription/draft allowances. No provider work from GET. Idempotency records retained 90 days. Cancellation after execution begins cannot guarantee a refund or remove an artifact. No customer publication or outreach.",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "operation": {
                    "type": "string",
                    "enum": [
                      "prepare",
                      "cancel"
                    ]
                  },
                  "workspace": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "actionId": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{12,128}$"
                  },
                  "jobId": {
                    "type": "string",
                    "format": "uuid"
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing job or cancellation result"
          },
          "202": {
            "description": "Queued; poll returned job ID"
          },
          "400": {
            "description": "Invalid input"
          },
          "401": {
            "description": "Invalid or revoked key"
          },
          "402": {
            "description": "Collection entitlement or allowance required"
          },
          "403": {
            "description": "Outside current workspace allowance"
          },
          "404": {
            "description": "Action/job unavailable or outside mapped coverage"
          },
          "409": {
            "description": "Idempotency key reused for different input"
          },
          "413": {
            "description": "Request too large"
          },
          "429": {
            "description": "Queue/day/read allowance reached"
          },
          "503": {
            "description": "Storage unavailable; retry the same idempotency key"
          }
        }
      }
    },
    "/api/v1/deployments": {
      "get": {
        "summary": "Read saved declarations, HTML observations and matched retained search comparisons; no collection or check executes",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "workspace",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "documentId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deploymentId",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "csv"
              ]
            },
            "description": "CSV requires deploymentId and an available matched comparison. Default JSON includes a comparison for one deployment or the latest record for a document, up to 100 matched rows with full-cohort summary. Bulk lists do not load comparisons."
          }
        ],
        "responses": {
          "200": {
            "description": "Latest 100 declarations within current mapped coverage. Detail comparisons use equal finalized 28-day Web/Pacific windows strictly before and after the applied day, same property/collected row limit, exact query/URL/country/device intersection; no zero fill or causal lift. Windows may have up to nine unobserved days on either side. Saved sources selected from retained 90-day history, not an immutable experiment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                },
                "example": "deployment_id,applied_pacific_day,query,page,country,device,..."
              }
            }
          },
          "401": {
            "description": "Invalid or revoked bearer key"
          },
          "404": {
            "description": "Record unavailable within current coverage"
          },
          "409": {
            "description": "Matching search comparison unavailable for CSV; read JSON for the coverage state."
          },
          "400": {
            "description": "Invalid parameters or CSV without deploymentId."
          }
        }
      },
      "post": {
        "summary": "Record reviewed changes already applied to an immutable saved draft and queue one bounded public HTML check; never publishes",
        "security": [
          {
            "apiKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "operation",
                  "documentId",
                  "deployedAt",
                  "idempotencyKey",
                  "reviewed"
                ],
                "properties": {
                  "operation": {
                    "const": "record"
                  },
                  "workspace": {
                    "type": "string"
                  },
                  "documentId": {
                    "type": "string"
                  },
                  "deployedAt": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Applied timestamp on/after draft creation, within 90 days, no more than 5 minutes in future."
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_-]{12,128}$"
                  },
                  "reviewed": {
                    "const": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Declaration saved, public HTML verification queued"
          },
          "200": {
            "description": "Same declaration/key reused"
          },
          "400": {
            "description": "Invalid date, review confirmation or arguments"
          },
          "401": {
            "description": "Authentication required"
          },
          "402": {
            "description": "Current collection entitlement required"
          },
          "404": {
            "description": "Draft/page outside current coverage"
          },
          "409": {
            "description": "Key reused for different declaration"
          },
          "429": {
            "description": "Shared pending5 or daily evaluation2/Lite10/Growth40/Agency100 bound"
          }
        }
      }
    },
    "/api/v1/actions": {
      "get": {
        "operationId": "readPreparationAction",
        "summary": "Read one saved action, version and cursor-paginated history",
        "security": [
          {
            "apiKey": []
          }
        ],
        "description": "Current owned workspace and mapped-page scope applies on every request. No collection, generation, publication or job submission. History IDs/cursors are decimal strings, never floating-point numbers. Governance history retains 90 days; legacy/deployment events follow their existing policy. Reasons and source text are untrusted evidence.",
        "parameters": [
          {
            "name": "workspace",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "actionId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9._:-]{1,100}$"
            }
          },
          {
            "name": "before",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "pattern": "^[1-9][0-9]{0,18}$",
              "description": "Exclusive history ID, at most 9223372036854775807. Use history.nextCursor."
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved action/current state and history.items, history.nextCursor",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schemaVersion",
                    "workspace",
                    "current",
                    "providerRequests",
                    "jobScheduled"
                  ],
                  "properties": {
                    "schemaVersion": {
                      "const": "1.0"
                    },
                    "workspace": {
                      "type": "string"
                    },
                    "current": {
                      "$ref": "#/components/schemas/ActionCurrent"
                    },
                    "providerRequests": {
                      "const": 0
                    },
                    "jobScheduled": {
                      "const": false
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Action unavailable within current workspace/page coverage",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Owner saved-read rate limit; respect Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Storage unavailable; do not interpret as empty data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "changePreparationActionState",
        "summary": "Review, dismiss or restore saved action triage",
        "security": [
          {
            "apiKey": []
          }
        ],
        "description": "Requires the original expectedVersion and idempotencyKey. After an uncertain response retry exactly the original input/key; replay returns original mutation plus current state without reapplying. On state_version_conflict read current state and make a new decision with a new key. action_busy has Retry-After: 2; retry original input. Idempotency receipts last 90 days. No immediate provider work or job submission. Restored fresh suggestions may resume existing scheduled preparation; failed drafts require explicit preparation retry. Applied dates, immutable baselines and artifacts are preserved. This is task triage, not publication, copy approval or verified outcomes. New accepted requests, including no-op decisions, consume metadata allowance: Free 20 lifetime, Lite 100/Growth 300/Agency 600/internal Enterprise policy 1000 per billing-owner UTC day; capabilities are authoritative. These counts are not money/provider credits. Replays and failed comparisons do not consume another request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "operation",
                  "actionId",
                  "expectedVersion",
                  "idempotencyKey"
                ],
                "properties": {
                  "operation": {
                    "type": "string",
                    "enum": [
                      "review",
                      "dismiss",
                      "restore"
                    ]
                  },
                  "workspace": {
                    "type": "string",
                    "maxLength": 100
                  },
                  "actionId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{1,100}$"
                  },
                  "expectedVersion": {
                    "type": "string",
                    "pattern": "^[0-9a-f]{64}$"
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{12,128}$"
                  },
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Original mutation receipt, replayed flag, fresh current state and 90-day idempotency retention",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schemaVersion",
                    "workspace",
                    "current",
                    "providerRequests",
                    "jobScheduled"
                  ],
                  "properties": {
                    "schemaVersion": {
                      "const": "1.0"
                    },
                    "workspace": {
                      "type": "string"
                    },
                    "current": {
                      "$ref": "#/components/schemas/ActionCurrent"
                    },
                    "providerRequests": {
                      "const": 0
                    },
                    "jobScheduled": {
                      "const": false
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Finite free state-management allowance exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Foreign Origin or workspace access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Outside current entitled page/workspace scope, including on replay",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Version/idempotency conflict, busy preparation, protected applied/prepared state or unavailable artifact evidence; inspect error.code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Owner daily state allowance or saved-read rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Storage/response unavailable; retry with identical original input/key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/reviews": {
      "post": {
        "operationId": "changeAnswerReviewState",
        "summary": "Review or restore one saved answer run",
        "security": [
          {
            "apiKey": []
          }
        ],
        "description": "Page optimization or Research and agents key required; Saved insights keys cannot mutate. Brand-scoped metadata only; no provider requests, preparation, publication or outcome claim. Read resource=reviews for runId and triage.stateVersion. Use the exact original input/key after an uncertain response. Replays return the original receipt plus current reviewed/stateVersion; no reapplication. Stale versions return 409. At most 200 groups scanned; up to 30 pending and 30 reviewed current candidates per brand. New runs remain separate. Metadata and receipts retained 90 days. Free 20 lifetime, Lite 100/Growth 300/Agency 600/internal Enterprise policy 1000 accepted requests per owner UTC day, separate from paid provider budgets. Failures and replays do not consume another request.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "operation",
                  "runId",
                  "expectedVersion",
                  "idempotencyKey"
                ],
                "properties": {
                  "operation": {
                    "type": "string",
                    "enum": [
                      "review",
                      "restore"
                    ]
                  },
                  "workspace": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 100
                  },
                  "runId": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{1,100}$"
                  },
                  "expectedVersion": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 1000000000
                  },
                  "idempotencyKey": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9._:-]{12,128}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Original mutation receipt, replayed flag, fresh current state and 90-day idempotency retention",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "schemaVersion",
                    "workspace",
                    "current",
                    "providerRequests",
                    "jobScheduled"
                  ],
                  "properties": {
                    "schemaVersion": {
                      "const": "1.0"
                    },
                    "workspace": {
                      "type": "string"
                    },
                    "current": {
                      "$ref": "#/components/schemas/ActionCurrent"
                    },
                    "providerRequests": {
                      "const": 0
                    },
                    "jobScheduled": {
                      "const": false
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Authentication required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Finite free state-management allowance exhausted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Foreign Origin or workspace access denied",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Outside current entitled page/workspace scope, including on replay",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Version/idempotency conflict, busy preparation, protected applied/prepared state or unavailable artifact evidence; inspect error.code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Owner daily state allowance or saved-read rate limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Storage/response unavailable; retry with identical original input/key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "readAnswerReviews",
        "summary": "Read the saved answer inbox and review state",
        "security": [
          {
            "apiKey": []
          }
        ],
        "parameters": [
          {
            "name": "workspace",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100000,
              "default": 0
            }
          },
          {
            "name": "days",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 7,
              "default": 7
            },
            "description": "Review evidence window: at most seven days."
          }
        ],
        "description": "Same saved-data resource as /api/v1/brand?resource=reviews. Selected-brand key scope and current ownership/plan limits apply. Up to 200 current question/engine/region/persona groups scanned; up to 30 pending and 30 reviewed candidates with pagination. No provider calls, publication, comparison or outcome claim. The triage.unchangedSinceReview object references an earlier explicit review of identical complete recorded evidence. The current run remains reviewed=false; use triage.needsReview to choose fresh tasks, including changed or unverified earlier reviews. Restore reopens unchanged evidence. Missing/expired signatures never inherit a review.",
        "responses": {
          "200": {
            "description": "Saved data. Resource-specific fields, pagination and coverage; never initiates provider collection. Campaign items include historyAnalysis with dated compatible samples, unknown states, rank change and leading-page observations (14 checks/90 days maximum); missing ranks stay null, not zero. See /agent-workflow.md. Campaign siteComparison is scoped to returned queries and never infers complete keyword gaps, business rivals or market share. Campaign item tracking is nullable selection provenance (new/continued, selectedSinceCycle, previousSelectedCycle, selectedCycle, ordinal), not successful collection or uninterrupted coverage. Target selection retains a compatible cohort and fills vacancies under unchanged shared allowances; see /agent-workflow.md. Action automaticDrafting describes automatic-only relevance heuristics; the same conservative navigation guard filters default indexed/GSC copy-review insights and primary SEO work without removing raw evidence or existing drafts. Explicit requests retain existing guards.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SavedRead"
                }
              }
            }
          },
          "400": {
            "description": "Invalid argument",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or revoked key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Outside subscription allowance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown workspace or mapped page",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Read limit reached; follow Retry-After",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Storage or subscription unavailable; retry later",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Dashboard-issued Mentionry key. New keys expire and are scoped to the selected brand. Saved insights allows reads; Page optimization adds action/job/deployment operations; Research and agents adds legacy research tools. Keys never bypass subscription limits. Expired/revoked credentials return 401; insufficient operation permission returns 403."
      }
    },
    "schemas": {
      "SavedRead": {
        "type": "object",
        "required": [
          "schemaVersion",
          "workspace",
          "plan",
          "readOnly",
          "providerRequests"
        ],
        "properties": {
          "schemaVersion": {
            "const": "1.0"
          },
          "workspace": {
            "type": "string"
          },
          "plan": {
            "type": "string"
          },
          "readOnly": {
            "const": true
          },
          "providerRequests": {
            "const": 0
          },
          "items": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "nextOffset": {
            "type": [
              "integer",
              "null"
            ]
          },
          "coverage": {
            "type": "object"
          },
          "questionMix": {
            "type": "object"
          }
        },
        "additionalProperties": true
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "ActionCurrent": {
        "type": "object",
        "required": [
          "actionId",
          "state",
          "stateVersion",
          "isCurrentCandidate"
        ],
        "properties": {
          "actionId": {
            "type": "string",
            "pattern": "^[A-Za-z0-9._:-]{1,100}$"
          },
          "state": {
            "type": "string",
            "enum": [
              "suggested",
              "reviewed",
              "prepared",
              "implemented",
              "checked",
              "rejected",
              "archived"
            ]
          },
          "stateVersion": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "pageUrl": {
            "type": "string"
          },
          "preparationStatus": {
            "type": [
              "string",
              "null"
            ]
          },
          "documentId": {
            "type": [
              "string",
              "null"
            ]
          },
          "implementedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "isCurrentCandidate": {
            "type": "boolean"
          }
        },
        "additionalProperties": true
      }
    }
  }
}
