{
  "openapi": "3.1.0",
  "info": {
    "title": "Win & Scale API",
    "version": "6a38a9033440",
    "description": "Read one Meta ad account's warehouse and history, launch ads PAUSED, and — with the approval grant — put them live. Over HTTP.\n\nOne workspace is one Meta ad account, so there is no account id in any path: a key reaches the workspace it was minted in.\n\nEvery operation runs one MCP tool (named in `x-mcp-tool`) and returns that tool's own result, so the two surfaces never disagree. Request bodies and query parameters are snake_case; response bodies are the tool's payload as-is. Budgets are in the account currency's major units (50 = 50.00).\n\nKeys are server-side secrets. There are no CORS headers and browser use is not supported.\n\n**Every response** — success or error — carries `X-Request-Id`. It echoes your own `X-Request-Id` when you send a sane one (letters, digits, `.`, `_`, `-`, up to 128 chars) and is otherwise generated. Errors repeat it in the body as `request_id`, so pasting the JSON into a support request is enough to find the call.\n\n**Errors** are always `{ error: { code, message } }`. `code` is a stable identifier to branch on; `message` is human-readable and safe to log but not to branch on. The HTTP status is derived from `code`, never inferred from the message.\n\n**Rate limits.** Every response carries `RateLimit-Limit`, `RateLimit-Remaining`, `RateLimit-Reset` (seconds until the window refills) and `RateLimit-Policy`; a 429 adds `Retry-After` and `retry_after_ms`. Treat these as a best-effort backstop against runaway loops, not a quota: the limiter is per-instance, so the effective ceiling across a horizontally-scaled deployment is higher than the advertised number and is not currently enforced globally.",
    "x-generated-from": "lib/openapi/registry.ts"
  },
  "servers": [
    {
      "url": "https://winandscale.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "reports",
      "description": "The warehouse (daily, as of the last sync) and the history (lifetime totals per ad). Numbers, not verdicts."
    },
    {
      "name": "account",
      "description": "The connected ad account, its sync, its quota and the thresholds reports judge against."
    },
    {
      "name": "launches",
      "description": "Launch ads PAUSED, then activate, pause, retarget or rebuild them. Everything that changes spend needs the approval grant."
    },
    {
      "name": "creatives",
      "description": "The creative library and its Values on the house taxonomy."
    },
    {
      "name": "taxonomy",
      "description": "The Dimensions and this workspace's Values."
    },
    {
      "name": "briefs",
      "description": "Briefs and strategist notes shown to the operator on Insights."
    },
    {
      "name": "tests",
      "description": "Committed Tests: frozen intent, artifacts, append-only Observations, a final Conclusion."
    },
    {
      "name": "swipes",
      "description": "Other people's ads, saved for reference. Never launchable."
    },
    {
      "name": "research",
      "description": "Customer language in, personas and angles out, every line traceable to a quote."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from Settings → API keys, sent as `Authorization: Bearer rsk_…`.\n\nAuthorization has two independent axes.\n\nThe **scope** is ranked — a key satisfies any requirement at or below its own tier:\n\n- **`read`** — every GET.\n- **`write`** — launch ads PAUSED, sync, pull history, edit thresholds, Values, briefs, tests, swipes and research.\n- **`admin`** — everything `write` can. No operation requires more than `write` today.\n\nThere is no `approve` scope. It was a rung once; it is not one now, and a key requested with it is rejected.\n\nThe **approval grant** (`can_approve`) is a separate boolean, not a rung. Changing spend on Meta — activating a launch, pausing or resuming ads, retargeting an ad set, or rebuilding a launch's live creative — needs `write` **and** the grant. Keeping them on separate axes is what makes the review gate a control rather than a convention: a key that may propose is not automatically a key that may approve its own proposal.\n\nA key reaches the one workspace — one Meta ad account — it was minted in, and stops working when the operator who minted it leaves the workspace. The same key authenticates the MCP endpoint (`/api/mcp`) for a headless agent, with the same scope and grant."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "unauthorized",
                  "forbidden",
                  "invalid_request",
                  "not_found",
                  "conflict",
                  "proposal_rejected",
                  "rate_limited",
                  "upstream_error",
                  "internal"
                ]
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/v1/overview": {
      "get": {
        "operationId": "getOverview",
        "summary": "Account totals, the daily series, campaigns and top ads for a window.",
        "description": "From the warehouse, as of the last sync. `coverage` says from when the warehouse holds days: a window starting earlier carries a warning, and zero there means not held, not no spend. `funnel` is the operator's funnel over the totals.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_overview`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_overview",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.",
            "schema": {
              "default": "7d",
              "type": "string",
              "enum": [
                "7d",
                "14d",
                "30d",
                "this_week",
                "last_week"
              ]
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Custom window end, YYYY-MM-DD, inclusive. Default today.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ads": {
      "get": {
        "operationId": "listAdPerformance",
        "summary": "Per-ad metrics for a window, sorted.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_ad_performance`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_ad_performance",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.",
            "schema": {
              "default": "7d",
              "type": "string",
              "enum": [
                "7d",
                "14d",
                "30d",
                "this_week",
                "last_week"
              ]
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Custom window end, YYYY-MM-DD, inclusive. Default today.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "default": "spend",
              "type": "string",
              "enum": [
                "spend",
                "roas",
                "cpa",
                "purchases",
                "hook",
                "atc",
                "leads",
                "costPerLead",
                "conversations"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/performance-cube": {
      "get": {
        "operationId": "getPerformanceCube",
        "summary": "The window grouped and crossed on campaign, ad set, country, ad, upload or Values.",
        "description": "`rows` takes one axis or two, comma-separated (nested); `column` crosses them. An ad with two Values on an axis counts under each, so the total is never a sum of rows.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_performance_cube`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_performance_cube",
        "parameters": [
          {
            "name": "rows",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "Comma-separated, or the parameter repeated.",
              "x-items": {
                "type": "string",
                "enum": [
                  "campaign",
                  "adset",
                  "country",
                  "ad",
                  "creative",
                  "concept",
                  "angle",
                  "persona",
                  "awareness",
                  "offer",
                  "offer_type",
                  "pain",
                  "season",
                  "asset_type",
                  "format",
                  "hook",
                  "headline_tactic",
                  "talent",
                  "visual"
                ]
              }
            }
          },
          {
            "name": "column",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "campaign",
                "adset",
                "country",
                "ad",
                "creative",
                "concept",
                "angle",
                "persona",
                "awareness",
                "offer",
                "offer_type",
                "pain",
                "season",
                "asset_type",
                "format",
                "hook",
                "headline_tactic",
                "talent",
                "visual"
              ]
            }
          },
          {
            "name": "campaign_ids",
            "in": "query",
            "required": false,
            "description": "Only these campaigns.",
            "schema": {
              "type": "string",
              "description": "Comma-separated, or the parameter repeated.",
              "x-items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Top rows by spend.",
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          },
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.",
            "schema": {
              "default": "7d",
              "type": "string",
              "enum": [
                "7d",
                "14d",
                "30d",
                "this_week",
                "last_week"
              ]
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Custom window end, YYYY-MM-DD, inclusive. Default today.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/report-views": {
      "get": {
        "operationId": "listReportViews",
        "summary": "Saved report views (shared and your own) and the built-in templates.",
        "description": "Each view is a named URL state of the Ads report — `query` holds it as `?key=value` strings. Templates are resolved for this workspace's goal: a lead account ranks on cost per lead, never ROAS.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_report_views`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_list_report_views",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createReportView",
        "summary": "Save a report view.",
        "description": "`query` is the report URL state; defaults are dropped. Shared with the workspace unless `shared` is false. Stores no numbers — a view is re-asked live. Send an `Idempotency-Key`: a retry would otherwise save a second view.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_report_view`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_save_report_view",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "description": "Required to create.",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "path": {
                    "description": "The report page. Default: the Ads report.",
                    "type": "string",
                    "enum": [
                      "/app/creatives",
                      "/app/compare"
                    ]
                  },
                  "query": {
                    "description": "The report URL state. Omit on an update to keep it.",
                    "anyOf": [
                      {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "template": {
                    "description": "The template it starts from (its prompts follow it).",
                    "type": "string"
                  },
                  "shared": {
                    "type": "boolean"
                  },
                  "make_default": {
                    "type": "boolean"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/report-views/{view}": {
      "get": {
        "operationId": "getReportView",
        "summary": "Open a saved view or a template by slug: its rows, totals and notes.",
        "description": "The same rows, filters, grouping, sort and totals the page shows, from the warehouse. A week-over-week view (`vs=prev`) carries each row's previous-window numbers.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_report_view`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_report_view",
        "parameters": [
          {
            "name": "view",
            "in": "path",
            "required": true,
            "description": "The view.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateReportView",
        "summary": "Change a saved view: its name, state, sharing or whether it is the default.",
        "description": "Templates cannot be changed. Only the view's creator can make a shared view private.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_report_view`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_save_report_view",
        "parameters": [
          {
            "name": "view",
            "in": "path",
            "required": true,
            "description": "The view.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "description": "Required to create.",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "path": {
                    "description": "The report page. Default: the Ads report.",
                    "type": "string",
                    "enum": [
                      "/app/creatives",
                      "/app/compare"
                    ]
                  },
                  "query": {
                    "description": "The report URL state. Omit on an update to keep it.",
                    "anyOf": [
                      {
                        "type": "object",
                        "propertyNames": {
                          "type": "string"
                        },
                        "additionalProperties": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string"
                      }
                    ]
                  },
                  "template": {
                    "description": "The template it starts from (its prompts follow it).",
                    "type": "string"
                  },
                  "shared": {
                    "type": "boolean"
                  },
                  "make_default": {
                    "type": "boolean"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/strategy-rollup": {
      "get": {
        "operationId": "getStrategyRollup",
        "summary": "Spend and results per Value of every creative Dimension, for a window.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_strategy_rollup`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_strategy_rollup",
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "description": "Reporting window. 7d/14d/30d are the last N complete days, ending yesterday (as in Ads Manager); weeks are Monday-based, this_week runs to today. UTC.",
            "schema": {
              "default": "7d",
              "type": "string",
              "enum": [
                "7d",
                "14d",
                "30d",
                "this_week",
                "last_week"
              ]
            }
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "description": "Custom window start, YYYY-MM-DD, UTC. Overrides `period`. The result's `coverage` says what the warehouse holds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "description": "Custom window end, YYYY-MM-DD, inclusive. Default today.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/evidence-health": {
      "get": {
        "operationId": "getEvidenceHealth",
        "summary": "Whether the evidence is fit for comparison: freshness, coverage, unread spend.",
        "description": "Judges nothing. Each check names what it does to an analysis and what would close it — read it before trusting any comparison built on the other reports.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_evidence_health`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_evidence_health",
        "parameters": [
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "default": "90d",
              "type": "string",
              "enum": [
                "30d",
                "90d",
                "180d",
                "lifetime"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/history": {
      "get": {
        "operationId": "getAccountHistory",
        "summary": "Every ad that ever ran, with lifetime totals and the per-funnel baselines.",
        "description": "Lifetime totals per ad, not a time series — for a window use GET /api/v1/overview. Empty until POST /api/v1/history/pull has run once.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_account_history`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_get_account_history",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 40,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          },
          {
            "name": "funnel",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "instant_form",
                "website",
                "messaging",
                "profile",
                "traffic",
                "unknown"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/history/pull": {
      "post": {
        "operationId": "pullAccountHistory",
        "summary": "Replace the lifetime history snapshot from Meta.",
        "description": "On Meta's hourly quota the pull is scheduled instead (`status: queued`, `retryInMin`) and runs by itself; the stored history stays readable meanwhile.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_pull_account_history`.",
        "tags": [
          "reports"
        ],
        "x-mcp-tool": "meta_pull_account_history",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/campaigns": {
      "get": {
        "operationId": "listCampaigns",
        "summary": "Every campaign with its ad sets, statuses and the event each optimises for.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_campaigns`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_list_campaigns",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/identities": {
      "get": {
        "operationId": "listIdentities",
        "summary": "The ad account, and the Facebook Pages and Pixels it can launch under.",
        "description": "A live Meta read. Pass a chosen `page_id` / `pixel_id` to POST /api/v1/launches; omitted, the workspace defaults apply.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_pages_and_pixels`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_list_pages_and_pixels",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/workspace": {
      "get": {
        "operationId": "getWorkspace",
        "summary": "The workspace this key belongs to, and its connected ad account.",
        "description": "A key is pinned to the workspace it was minted in. `workspace.adAccountId` is the Meta ad account every call with this key reads and writes (null when the workspace is not connected).\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_workspace`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_get_workspace",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/api-usage": {
      "get": {
        "operationId": "getApiUsage",
        "summary": "Meta API quota for the current hour.",
        "description": "Check before a large launch: launches, syncs and pulls share one hourly quota.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_api_usage`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_get_api_usage",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sync": {
      "post": {
        "operationId": "syncNow",
        "summary": "Pull the last N days of ad-level insights and objects into the warehouse.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_sync_now`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_sync_now",
        "parameters": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "days": {
                    "default": 3,
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 90
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/backfill": {
      "post": {
        "operationId": "backfillInsights",
        "summary": "Fill the daily warehouse back in time, one month per step, in the background.",
        "description": "Asking again resumes; it never re-reads a finished month. Progress shows in GET /api/v1/overview's `coverage`.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_backfill_insights`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_backfill_insights",
        "parameters": [],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "since": {
                    "description": "How far back, YYYY-MM-DD. Optional.",
                    "type": "string"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. The work continues in the background; the body says how to follow it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/thresholds": {
      "patch": {
        "operationId": "setThresholds",
        "summary": "Change the goal, targets and funnel every report is judged against.",
        "description": "Only the fields sent change; `null` removes an override. Amounts are in the account currency. Returns the thresholds now in force. Moves no money.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_set_thresholds`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_set_thresholds",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "goal_event": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "add_to_cart",
                          "form_lead",
                          "website_lead",
                          "conversation",
                          "purchase",
                          "view_content",
                          "link_click"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "campaign_goals": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "minLength": 1
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {
                            "event": {
                              "type": "string",
                              "enum": [
                                "add_to_cart",
                                "form_lead",
                                "website_lead",
                                "conversation",
                                "purchase",
                                "view_content",
                                "link_click"
                              ]
                            },
                            "target": {
                              "type": "number",
                              "exclusiveMinimum": 0
                            }
                          },
                          "required": [
                            "event"
                          ]
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "cost_per_result": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "enum": [
                        "form_lead",
                        "conversation",
                        "add_to_cart",
                        "purchase",
                        "view_content",
                        "registration",
                        "website_lead",
                        "link_click",
                        "none"
                      ]
                    },
                    "additionalProperties": {
                      "anyOf": [
                        {
                          "type": "number",
                          "exclusiveMinimum": 0
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  },
                  "funnel_steps": {
                    "anyOf": [
                      {
                        "minItems": 2,
                        "maxItems": 6,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "enum": [
                            "impressions",
                            "video_3s",
                            "thruplays",
                            "clicks",
                            "link_clicks",
                            "landing_page_views",
                            "view_content",
                            "leads",
                            "form_leads",
                            "website_leads",
                            "registrations",
                            "add_to_cart",
                            "checkouts",
                            "purchases",
                            "conversations"
                          ]
                        }
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "min_spend_validate": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "min_spend_scale": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "cpa_cut": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "roas_break_even": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "roas_early_kill": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  },
                  "roas_scale": {
                    "type": "number",
                    "exclusiveMinimum": 0
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/strategy": {
      "get": {
        "operationId": "getStrategy",
        "summary": "The workspace's brand & strategy, with the account goal read-only.",
        "description": "Product, offer, ideal customer and pains, voice, do's and don'ts, proof points and production capacity. `goal` is read-only here: PATCH /api/v1/thresholds changes it.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_strategy`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_get_strategy",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateStrategy",
        "summary": "Change brand & strategy fields, or propose them for a human to accept.",
        "description": "`patch` holds only the fields to change; a list field replaces the list. Goal fields are refused (they are PATCH /api/v1/thresholds'). `mode: suggest` stores pending suggestions instead of writing. Attributed to the key. Moves no money.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_update_strategy`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_update_strategy",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "patch": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string"
                    },
                    "additionalProperties": {},
                    "description": "Only the fields to change."
                  },
                  "mode": {
                    "default": "write",
                    "type": "string",
                    "enum": [
                      "write",
                      "suggest"
                    ]
                  }
                },
                "required": [
                  "patch"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launch-defaults/pull": {
      "post": {
        "operationId": "pullLaunchDefaults",
        "summary": "Read audience, CTA, link and URL tags back from recent launches and save them as defaults.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_pull_account_defaults`.",
        "tags": [
          "account"
        ],
        "x-mcp-tool": "meta_pull_account_defaults",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lead-forms": {
      "get": {
        "operationId": "listLeadForms",
        "summary": "The instant (lead) forms on the Page, with every question's key, type and options.",
        "description": "A live Meta read with a Page access token. The question keys are the field names a lead arrives under. Pass a form's id as `copy.lead_form_id` to POST /api/v1/launches.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_lead_forms`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_list_lead_forms",
        "parameters": [
          {
            "name": "page_id",
            "in": "query",
            "required": false,
            "description": "Omit for the workspace's default Page.",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "default": "ACTIVE",
              "type": "string",
              "enum": [
                "ACTIVE",
                "ARCHIVED",
                "all"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createLeadForm",
        "summary": "Create an instant (lead) form on the Page.",
        "description": "Spends nothing until an ad opens it. A published form cannot be edited; a change is a new form. Send an `Idempotency-Key`: a retry would otherwise create a second form.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_create_lead_form`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_create_lead_form",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "locale": {
                    "description": "Meta's form locale, e.g. EN_US, PL_PL. Default: the Page's.",
                    "type": "string",
                    "pattern": "^[A-Za-z]{2}_[A-Za-z]{2}$"
                  },
                  "questions": {
                    "minItems": 1,
                    "maxItems": 15,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string",
                          "enum": [
                            "FULL_NAME",
                            "FIRST_NAME",
                            "LAST_NAME",
                            "EMAIL",
                            "WORK_EMAIL",
                            "PHONE",
                            "WHATSAPP_NUMBER",
                            "CITY",
                            "COUNTRY",
                            "COMPANY_NAME",
                            "JOB_TITLE",
                            "CUSTOM"
                          ]
                        },
                        "key": {
                          "description": "CUSTOM only, required: the field name the answer arrives under — what the CRM maps on. Prefilled types arrive as email, phone_number, full_name…",
                          "type": "string",
                          "pattern": "^[a-z][a-z0-9_]{0,63}$"
                        },
                        "label": {
                          "description": "CUSTOM only, required: the question.",
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "options": {
                          "description": "CUSTOM only: multiple choice. `value` is the text the lead carries.",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 64
                              },
                              "value": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 100
                              }
                            },
                            "required": [
                              "key",
                              "value"
                            ]
                          }
                        }
                      },
                      "required": [
                        "type"
                      ]
                    }
                  },
                  "privacy_policy": {
                    "type": "object",
                    "properties": {
                      "url": {
                        "type": "string",
                        "format": "uri"
                      },
                      "link_text": {
                        "type": "string",
                        "maxLength": 70
                      }
                    },
                    "required": [
                      "url"
                    ]
                  },
                  "intro": {
                    "description": "The intro screen.",
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "style": {
                        "default": "paragraph",
                        "type": "string",
                        "enum": [
                          "paragraph",
                          "list"
                        ]
                      },
                      "content": {
                        "minItems": 1,
                        "maxItems": 5,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      }
                    },
                    "required": [
                      "title",
                      "content"
                    ]
                  },
                  "thank_you": {
                    "description": "The screen after submit.",
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 60
                      },
                      "body": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 300
                      },
                      "button_type": {
                        "default": "NONE",
                        "type": "string",
                        "enum": [
                          "VIEW_WEBSITE",
                          "CALL_BUSINESS",
                          "WHATSAPP",
                          "NONE"
                        ]
                      },
                      "button_text": {
                        "type": "string",
                        "maxLength": 30
                      },
                      "website_url": {
                        "type": "string",
                        "format": "uri"
                      },
                      "phone": {
                        "description": "E.164, for CALL_BUSINESS and WHATSAPP.",
                        "type": "string"
                      }
                    },
                    "required": [
                      "title",
                      "body"
                    ]
                  },
                  "higher_intent": {
                    "default": true,
                    "type": "boolean"
                  },
                  "page_id": {
                    "description": "Omit for the workspace's default Page.",
                    "type": "string",
                    "pattern": "^\\d+$"
                  }
                },
                "required": [
                  "name",
                  "questions",
                  "privacy_policy"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/lead-forms/{formId}/test-leads": {
      "post": {
        "operationId": "sendTestLead",
        "summary": "Send a test lead through a form, end to end.",
        "description": "Meta delivers it to the lead webhook like a real lead, so it runs whatever the CRM does with one — use the operator's own phone and email. One test lead per form: pass `replace_lead_id` to delete the previous one first.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_send_test_lead`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_send_test_lead",
        "parameters": [
          {
            "name": "formId",
            "in": "path",
            "required": true,
            "description": "The formId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "answers": {
                    "type": "object",
                    "propertyNames": {
                      "type": "string",
                      "minLength": 1
                    },
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "replace_lead_id": {
                    "type": "string",
                    "pattern": "^\\d+$"
                  },
                  "page_id": {
                    "type": "string",
                    "pattern": "^\\d+$"
                  }
                },
                "required": [
                  "answers"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launch-presets": {
      "get": {
        "operationId": "listLaunchPresets",
        "summary": "The workspace's launch presets, the default first, each with what stops it launching.",
        "description": "A preset is everything a launch needs except the creatives: destination, audience, budget and split, fallback copy, the campaign. The default is the one last launched with; POST /api/v1/launches fills what it is not given from it.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_presets`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_list_presets",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createLaunchPreset",
        "summary": "Create a launch preset.",
        "description": "`config` is laid over the defaults, group by group. A workspace's first preset becomes its default. Spends nothing. Send an `Idempotency-Key`: a retry would otherwise create a second preset.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_preset`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_save_preset",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "description": "Required to create. Also a good campaign name.",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "config": {
                    "type": "object",
                    "properties": {
                      "target": {
                        "type": "object",
                        "properties": {
                          "mode": {
                            "type": "string",
                            "enum": [
                              "new",
                              "existing"
                            ],
                            "description": "new: each batch creates ad sets (and the campaign, by name) from this preset. existing: every ad goes into adSetId, which keeps its own audience, budget, placements and optimisation."
                          },
                          "campaign_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: the campaign that holds adSetId."
                          },
                          "ad_set_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: the ad set the ads go into."
                          },
                          "campaign_name": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 400
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: shown, never sent."
                          },
                          "ad_set_name": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 400
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: shown, never sent."
                          }
                        }
                      },
                      "destination": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "form",
                              "website",
                              "whatsapp"
                            ]
                          },
                          "form_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "form: the instant form the ads open."
                          },
                          "url": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uri"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "website: the landing page, without a query string."
                          },
                          "utm_template": {
                            "type": "string",
                            "maxLength": 500,
                            "description": "website: the URL tags every ad carries. Meta macros like {{ad.name}} resolve."
                          },
                          "conversion_event": {
                            "anyOf": [
                              {
                                "type": "string",
                                "enum": [
                                  "PURCHASE",
                                  "INITIATE_CHECKOUT",
                                  "ADD_TO_CART",
                                  "LEAD",
                                  "COMPLETE_REGISTRATION",
                                  "START_TRIAL",
                                  "SUBSCRIBE"
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "website: the pixel event the ad sets optimise for. Null = link clicks."
                          }
                        }
                      },
                      "audience": {
                        "type": "object",
                        "properties": {
                          "countries": {
                            "maxItems": 25,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "pattern": "^[A-Z]{2}$"
                            }
                          },
                          "age_min": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "age_max": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "languages": {
                            "maxItems": 10,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "pattern": "^[a-z]{2}$"
                            },
                            "description": "Saved with the preset. Not sent to Meta as targeting yet."
                          },
                          "advantage_audience": {
                            "type": "boolean",
                            "description": "Let Meta go beyond the audience. Launches keep it off; true is not launchable yet."
                          }
                        }
                      },
                      "budget": {
                        "type": "object",
                        "properties": {
                          "daily_per_adset": {
                            "anyOf": [
                              {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "maximum": 1000000
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Daily budget per ad set, account currency, major units (150 = 150.00)."
                          },
                          "control": {
                            "type": "string",
                            "enum": [
                              "ABO",
                              "CBO"
                            ],
                            "description": "CBO: one campaign budget, ad sets × the per-ad-set budget. ABO is stored but not launchable yet."
                          },
                          "split": {
                            "type": "string",
                            "enum": [
                              "batch",
                              "angle"
                            ],
                            "description": "angle: one ad set per angle in the batch. batch: one ad set for everything."
                          }
                        }
                      },
                      "copy": {
                        "type": "object",
                        "properties": {
                          "ai_from_recipe": {
                            "type": "boolean",
                            "description": "Write each ad's copy from its angle's approved messaging (Research). Falls back to the copy below."
                          },
                          "primary_text": {
                            "type": "string",
                            "maxLength": 5000
                          },
                          "headline": {
                            "type": "string",
                            "maxLength": 40
                          },
                          "cta": {
                            "type": "string",
                            "enum": [
                              "LEARN_MORE",
                              "SHOP_NOW",
                              "SIGN_UP",
                              "SUBSCRIBE",
                              "DOWNLOAD",
                              "GET_OFFER",
                              "GET_QUOTE",
                              "CONTACT_US",
                              "APPLY_NOW"
                            ]
                          },
                          "language": {
                            "type": "string",
                            "pattern": "^(auto|[a-z]{2})$",
                            "description": "auto = the creative's own locale; otherwise the locale for files with no name."
                          }
                        }
                      },
                      "naming": {
                        "type": "object",
                        "properties": {
                          "campaign": {
                            "type": "string",
                            "maxLength": 200,
                            "description": "The campaign the batches launch into, by name: reused when it exists, else created."
                          },
                          "pattern": {
                            "type": "string",
                            "maxLength": 40,
                            "description": "The ad-name id for files dropped without a canonical name: {MMDD}, {YYMMDD}."
                          }
                        }
                      }
                    }
                  },
                  "make_default": {
                    "type": "boolean"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launch-presets/{presetId}": {
      "patch": {
        "operationId": "updateLaunchPreset",
        "summary": "Change a launch preset: only the groups and fields sent change.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_save_preset`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_save_preset",
        "parameters": [
          {
            "name": "presetId",
            "in": "path",
            "required": true,
            "description": "The presetId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "description": "Required to create. Also a good campaign name.",
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 120
                  },
                  "config": {
                    "type": "object",
                    "properties": {
                      "target": {
                        "type": "object",
                        "properties": {
                          "mode": {
                            "type": "string",
                            "enum": [
                              "new",
                              "existing"
                            ],
                            "description": "new: each batch creates ad sets (and the campaign, by name) from this preset. existing: every ad goes into adSetId, which keeps its own audience, budget, placements and optimisation."
                          },
                          "campaign_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: the campaign that holds adSetId."
                          },
                          "ad_set_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: the ad set the ads go into."
                          },
                          "campaign_name": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 400
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: shown, never sent."
                          },
                          "ad_set_name": {
                            "anyOf": [
                              {
                                "type": "string",
                                "maxLength": 400
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "existing: shown, never sent."
                          }
                        }
                      },
                      "destination": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "form",
                              "website",
                              "whatsapp"
                            ]
                          },
                          "form_id": {
                            "anyOf": [
                              {
                                "type": "string",
                                "pattern": "^\\d+$"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "form: the instant form the ads open."
                          },
                          "url": {
                            "anyOf": [
                              {
                                "type": "string",
                                "format": "uri"
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "website: the landing page, without a query string."
                          },
                          "utm_template": {
                            "type": "string",
                            "maxLength": 500,
                            "description": "website: the URL tags every ad carries. Meta macros like {{ad.name}} resolve."
                          },
                          "conversion_event": {
                            "anyOf": [
                              {
                                "type": "string",
                                "enum": [
                                  "PURCHASE",
                                  "INITIATE_CHECKOUT",
                                  "ADD_TO_CART",
                                  "LEAD",
                                  "COMPLETE_REGISTRATION",
                                  "START_TRIAL",
                                  "SUBSCRIBE"
                                ]
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "website: the pixel event the ad sets optimise for. Null = link clicks."
                          }
                        }
                      },
                      "audience": {
                        "type": "object",
                        "properties": {
                          "countries": {
                            "maxItems": 25,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "pattern": "^[A-Z]{2}$"
                            }
                          },
                          "age_min": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "age_max": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "languages": {
                            "maxItems": 10,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "pattern": "^[a-z]{2}$"
                            },
                            "description": "Saved with the preset. Not sent to Meta as targeting yet."
                          },
                          "advantage_audience": {
                            "type": "boolean",
                            "description": "Let Meta go beyond the audience. Launches keep it off; true is not launchable yet."
                          }
                        }
                      },
                      "budget": {
                        "type": "object",
                        "properties": {
                          "daily_per_adset": {
                            "anyOf": [
                              {
                                "type": "number",
                                "exclusiveMinimum": 0,
                                "maximum": 1000000
                              },
                              {
                                "type": "null"
                              }
                            ],
                            "description": "Daily budget per ad set, account currency, major units (150 = 150.00)."
                          },
                          "control": {
                            "type": "string",
                            "enum": [
                              "ABO",
                              "CBO"
                            ],
                            "description": "CBO: one campaign budget, ad sets × the per-ad-set budget. ABO is stored but not launchable yet."
                          },
                          "split": {
                            "type": "string",
                            "enum": [
                              "batch",
                              "angle"
                            ],
                            "description": "angle: one ad set per angle in the batch. batch: one ad set for everything."
                          }
                        }
                      },
                      "copy": {
                        "type": "object",
                        "properties": {
                          "ai_from_recipe": {
                            "type": "boolean",
                            "description": "Write each ad's copy from its angle's approved messaging (Research). Falls back to the copy below."
                          },
                          "primary_text": {
                            "type": "string",
                            "maxLength": 5000
                          },
                          "headline": {
                            "type": "string",
                            "maxLength": 40
                          },
                          "cta": {
                            "type": "string",
                            "enum": [
                              "LEARN_MORE",
                              "SHOP_NOW",
                              "SIGN_UP",
                              "SUBSCRIBE",
                              "DOWNLOAD",
                              "GET_OFFER",
                              "GET_QUOTE",
                              "CONTACT_US",
                              "APPLY_NOW"
                            ]
                          },
                          "language": {
                            "type": "string",
                            "pattern": "^(auto|[a-z]{2})$",
                            "description": "auto = the creative's own locale; otherwise the locale for files with no name."
                          }
                        }
                      },
                      "naming": {
                        "type": "object",
                        "properties": {
                          "campaign": {
                            "type": "string",
                            "maxLength": 200,
                            "description": "The campaign the batches launch into, by name: reused when it exists, else created."
                          },
                          "pattern": {
                            "type": "string",
                            "maxLength": 40,
                            "description": "The ad-name id for files dropped without a canonical name: {MMDD}, {YYMMDD}."
                          }
                        }
                      }
                    }
                  },
                  "make_default": {
                    "type": "boolean"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launches": {
      "get": {
        "operationId": "listLaunches",
        "summary": "Recent launches, with their Meta ids and status (created = PAUSED, active, failed).",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_launches`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_list_launches",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 20,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createLaunch",
        "summary": "Create ads PAUSED — campaign, ad set and ads — and record the launch.",
        "description": "PAUSED is the draft: nothing spends until POST /api/v1/launches/{launchId}/activate. Each creative is uploaded from a public https URL, every Advantage+ enhancement is opted out, and ad names must be canonical (`id__locale__format__persona__angle__concept__variant`). With a launch preset only `creatives` is required: `campaign`, `ad_set` and `copy` default to the preset's (`preset_id`, or the workspace default). A retry without an `Idempotency-Key` reuses an ad set the failed attempt already made, but can still upload twice — send the key.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_launch_ads`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_launch_ads",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "preset_id": {
                    "description": "The launch preset (meta_list_presets) that fills whatever this call leaves out — campaign, adSet, copy. Omitted: the workspace default preset, used only when one of the three is missing.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "campaign": {
                    "description": "Omit to take the preset's: its campaign by name, or a new CBO campaign.",
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "existing_id": {
                            "type": "string",
                            "description": "A campaign id from meta_list_campaigns."
                          }
                        },
                        "required": [
                          "existing_id"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "minLength": 1
                          },
                          "objective": {
                            "type": "string",
                            "enum": [
                              "OUTCOME_SALES",
                              "OUTCOME_LEADS",
                              "OUTCOME_TRAFFIC",
                              "OUTCOME_APP_PROMOTION",
                              "OUTCOME_AWARENESS",
                              "OUTCOME_ENGAGEMENT"
                            ]
                          },
                          "daily_budget": {
                            "type": "number",
                            "exclusiveMinimum": 0,
                            "description": "Daily budget in the account currency, e.g. 50 = 50.00."
                          }
                        },
                        "required": [
                          "name",
                          "objective",
                          "daily_budget"
                        ]
                      }
                    ]
                  },
                  "ad_set": {
                    "description": "Omit for a new ad set with the preset's audience and destination.",
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "existing_id": {
                            "type": "string",
                            "description": "An ad set id from meta_list_campaigns."
                          }
                        },
                        "required": [
                          "existing_id"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "minLength": 1
                          },
                          "countries": {
                            "minItems": 1,
                            "type": "array",
                            "items": {
                              "type": "string",
                              "minLength": 2,
                              "maxLength": 2
                            },
                            "description": "ISO 3166-1 alpha-2 codes."
                          },
                          "age_min": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "age_max": {
                            "type": "integer",
                            "minimum": 13,
                            "maximum": 65
                          },
                          "placements": {
                            "type": "string",
                            "enum": [
                              "facebook_instagram",
                              "automatic"
                            ],
                            "description": "facebook_instagram (default): Facebook + Instagram only — no Audience Network, Messenger, Threads or WhatsApp. automatic: Meta's Advantage+ placements, Audience Network included."
                          },
                          "conversion_event": {
                            "description": "Omit for a traffic ad set (optimises for link clicks). Locked after publish.",
                            "type": "string",
                            "enum": [
                              "PURCHASE",
                              "INITIATE_CHECKOUT",
                              "ADD_TO_CART",
                              "LEAD",
                              "COMPLETE_REGISTRATION",
                              "START_TRIAL",
                              "SUBSCRIBE"
                            ]
                          },
                          "lead_form": {
                            "description": "An instant-form ad set: the ads open a Meta lead form (copy.leadFormId) instead of a website. Needs a campaign with objective OUTCOME_LEADS; no conversionEvent. LEAD_GENERATION = every submitted form; QUALITY_LEAD = Meta's conversion leads, which only learns when CRM stages are sent back.",
                            "type": "object",
                            "properties": {
                              "optimization": {
                                "default": "LEAD_GENERATION",
                                "type": "string",
                                "enum": [
                                  "LEAD_GENERATION",
                                  "QUALITY_LEAD"
                                ]
                              }
                            }
                          }
                        },
                        "required": [
                          "name",
                          "countries"
                        ]
                      }
                    ]
                  },
                  "creatives": {
                    "minItems": 1,
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "anyOf": [
                        {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string",
                              "minLength": 1
                            },
                            "media_url": {
                              "type": "string",
                              "format": "uri",
                              "description": "A public https URL Meta can fetch."
                            }
                          },
                          "required": [
                            "name",
                            "media_url"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string",
                              "minLength": 1
                            },
                            "asset_id": {
                              "type": "string",
                              "format": "uuid",
                              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
                              "description": "A library upload (meta_list_creatives): launched from its stored original and linked to it."
                            }
                          },
                          "required": [
                            "name",
                            "asset_id"
                          ]
                        },
                        {
                          "type": "object",
                          "properties": {
                            "name": {
                              "type": "string",
                              "minLength": 1
                            },
                            "media": {
                              "minItems": 2,
                              "maxItems": 2,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "ratio": {
                                    "type": "string",
                                    "enum": [
                                      "4x5",
                                      "1x1",
                                      "9x16"
                                    ]
                                  },
                                  "url": {
                                    "type": "string",
                                    "format": "uri"
                                  },
                                  "asset_id": {
                                    "type": "string",
                                    "format": "uuid",
                                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                                  }
                                },
                                "required": [
                                  "ratio"
                                ]
                              },
                              "description": "ONE ad from two files: a 9x16 (Stories and Reels) and a 4x5 or 1x1 (every other placement), each by url or library assetId. The name carries no ratio."
                            }
                          },
                          "required": [
                            "name",
                            "media"
                          ]
                        }
                      ]
                    }
                  },
                  "copy": {
                    "description": "Omit to take the preset's: the angle's approved messaging (when the preset writes from the recipe) or its fallback copy, with its destination.",
                    "type": "object",
                    "properties": {
                      "primary_text": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 5000
                      },
                      "headline": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 40
                      },
                      "description": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "cta": {
                        "default": "LEARN_MORE",
                        "type": "string",
                        "enum": [
                          "LEARN_MORE",
                          "SHOP_NOW",
                          "SIGN_UP",
                          "SUBSCRIBE",
                          "DOWNLOAD",
                          "GET_OFFER",
                          "GET_QUOTE",
                          "CONTACT_US",
                          "APPLY_NOW"
                        ]
                      },
                      "link": {
                        "description": "The website. Omit for an instant-form ad.",
                        "type": "string",
                        "format": "uri"
                      },
                      "url_tags": {
                        "description": "Query string appended to the link, e.g. utm_source=meta.",
                        "type": "string"
                      },
                      "lead_form_id": {
                        "description": "The instant form the ad opens (meta_list_lead_forms). Needs an instant-form ad set; the CTA must be one Meta offers on a form (LEARN_MORE, SIGN_UP, GET_QUOTE, APPLY_NOW, DOWNLOAD, SUBSCRIBE).",
                        "type": "string",
                        "pattern": "^\\d+$"
                      }
                    },
                    "required": [
                      "primary_text",
                      "headline"
                    ]
                  },
                  "page_id": {
                    "description": "The Facebook Page the ads publish under. Omit for the workspace default.",
                    "type": "string",
                    "pattern": "^\\d+$"
                  },
                  "pixel_id": {
                    "description": "The Pixel for conversion tracking. Omit for the workspace default.",
                    "type": "string",
                    "pattern": "^\\d+$"
                  },
                  "test_id": {
                    "description": "The Test these ads run for: the launch and its ads are linked to it. Still PAUSED.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "brief_id": {
                    "description": "The brief these ads were made from: the launch is linked to it, and the brief goes live when an ad first delivers. Still PAUSED.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  }
                },
                "required": [
                  "creatives"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launches/{launchId}/activate": {
      "post": {
        "operationId": "activateLaunch",
        "summary": "Money-moving: flip a launch's ads, ad set and campaign to ACTIVE.",
        "description": "Spends from the moment it returns. Requires the approval grant: a key that may launch PAUSED drafts may not, by that alone, put them live.\n\nRequires a key with `write` scope or higher, and the approval grant.\n\nMCP: `meta_activate`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_activate",
        "parameters": [
          {
            "name": "launchId",
            "in": "path",
            "required": true,
            "description": "A launch id, from GET /api/v1/launches or the launch's create response.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launches/{launchId}/pause": {
      "post": {
        "operationId": "pauseLaunch",
        "summary": "Pause a launch's ads (the ad set and campaign are left alone).",
        "description": "Requires a key with `write` scope or higher, and the approval grant.\n\nMCP: `meta_pause_launch`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_pause_launch",
        "parameters": [
          {
            "name": "launchId",
            "in": "path",
            "required": true,
            "description": "A launch id, from GET /api/v1/launches or the launch's create response.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/launches/{launchId}/copy": {
      "patch": {
        "operationId": "updateLaunchCopy",
        "summary": "Change the CTA, link, URL tags or ad text on every ad of a launch.",
        "description": "Rebuilds each ad's creative (Meta creatives are immutable) and repoints the ad: ACTIVE ads go back through Meta's review, the post's likes and comments do not carry over, and learning restarts. Change link and text in one call so the ads are reviewed once. Requires the approval grant because it changes what live ads deliver.\n\nRequires a key with `write` scope or higher, and the approval grant.\n\nMCP: `meta_relink_launch`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_relink_launch",
        "parameters": [
          {
            "name": "launchId",
            "in": "path",
            "required": true,
            "description": "A launch id, from GET /api/v1/launches or the launch's create response.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cta": {
                    "type": "string",
                    "enum": [
                      "LEARN_MORE",
                      "SHOP_NOW",
                      "SIGN_UP",
                      "SUBSCRIBE",
                      "DOWNLOAD",
                      "GET_OFFER",
                      "GET_QUOTE",
                      "CONTACT_US",
                      "APPLY_NOW"
                    ]
                  },
                  "link": {
                    "type": "string",
                    "format": "uri"
                  },
                  "url_tags": {
                    "description": "Replaces the tags; empty string clears them.",
                    "type": "string"
                  },
                  "primary_text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 5000
                  },
                  "headline": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 40
                  },
                  "description": {
                    "description": "Replaces the description; empty string clears it.",
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ads/{adId}/status": {
      "post": {
        "operationId": "setAdStatus",
        "summary": "Pause or resume one ad by its Meta ad id.",
        "description": "`PAUSED` stops spend; `ACTIVE` is money-moving. Only the ad changes — `effectiveStatus` stays ADSET_PAUSED / CAMPAIGN_PAUSED when a parent is off.\n\nRequires a key with `write` scope or higher, and the approval grant.\n\nMCP: `meta_set_ad_status`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_set_ad_status",
        "parameters": [
          {
            "name": "adId",
            "in": "path",
            "required": true,
            "description": "A Meta ad id, from GET /api/v1/ads.",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "ACTIVE",
                      "PAUSED"
                    ]
                  }
                },
                "required": [
                  "status"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/ad-sets/{adSetId}/targeting": {
      "patch": {
        "operationId": "updateAdSetTargeting",
        "summary": "Change an existing ad set's placements and/or age range.",
        "description": "Only the fields sent change. A significant edit: the ad set re-enters learning, so send every targeting change for one ad set in one call. Returns before / after.\n\nRequires a key with `write` scope or higher, and the approval grant.\n\nMCP: `meta_update_ad_set_targeting`.",
        "tags": [
          "launches"
        ],
        "x-mcp-tool": "meta_update_ad_set_targeting",
        "parameters": [
          {
            "name": "adSetId",
            "in": "path",
            "required": true,
            "description": "A Meta ad set id, from GET /api/v1/campaigns.",
            "schema": {
              "type": "string",
              "pattern": "^\\d+$"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "placements": {
                    "type": "string",
                    "enum": [
                      "facebook_instagram",
                      "automatic"
                    ],
                    "description": "facebook_instagram (default): Facebook + Instagram only — no Audience Network, Messenger, Threads or WhatsApp. automatic: Meta's Advantage+ placements, Audience Network included."
                  },
                  "age_min": {
                    "type": "integer",
                    "minimum": 13,
                    "maximum": 65
                  },
                  "age_max": {
                    "type": "integer",
                    "minimum": 13,
                    "maximum": 65
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key's authorization is short on one of two axes: it is below `write`, or it lacks the approval grant. The grant is a separate boolean, not a rung above `write` — a key can hold `admin` and still be refused here.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires the approval grant (activate, pause or resume ads, retarget an ad set, or rebuild a launch's live creative — what changes spend on Meta) — this key does not have it.",
                    "required_grant": "approve",
                    "key_scope": "write",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives": {
      "get": {
        "operationId": "listCreatives",
        "summary": "Creatives and swipes with their Values, confidences and lifetime performance.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_creatives`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_list_creatives",
        "parameters": [
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "schema": {
              "default": "needs_review",
              "type": "string",
              "enum": [
                "needs_review",
                "all",
                "unclassified",
                "drafts",
                "unsure",
                "top_spend"
              ]
            }
          },
          {
            "name": "subject",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "asset",
                "swipe",
                "all"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "default": 0,
              "type": "integer",
              "minimum": 0,
              "maximum": 9007199254740991
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives/{creativeId}": {
      "get": {
        "operationId": "getCreative",
        "summary": "One creative (or swipe) with its Values and performance; optionally its image.",
        "description": "`image=true` adds `image.data`, the still as base64 — the 600px feed thumbnail when Meta still serves it, else our poster. A video comes back as one frame. `transcript` is what the video says (language and timed segments) when one is stored, else null.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_get_creative`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_get_creative",
        "parameters": [
          {
            "name": "creativeId",
            "in": "path",
            "required": true,
            "description": "An asset id (or a swipe id with `subject=swipe`), from GET /api/v1/creatives.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "subject",
            "in": "query",
            "required": false,
            "schema": {
              "default": "asset",
              "type": "string",
              "enum": [
                "asset",
                "swipe"
              ]
            }
          },
          {
            "name": "image",
            "in": "query",
            "required": false,
            "schema": {
              "default": false,
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCreative",
        "summary": "Rename and re-tag one library upload.",
        "description": "`title` (null clears it) and/or `tags`, which replace the current ones. A human edit wins: the auto-labeler only fills what is empty. Values are PATCH /api/v1/creatives/values.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_update_creative`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_update_creative",
        "parameters": [
          {
            "name": "creativeId",
            "in": "path",
            "required": true,
            "description": "An asset id (or a swipe id with `subject=swipe`), from GET /api/v1/creatives.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 100
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "tags": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives/{creativeId}/recipe": {
      "get": {
        "operationId": "getRecipe",
        "summary": "The recipe of one static: layout, copy, visual system, replaceable slots.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_recipe`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_get_recipe",
        "parameters": [
          {
            "name": "creativeId",
            "in": "path",
            "required": true,
            "description": "An asset id (or a swipe id with `subject=swipe`), from GET /api/v1/creatives.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "subject",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "asset",
                "swipe"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives/values": {
      "patch": {
        "operationId": "setCreativeValues",
        "summary": "Set one or many creatives' Values by Value id — a human-grade override.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_set_creative_links`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_set_creative_links",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "subject": {
                    "type": "string",
                    "enum": [
                      "asset",
                      "swipe"
                    ]
                  },
                  "id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "ids": {
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "persona": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "angle": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "format": {
                    "anyOf": [
                      {
                        "maxItems": 3,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        }
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "offer": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "pain": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "visual": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "visual_mode": {
                    "default": "replace",
                    "type": "string",
                    "enum": [
                      "replace",
                      "add"
                    ]
                  },
                  "awareness": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "unaware",
                          "problem-aware",
                          "solution-aware",
                          "product-aware",
                          "most-aware"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "asset_type": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "ugc",
                          "hybrid",
                          "lifestyle-image-text",
                          "product-image-text",
                          "text-only",
                          "illustration",
                          "ugc-mashup",
                          "other"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "hook": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "aspirational",
                          "authority",
                          "belief",
                          "bold-claim",
                          "call-to-action-first",
                          "challenge",
                          "contrast",
                          "confession",
                          "contrarian",
                          "curiosity",
                          "demographic-callout",
                          "direct-address",
                          "directive",
                          "exclusivity",
                          "explainer",
                          "fomo",
                          "how-to",
                          "if-then",
                          "listicle",
                          "myth-busting",
                          "offer-only",
                          "price-anchor",
                          "question",
                          "reasons-why",
                          "relatability",
                          "reverse-psychology",
                          "risk-reversal",
                          "shocking-statement",
                          "social-proof",
                          "statistic",
                          "storytelling",
                          "urgency",
                          "warning",
                          "none"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "headline_tactic": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "aspirational",
                          "authority",
                          "belief",
                          "bold-claim",
                          "call-to-action-first",
                          "challenge",
                          "contrast",
                          "confession",
                          "contrarian",
                          "curiosity",
                          "demographic-callout",
                          "direct-address",
                          "directive",
                          "exclusivity",
                          "explainer",
                          "fomo",
                          "how-to",
                          "if-then",
                          "listicle",
                          "myth-busting",
                          "offer-only",
                          "price-anchor",
                          "question",
                          "reasons-why",
                          "relatability",
                          "reverse-psychology",
                          "risk-reversal",
                          "shocking-statement",
                          "social-proof",
                          "statistic",
                          "storytelling",
                          "urgency",
                          "warning",
                          "none"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "offer_type": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "no-offer",
                          "promo",
                          "always-on-offer"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "season": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "evergreen",
                          "new-year",
                          "valentines",
                          "summer",
                          "back-to-school",
                          "black-friday",
                          "christmas",
                          "other"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "talent": {
                    "anyOf": [
                      {
                        "type": "string",
                        "enum": [
                          "none",
                          "creator",
                          "founder",
                          "customer",
                          "model"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "subject"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives/delete": {
      "post": {
        "operationId": "deleteCreatives",
        "summary": "Permanently delete library uploads that never became an ad.",
        "description": "Deletes the file, its Values, notes and brief links. Each id is deleted or refused with a reason: a creative in any ad keeps its row, because its performance is read through that link; so does one in a Test.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_delete_creatives`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_delete_creatives",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "minItems": 1,
                    "maxItems": 100,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  }
                },
                "required": [
                  "ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/creatives/reviews": {
      "post": {
        "operationId": "reviewCreatives",
        "summary": "Tag many creatives by Value name, as a strategist reviewing the classifier.",
        "description": "A name nobody has becomes a draft Value; near-duplicates fold into one. Every creative touched is marked curated, so the in-app classifier only fills gaps behind it.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_tag_creatives`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_tag_creatives",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "items": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "subject": {
                          "default": "asset",
                          "type": "string",
                          "enum": [
                            "asset",
                            "swipe"
                          ]
                        },
                        "id": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        },
                        "values": {
                          "type": "object",
                          "properties": {
                            "angle": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "persona": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "offer": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "pain": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "format": {
                              "anyOf": [
                                {
                                  "anyOf": [
                                    {
                                      "type": "string"
                                    },
                                    {
                                      "maxItems": 3,
                                      "type": "array",
                                      "items": {
                                        "type": "string"
                                      }
                                    }
                                  ]
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "visual": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            },
                            "awareness": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "enum": [
                                    "unaware",
                                    "problem-aware",
                                    "solution-aware",
                                    "product-aware",
                                    "most-aware"
                                  ]
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            },
                            "asset_type": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "hook": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "headline_tactic": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "offer_type": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "season": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "talent": {
                              "anyOf": [
                                {
                                  "type": "string",
                                  "enum": [
                                    "none",
                                    "creator",
                                    "founder",
                                    "customer",
                                    "model"
                                  ]
                                },
                                {
                                  "type": "null"
                                }
                              ]
                            }
                          },
                          "additionalProperties": false
                        },
                        "rationale": {
                          "type": "string",
                          "maxLength": 400
                        }
                      },
                      "required": [
                        "id",
                        "values"
                      ]
                    }
                  }
                },
                "required": [
                  "items"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/drafts": {
      "get": {
        "operationId": "listDrafts",
        "summary": "Generated drafts, newest first, optionally for one subject.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_drafts`.",
        "tags": [
          "creatives"
        ],
        "x-mcp-tool": "meta_list_drafts",
        "parameters": [
          {
            "name": "subject",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asset",
                "swipe"
              ]
            }
          },
          {
            "name": "subject_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 20,
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxonomy": {
      "get": {
        "operationId": "getTaxonomy",
        "summary": "The house Dimensions and this workspace's Values, with how many creatives carry each.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_taxonomy`.",
        "tags": [
          "taxonomy"
        ],
        "x-mcp-tool": "meta_list_taxonomy",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxonomy/values": {
      "post": {
        "operationId": "createTaxonomyValue",
        "summary": "Create a Value on an open Dimension (approved, attributed to the caller).",
        "description": "Refused with the existing Value when the same idea is already there (`price card` = `Pricing cards`) — use it, or PATCH it. Archived Values come back with PATCH `status: approved`.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_create_taxonomy_value`.",
        "tags": [
          "taxonomy"
        ],
        "x-mcp-tool": "meta_create_taxonomy_value",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dimension": {
                    "type": "string",
                    "enum": [
                      "angle",
                      "persona",
                      "offer",
                      "pain",
                      "format",
                      "visual"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 400
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "dimension",
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxonomy/values/{valueId}": {
      "patch": {
        "operationId": "updateTaxonomyValue",
        "summary": "Rename, approve or archive a Value.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_update_taxonomy_value`.",
        "tags": [
          "taxonomy"
        ],
        "x-mcp-tool": "meta_update_taxonomy_value",
        "parameters": [
          {
            "name": "valueId",
            "in": "path",
            "required": true,
            "description": "A Value id on an open Dimension, from GET /api/v1/taxonomy.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dimension": {
                    "type": "string",
                    "enum": [
                      "angle",
                      "persona",
                      "offer",
                      "pain",
                      "format",
                      "visual"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 80
                  },
                  "description": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 400
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "approved",
                      "archived"
                    ]
                  },
                  "persona": {
                    "type": "object",
                    "properties": {
                      "summary": {
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 600
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "psychographics": {
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 2000
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "pains": {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      },
                      "desires": {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      },
                      "objections": {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      },
                      "triggers": {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      },
                      "trust_needs": {
                        "maxItems": 30,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        }
                      },
                      "language_notes": {
                        "anyOf": [
                          {
                            "type": "string",
                            "maxLength": 2000
                          },
                          {
                            "type": "null"
                          }
                        ]
                      }
                    }
                  },
                  "persona_mode": {
                    "default": "append",
                    "type": "string",
                    "enum": [
                      "append",
                      "replace"
                    ]
                  }
                },
                "required": [
                  "dimension"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxonomy/values/{valueId}/merge": {
      "post": {
        "operationId": "mergeTaxonomyValue",
        "summary": "Fold a Value into another on the same Dimension, then delete it.",
        "description": "Every creative that carried `{valueId}` now carries `into_id`. Irreversible.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_merge_taxonomy_values`.",
        "tags": [
          "taxonomy"
        ],
        "x-mcp-tool": "meta_merge_taxonomy_values",
        "parameters": [
          {
            "name": "valueId",
            "in": "path",
            "required": true,
            "description": "A Value id on an open Dimension, from GET /api/v1/taxonomy.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "dimension": {
                    "type": "string",
                    "enum": [
                      "angle",
                      "persona",
                      "offer",
                      "pain",
                      "format",
                      "visual"
                    ]
                  },
                  "into_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  }
                },
                "required": [
                  "dimension",
                  "into_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/taxonomy/merge-suggestions/{suggestionId}/answer": {
      "post": {
        "operationId": "answerMergeSuggestion",
        "summary": "Merge two approved Values the reconcile pass read as one idea, or keep them apart.",
        "description": "`decision: merge` folds the suggestion's `mergeId` into its `keepId` (irreversible); `keep_apart` is remembered and the pair is never suggested again. Open suggestions are `mergeSuggestions` on `GET /api/v1/taxonomy`.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_answer_merge_suggestion`.",
        "tags": [
          "taxonomy"
        ],
        "x-mcp-tool": "meta_answer_merge_suggestion",
        "parameters": [
          {
            "name": "suggestionId",
            "in": "path",
            "required": true,
            "description": "The suggestionId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "decision": {
                    "type": "string",
                    "enum": [
                      "merge",
                      "keep_apart"
                    ]
                  }
                },
                "required": [
                  "decision"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/briefs": {
      "get": {
        "operationId": "listBriefs",
        "summary": "Briefs on the Briefs board, newest first, with what was made from each.",
        "description": "Board briefs and the ones written from Next tests. `status` follows the work (draft → ready → in_production → live → learned); dismissed briefs only with `include_dismissed`. `owner` is anyone, me (the key's minter), agent or others; `value_id` (with an optional `dimension`) keeps briefs scoped to that Value.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_briefs`.",
        "tags": [
          "briefs"
        ],
        "x-mcp-tool": "meta_list_briefs",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "ready",
                "in_production",
                "live",
                "learned",
                "dismissed"
              ]
            }
          },
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "description": "me = the human this session acts for; agent = written over MCP or the API.",
            "schema": {
              "default": "anyone",
              "type": "string",
              "enum": [
                "anyone",
                "me",
                "agent",
                "others"
              ]
            }
          },
          {
            "name": "dimension",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "angle",
                "persona",
                "awareness",
                "offer",
                "offer_type",
                "pain",
                "season",
                "asset_type",
                "format",
                "hook",
                "headline_tactic",
                "talent",
                "visual"
              ]
            }
          },
          {
            "name": "value_id",
            "in": "query",
            "required": false,
            "description": "Briefs scoped to this Value.",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 100
            }
          },
          {
            "name": "include_dismissed",
            "in": "query",
            "required": false,
            "schema": {
              "default": false,
              "type": "boolean"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "saveBriefs",
        "summary": "Save briefs or strategist notes. Re-saving an id replaces its brief.",
        "description": "A brief may only quote numbers its `evidence` carries. Next-test ids come from the MCP surface's analysis (it ranks; REST does not); a free note takes an id `note:<slug>`.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_briefs`.",
        "tags": [
          "briefs"
        ],
        "x-mcp-tool": "meta_save_briefs",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "window": {
                    "default": "90d",
                    "type": "string",
                    "enum": [
                      "30d",
                      "90d",
                      "180d",
                      "lifetime"
                    ]
                  },
                  "funnel": {
                    "type": "string",
                    "enum": [
                      "instant_form",
                      "website",
                      "messaging",
                      "profile",
                      "traffic",
                      "unknown"
                    ]
                  },
                  "briefs": {
                    "minItems": 1,
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "test_id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 300
                        },
                        "title": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "why": {
                          "type": "string",
                          "maxLength": 800
                        },
                        "make": {
                          "type": "string",
                          "maxLength": 800
                        },
                        "openers": {
                          "maxItems": 5,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "maxLength": 160
                          }
                        },
                        "evidence": {
                          "maxItems": 10,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "maxLength": 400
                          }
                        }
                      },
                      "required": [
                        "test_id",
                        "title"
                      ]
                    }
                  }
                },
                "required": [
                  "briefs"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/briefs/{briefId}": {
      "get": {
        "operationId": "getBrief",
        "summary": "One brief in full, with the learnings it cites and what was made from it.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_brief`.",
        "tags": [
          "briefs"
        ],
        "x-mcp-tool": "meta_get_brief",
        "parameters": [
          {
            "name": "briefId",
            "in": "path",
            "required": true,
            "description": "The briefId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateBrief",
        "summary": "Change a brief's fields, status or links.",
        "description": "By hand a brief moves draft ⇄ ready, to dismissed, or back from dismissed to draft; the other moves follow the work (a linked draft or asset, an ad's first delivery, a Test's conclusion) and are refused here.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_update_brief`.",
        "tags": [
          "briefs"
        ],
        "x-mcp-tool": "meta_update_brief",
        "parameters": [
          {
            "name": "briefId",
            "in": "path",
            "required": true,
            "description": "The briefId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "ready",
                      "in_production",
                      "live",
                      "learned",
                      "dismissed"
                    ]
                  },
                  "fields": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "concept": {
                        "description": "The idea and why it should work.",
                        "type": "string",
                        "maxLength": 2000
                      },
                      "copy": {
                        "type": "object",
                        "properties": {
                          "hook": {
                            "type": "string",
                            "maxLength": 200
                          },
                          "headline": {
                            "type": "string",
                            "maxLength": 120
                          },
                          "primary_text": {
                            "type": "string",
                            "maxLength": 2000
                          },
                          "cta": {
                            "description": "The button, e.g. GET_QUOTE or Learn more.",
                            "type": "string",
                            "maxLength": 60
                          },
                          "lead_form_id": {
                            "type": "string",
                            "pattern": "^\\d+$"
                          },
                          "script": {
                            "maxItems": 20,
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "from": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 600,
                                  "description": "Seconds from the start."
                                },
                                "to": {
                                  "type": "number",
                                  "minimum": 0,
                                  "maximum": 600
                                },
                                "on_screen": {
                                  "default": "",
                                  "type": "string",
                                  "maxLength": 300
                                },
                                "vo": {
                                  "default": "",
                                  "description": "Voice-over, verbatim.",
                                  "type": "string",
                                  "maxLength": 400
                                }
                              },
                              "required": [
                                "from",
                                "to"
                              ]
                            }
                          }
                        }
                      },
                      "visual": {
                        "description": "The visual approach.",
                        "type": "string",
                        "maxLength": 2000
                      },
                      "reference": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "kind": {
                                "type": "string",
                                "enum": [
                                  "asset",
                                  "swipe",
                                  "ad"
                                ]
                              },
                              "id": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 100
                              }
                            },
                            "required": [
                              "kind",
                              "id"
                            ]
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "deliverables": {
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "count": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 50
                            },
                            "format": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 80,
                              "description": "Static, UGC selfie, carousel…"
                            },
                            "ratios": {
                              "default": [],
                              "maxItems": 4,
                              "type": "array",
                              "items": {
                                "type": "string",
                                "enum": [
                                  "1:1",
                                  "4:5",
                                  "9:16",
                                  "16:9"
                                ]
                              }
                            },
                            "max_seconds": {
                              "type": "integer",
                              "minimum": 1,
                              "maximum": 600
                            }
                          },
                          "required": [
                            "count",
                            "format"
                          ]
                        }
                      },
                      "success": {
                        "anyOf": [
                          {
                            "type": "object",
                            "properties": {
                              "goal_event": {
                                "type": "string",
                                "enum": [
                                  "add_to_cart",
                                  "form_lead",
                                  "website_lead",
                                  "conversation",
                                  "purchase",
                                  "view_content",
                                  "link_click"
                                ]
                              },
                              "target": {
                                "default": null,
                                "anyOf": [
                                  {
                                    "type": "number",
                                    "exclusiveMinimum": 0
                                  },
                                  {
                                    "type": "null"
                                  }
                                ]
                              },
                              "window_days": {
                                "default": 7,
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 180
                              },
                              "min_expected_goals": {
                                "default": 10,
                                "type": "number",
                                "minimum": 1,
                                "maximum": 1000
                              }
                            },
                            "required": [
                              "goal_event"
                            ]
                          },
                          {
                            "type": "null"
                          }
                        ]
                      },
                      "scope": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "dimension": {
                              "type": "string",
                              "enum": [
                                "angle",
                                "persona",
                                "awareness",
                                "offer",
                                "offer_type",
                                "pain",
                                "season",
                                "asset_type",
                                "format",
                                "hook",
                                "headline_tactic",
                                "talent",
                                "visual"
                              ]
                            },
                            "value_id": {
                              "type": "string",
                              "minLength": 1,
                              "maxLength": 100
                            }
                          },
                          "required": [
                            "dimension",
                            "value_id"
                          ]
                        }
                      },
                      "learning_ids": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "format": "uuid",
                          "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                        }
                      },
                      "evidence": {
                        "description": "Facts the brief quotes that no cited learning carries — an offer price, a proof point.",
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 400
                        }
                      }
                    }
                  },
                  "links": {
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "draft",
                            "asset",
                            "launch",
                            "test"
                          ]
                        },
                        "ref_id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "kind",
                        "ref_id"
                      ]
                    }
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/briefs/board": {
      "post": {
        "operationId": "saveBrief",
        "summary": "Put one brief on the Briefs board as a Draft.",
        "description": "The concept and copy may only quote numbers their evidence carries: the cited `learning_ids`, the workspace's offer and proof points, or `evidence` lines. Refused otherwise, naming the numbers.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_brief`.",
        "tags": [
          "briefs"
        ],
        "x-mcp-tool": "meta_save_brief",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "concept": {
                    "description": "The idea and why it should work.",
                    "type": "string",
                    "maxLength": 2000
                  },
                  "copy": {
                    "type": "object",
                    "properties": {
                      "hook": {
                        "type": "string",
                        "maxLength": 200
                      },
                      "headline": {
                        "type": "string",
                        "maxLength": 120
                      },
                      "primary_text": {
                        "type": "string",
                        "maxLength": 2000
                      },
                      "cta": {
                        "description": "The button, e.g. GET_QUOTE or Learn more.",
                        "type": "string",
                        "maxLength": 60
                      },
                      "lead_form_id": {
                        "type": "string",
                        "pattern": "^\\d+$"
                      },
                      "script": {
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "from": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 600,
                              "description": "Seconds from the start."
                            },
                            "to": {
                              "type": "number",
                              "minimum": 0,
                              "maximum": 600
                            },
                            "on_screen": {
                              "default": "",
                              "type": "string",
                              "maxLength": 300
                            },
                            "vo": {
                              "default": "",
                              "description": "Voice-over, verbatim.",
                              "type": "string",
                              "maxLength": 400
                            }
                          },
                          "required": [
                            "from",
                            "to"
                          ]
                        }
                      }
                    }
                  },
                  "visual": {
                    "description": "The visual approach.",
                    "type": "string",
                    "maxLength": 2000
                  },
                  "reference": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "kind": {
                            "type": "string",
                            "enum": [
                              "asset",
                              "swipe",
                              "ad"
                            ]
                          },
                          "id": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 100
                          }
                        },
                        "required": [
                          "kind",
                          "id"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "deliverables": {
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 50
                        },
                        "format": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 80,
                          "description": "Static, UGC selfie, carousel…"
                        },
                        "ratios": {
                          "default": [],
                          "maxItems": 4,
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "1:1",
                              "4:5",
                              "9:16",
                              "16:9"
                            ]
                          }
                        },
                        "max_seconds": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 600
                        }
                      },
                      "required": [
                        "count",
                        "format"
                      ]
                    }
                  },
                  "success": {
                    "anyOf": [
                      {
                        "type": "object",
                        "properties": {
                          "goal_event": {
                            "type": "string",
                            "enum": [
                              "add_to_cart",
                              "form_lead",
                              "website_lead",
                              "conversation",
                              "purchase",
                              "view_content",
                              "link_click"
                            ]
                          },
                          "target": {
                            "default": null,
                            "anyOf": [
                              {
                                "type": "number",
                                "exclusiveMinimum": 0
                              },
                              {
                                "type": "null"
                              }
                            ]
                          },
                          "window_days": {
                            "default": 7,
                            "type": "integer",
                            "minimum": 1,
                            "maximum": 180
                          },
                          "min_expected_goals": {
                            "default": 10,
                            "type": "number",
                            "minimum": 1,
                            "maximum": 1000
                          }
                        },
                        "required": [
                          "goal_event"
                        ]
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "scope": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "dimension": {
                          "type": "string",
                          "enum": [
                            "angle",
                            "persona",
                            "awareness",
                            "offer",
                            "offer_type",
                            "pain",
                            "season",
                            "asset_type",
                            "format",
                            "hook",
                            "headline_tactic",
                            "talent",
                            "visual"
                          ]
                        },
                        "value_id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "dimension",
                        "value_id"
                      ]
                    }
                  },
                  "learning_ids": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "evidence": {
                    "description": "Facts the brief quotes that no cited learning carries — an offer price, a proof point.",
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 400
                    }
                  }
                },
                "required": [
                  "title"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests": {
      "get": {
        "operationId": "listTests",
        "summary": "Committed Tests, newest first.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_tests`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_list_tests",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "planned",
                "producing",
                "live",
                "concluded",
                "abandoned"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 30,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createTest",
        "summary": "Commit to a Test. Its intent is frozen from this moment.",
        "description": "Pass a `next_test_id` computed now (same `window` / `funnel`), or a `custom` test with its hypothesis and the evidence it rests on. A changed mind is a new Test with `supersedes_id`, never an edit. Touches nothing on Meta.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_create_test`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_create_test",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "next_test_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 300
                  },
                  "window": {
                    "default": "90d",
                    "type": "string",
                    "enum": [
                      "30d",
                      "90d",
                      "180d",
                      "lifetime"
                    ]
                  },
                  "funnel": {
                    "description": "The funnel the Next tests were read in; for an exploration that pools funnels, where to run it.",
                    "type": "string",
                    "enum": [
                      "instant_form",
                      "website",
                      "messaging",
                      "profile",
                      "traffic",
                      "unknown"
                    ]
                  },
                  "custom": {
                    "type": "object",
                    "properties": {
                      "title": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "hypothesis": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 800
                      },
                      "try": {
                        "default": [],
                        "maxItems": 6,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 200
                        }
                      },
                      "evidence": {
                        "minItems": 1,
                        "maxItems": 10,
                        "type": "array",
                        "items": {
                          "type": "string",
                          "maxLength": 400
                        }
                      },
                      "reference_asset_id": {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      }
                    },
                    "required": [
                      "title",
                      "hypothesis",
                      "evidence"
                    ]
                  },
                  "hypothesis": {
                    "description": "Overrides the default hypothesis written from the Next test.",
                    "type": "string",
                    "maxLength": 800
                  },
                  "comparator": {
                    "default": "baseline",
                    "type": "string",
                    "enum": [
                      "reference",
                      "baseline"
                    ]
                  },
                  "min_expected_goals": {
                    "type": "number",
                    "minimum": 1,
                    "maximum": 1000
                  },
                  "maturity_days": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 90
                  },
                  "window_days": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 180
                  },
                  "supersedes_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "brief_id": {
                    "description": "The brief this Test judges; it is linked, and learned when the Test concludes.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests/{testId}": {
      "get": {
        "operationId": "getTest",
        "summary": "One Test: frozen intent, evidence snapshot, artifacts and every Observation.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_test`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_get_test",
        "parameters": [
          {
            "name": "testId",
            "in": "path",
            "required": true,
            "description": "A Test id, from GET /api/v1/tests.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests/{testId}/links": {
      "post": {
        "operationId": "linkTestArtifacts",
        "summary": "Tie drafts, assets, ads or launches to a Test.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_link_test_artifacts`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_link_test_artifacts",
        "parameters": [
          {
            "name": "testId",
            "in": "path",
            "required": true,
            "description": "A Test id, from GET /api/v1/tests.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "links": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "draft",
                            "asset",
                            "ad",
                            "launch"
                          ]
                        },
                        "ref": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "kind",
                        "ref"
                      ]
                    }
                  }
                },
                "required": [
                  "links"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests/{testId}/observations": {
      "post": {
        "operationId": "observeTest",
        "summary": "Read a Test's outcome now and append it as an Observation.",
        "description": "Held to the rule frozen at commit. Low delivery is inconclusive, never a loss; every result is observational.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_observe_test`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_observe_test",
        "parameters": [
          {
            "name": "testId",
            "in": "path",
            "required": true,
            "description": "A Test id, from GET /api/v1/tests.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests/{testId}/conclusion": {
      "post": {
        "operationId": "concludeTest",
        "summary": "Record a Test's Conclusion. Final.",
        "description": "`supported` / `rejected` must match the latest Observation unless an `override_reason` is given, which is kept in the note. A second conclusion is refused.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_conclude_test`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_conclude_test",
        "parameters": [
          {
            "name": "testId",
            "in": "path",
            "required": true,
            "description": "A Test id, from GET /api/v1/tests.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "conclusion": {
                    "type": "string",
                    "enum": [
                      "supported",
                      "rejected",
                      "inconclusive",
                      "invalid"
                    ]
                  },
                  "note": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 1000
                  },
                  "override_reason": {
                    "type": "string",
                    "maxLength": 400
                  }
                },
                "required": [
                  "conclusion",
                  "note"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tests/{testId}/abandon": {
      "post": {
        "operationId": "abandonTest",
        "summary": "Stop a Test without a conclusion. Pauses nothing on Meta.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_abandon_test`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_abandon_test",
        "parameters": [
          {
            "name": "testId",
            "in": "path",
            "required": true,
            "description": "A Test id, from GET /api/v1/tests.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/learnings": {
      "get": {
        "operationId": "listLearnings",
        "summary": "The account's learnings, and the proposals nobody has accepted or dismissed.",
        "description": "Each learning is a statement of why, scoped on taxonomy Values, with its status history and the evidence the app computed. Proposals are drafts from concluded Tests and strong Traits; accept one by POSTing it with its `proposal_key`.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_learnings`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_list_learnings",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "hypothesis",
                "supported",
                "refuted",
                "retired"
              ]
            }
          },
          {
            "name": "dimension",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "angle",
                "persona",
                "awareness",
                "offer",
                "offer_type",
                "pain",
                "season",
                "asset_type",
                "format",
                "hook",
                "headline_tactic",
                "talent",
                "visual"
              ]
            }
          },
          {
            "name": "value_id",
            "in": "query",
            "required": false,
            "description": "A Value id (meta_list_taxonomy), or a closed Dimension's word.",
            "schema": {
              "type": "string",
              "maxLength": 100
            }
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "test",
                "trait",
                "analysis",
                "agent",
                "human"
              ]
            }
          },
          {
            "name": "include_proposals",
            "in": "query",
            "required": false,
            "schema": {
              "default": true,
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "saveLearning",
        "summary": "Record a learning. The app computes its evidence and returns the insight check.",
        "description": "`statement` is the why; `scope` the Values it applies to. Status starts as hypothesis, or supported / refuted when `test_id` names a concluded Test. `check.looks_like_observation` never blocks the save.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_learning`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_save_learning",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "statement": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 600
                  },
                  "observation": {
                    "type": "string",
                    "maxLength": 1200
                  },
                  "implication": {
                    "description": "What to make differently because of it. Briefs quote this line.",
                    "type": "string",
                    "maxLength": 800
                  },
                  "scope": {
                    "default": [],
                    "maxItems": 8,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "dimension": {
                          "type": "string",
                          "enum": [
                            "angle",
                            "persona",
                            "awareness",
                            "offer",
                            "offer_type",
                            "pain",
                            "season",
                            "asset_type",
                            "format",
                            "hook",
                            "headline_tactic",
                            "talent",
                            "visual"
                          ]
                        },
                        "value_id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "dimension",
                        "value_id"
                      ]
                    }
                  },
                  "proposal_key": {
                    "description": "Accept a proposal from meta_list_learnings: `test:<id>` or `trait:<trait id>`.",
                    "type": "string",
                    "maxLength": 300
                  },
                  "test_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "agent": {
                    "description": "Your name, e.g. \"Claude\" — shown as \"Added by Claude over MCP\".",
                    "type": "string",
                    "maxLength": 40
                  }
                },
                "required": [
                  "statement"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/learnings/{learningId}": {
      "get": {
        "operationId": "getLearning",
        "summary": "One learning: status history, evidence recomputed now, and the briefs citing it.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_get_learning`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_get_learning",
        "parameters": [
          {
            "name": "learningId",
            "in": "path",
            "required": true,
            "description": "The learningId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateLearning",
        "summary": "Change a learning's statement, scope or status. Status moves are appended.",
        "description": "Supported or refuted without a `test_id` needs a `reason`. Retire with status `retired`.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_update_learning`.",
        "tags": [
          "tests"
        ],
        "x-mcp-tool": "meta_update_learning",
        "parameters": [
          {
            "name": "learningId",
            "in": "path",
            "required": true,
            "description": "The learningId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "statement": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 600
                  },
                  "observation": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 1200
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "implication": {
                    "anyOf": [
                      {
                        "type": "string",
                        "maxLength": 800
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "scope": {
                    "maxItems": 8,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "dimension": {
                          "type": "string",
                          "enum": [
                            "angle",
                            "persona",
                            "awareness",
                            "offer",
                            "offer_type",
                            "pain",
                            "season",
                            "asset_type",
                            "format",
                            "hook",
                            "headline_tactic",
                            "talent",
                            "visual"
                          ]
                        },
                        "value_id": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 100
                        }
                      },
                      "required": [
                        "dimension",
                        "value_id"
                      ]
                    }
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "hypothesis",
                      "supported",
                      "refuted",
                      "retired"
                    ]
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 400
                  },
                  "test_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "agent": {
                    "type": "string",
                    "maxLength": 40
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/swipes": {
      "get": {
        "operationId": "listSwipes",
        "summary": "The swipe file: other people's ads, saved for reference.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_swipes`.",
        "tags": [
          "swipes"
        ],
        "x-mcp-tool": "meta_list_swipes",
        "parameters": [
          {
            "name": "source",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "all",
                "ad_library",
                "tiktok",
                "instagram",
                "url",
                "upload"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Matches advertiser, title or body.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tag",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "saveSwipe",
        "summary": "Save a reference ad from a link; its media is copied into storage.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_save_swipe`.",
        "tags": [
          "swipes"
        ],
        "x-mcp-tool": "meta_save_swipe",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "tags": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/swipes/{swipeId}": {
      "patch": {
        "operationId": "updateSwipe",
        "summary": "Replace a swipe's tags and/or note.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_update_swipe`.",
        "tags": [
          "swipes"
        ],
        "x-mcp-tool": "meta_update_swipe",
        "parameters": [
          {
            "name": "swipeId",
            "in": "path",
            "required": true,
            "description": "A swipe id, from GET /api/v1/swipes.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tags": {
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "notes": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "required": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/personas": {
      "get": {
        "operationId": "listPersonas",
        "summary": "Personas, each synthesized from customer quotes and curated by a human.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_personas`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_personas",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "archived",
                "all"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/angles": {
      "get": {
        "operationId": "listAngles",
        "summary": "Messaging angles, each with the persona it was born from.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_angles`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_angles",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "archived",
                "all"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/formats": {
      "get": {
        "operationId": "listFormats",
        "summary": "Creative formats derived from the swipe file and the library.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_formats`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_formats",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "archived",
                "all"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/verbatims": {
      "get": {
        "operationId": "listVerbatims",
        "summary": "Customer quotes, exactly as written.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_verbatims`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_verbatims",
        "parameters": [
          {
            "name": "persona_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "angle_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "pain",
                "desire",
                "objection",
                "trigger",
                "trust",
                "outcome",
                "praise",
                "competitor",
                "language"
              ]
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Substring match on the quote.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer",
              "minimum": 1,
              "maximum": 200
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/sources": {
      "get": {
        "operationId": "listResearchSources",
        "summary": "Every research source with its status and counts.",
        "description": "Requires a key with `read` scope or higher.\n\nMCP: `meta_list_research_sources`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_research_sources",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "addResearchSource",
        "summary": "Add customer language: an App Store / Google Play app, a URL, or pasted reviews.",
        "description": "Quotes are extracted in the background on the worker's schedule, not on save.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_add_research_source`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_add_research_source",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "app_store",
                      "google_play",
                      "url",
                      "paste"
                    ]
                  },
                  "reference": {
                    "description": "app_store / google_play: the store link, or the numeric app id.",
                    "type": "string",
                    "minLength": 1
                  },
                  "url": {
                    "description": "url: the page to read.",
                    "type": "string",
                    "format": "uri"
                  },
                  "text": {
                    "description": "paste: the reviews, one per block, blocks separated by a blank line.",
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 200000
                  },
                  "country": {
                    "description": "app_store / google_play: two-letter storefront code. Defaults to us.",
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 2
                  },
                  "label": {
                    "description": "How this source is listed. Say whose customers these are.",
                    "type": "string"
                  }
                },
                "required": [
                  "kind"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/sources/{sourceId}/refresh": {
      "post": {
        "operationId": "refreshResearchSource",
        "summary": "Fetch a source again: an app's newest reviews, or a page's current text.",
        "description": "Resumes from where the last fetch stopped; a page costs one scraper credit. Quotes are mined in the background. A pasted source has nothing to refresh.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_refresh_research_source`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_refresh_research_source",
        "parameters": [
          {
            "name": "sourceId",
            "in": "path",
            "required": true,
            "description": "A research source id, from GET /api/v1/research/sources.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Accepted. The work continues in the background; the body says how to follow it.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/sources/{sourceId}": {
      "delete": {
        "operationId": "deleteResearchSource",
        "summary": "Permanently delete a source and every document and quote mined from it.",
        "description": "Requires a key with `write` scope or higher.\n\nMCP: `meta_delete_research_source`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_delete_research_source",
        "parameters": [
          {
            "name": "sourceId",
            "in": "path",
            "required": true,
            "description": "A research source id, from GET /api/v1/research/sources.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/verbatims/link": {
      "post": {
        "operationId": "linkVerbatims",
        "summary": "File customer quotes under a persona and/or an angle (null detaches).",
        "description": "Changes whom a quote is evidence for, never the quote. Up to 200 ids per call; `persona_id` / `angle_id` come from the personas and angles lists.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_link_verbatims`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_link_verbatims",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "minItems": 1,
                    "maxItems": 200,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "persona_id": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "angle_id": {
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uuid",
                        "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/messaging": {
      "get": {
        "operationId": "listMessaging",
        "summary": "Copy lines per angle, with status, author and the quotes they cite.",
        "description": "`status` defaults to `all`, rejected lines included — drafting reads them so a turned-down line is never written again. Approved lines prefill a launch's copy.\n\nRequires a key with `read` scope or higher.\n\nMCP: `meta_list_messaging`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_list_messaging",
        "parameters": [
          {
            "name": "angle_id",
            "in": "query",
            "required": false,
            "description": "From meta_list_angles.",
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "hook",
                "headline",
                "primary_text",
                "objection"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "default": "all",
              "type": "string",
              "enum": [
                "draft",
                "approved",
                "rejected",
                "all"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "default": 100,
              "type": "integer",
              "minimum": 1,
              "maximum": 500
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `read`. Scopes are ranked, so any tier at or above `read` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires read access — this key has 'read' scope.",
                    "required_scope": "read",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createMessagingLine",
        "summary": "Add a copy line you wrote (hook, headline, primary text or objection).",
        "description": "Stored as a human line (`source: human`), which may cite no quote; `verbatim_ids` cites some. A draft unless `status` is `approved`. A headline is at most 40 characters.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_messaging`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_save_messaging",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Any unique string up to 256 characters. A retry with the same key and body replays the first success (`Idempotency-Replay: true`) instead of doing the work twice; the same key with a different body is refused.",
            "schema": {
              "type": "string",
              "maxLength": 256
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "angle_id": {
                    "description": "New line: the angle it argues.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "kind": {
                    "description": "New line: its kind.",
                    "type": "string",
                    "enum": [
                      "hook",
                      "headline",
                      "primary_text",
                      "objection"
                    ]
                  },
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "verbatim_ids": {
                    "description": "New line: quotes it was written from (meta_list_verbatims). Optional.",
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "status": {
                    "description": "Draft by default. `approved` makes it available to prefill launches.",
                    "type": "string",
                    "enum": [
                      "draft",
                      "approved"
                    ]
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "409": {
            "description": "A request with this Idempotency-Key is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/messaging/{messagingId}": {
      "patch": {
        "operationId": "updateMessagingLine",
        "summary": "Rewrite a copy line (it becomes a human line, keeping the quotes it cites).",
        "description": "The angle and kind cannot change — add a new line and reject the old one. `status` (draft or approved) may ride along.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_save_messaging`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_save_messaging",
        "parameters": [
          {
            "name": "messagingId",
            "in": "path",
            "required": true,
            "description": "The messagingId.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "angle_id": {
                    "description": "New line: the angle it argues.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "kind": {
                    "description": "New line: its kind.",
                    "type": "string",
                    "enum": [
                      "hook",
                      "headline",
                      "primary_text",
                      "objection"
                    ]
                  },
                  "text": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 2000
                  },
                  "verbatim_ids": {
                    "description": "New line: quotes it was written from (meta_list_verbatims). Optional.",
                    "maxItems": 10,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "status": {
                    "description": "Draft by default. `approved` makes it available to prefill launches.",
                    "type": "string",
                    "enum": [
                      "draft",
                      "approved"
                    ]
                  }
                },
                "required": [
                  "text"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such resource in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/messaging/status": {
      "post": {
        "operationId": "setMessagingStatus",
        "summary": "Approve, reject or return to draft one or several copy lines.",
        "description": "A rejected line keeps its row: drafting reads rejected lines and never writes the same one again.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_set_messaging_status`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_set_messaging_status",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "draft",
                      "approved",
                      "rejected"
                    ]
                  }
                },
                "required": [
                  "ids",
                  "status"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/research/messaging/delete": {
      "post": {
        "operationId": "deleteMessaging",
        "summary": "Permanently delete copy lines.",
        "description": "Irreversible, and drafting forgets a deleted line. To turn a line down for good, set its status to `rejected` instead.\n\nRequires a key with `write` scope or higher.\n\nMCP: `meta_delete_messaging`.",
        "tags": [
          "research"
        ],
        "x-mcp-tool": "meta_delete_messaging",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "minItems": 1,
                    "maxItems": 50,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid",
                      "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                    }
                  }
                },
                "required": [
                  "ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success. The body is the tool's own result — the same payload the MCP tool returns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "The query or body failed the tool's schema (`invalid_request`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid, revoked or expired API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "The key is below `write`. Scopes are ranked, so any tier at or above `write` is accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "This endpoint requires 'write' scope (launch PAUSED ads, run syncs, edit Values, tests and the swipe file) — this key has 'read' scope.",
                    "required_scope": "write",
                    "key_scope": "read",
                    "request_id": "req_8fK2mQ"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Well-formed, but refused — by the product's rules or by Meta. `message` says why.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. See `Retry-After` and `retry_after_ms`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
