{
  "openapi": "3.1.0",
  "info": {
    "title": "Simple Product Feeds API",
    "version": "1.0.0",
    "description": "API for managing Shopify product feeds, transformation rules, extracts, feed runs, and channel integrations. All requests require a Bearer token (`spf_live_sk_...` for merchant keys, `spf_admin_sk_...` for admin keys, `spf_org_sk_...` for organization keys).",
    "contact": {
      "name": "Simple Product Feeds",
      "url": "https://www.simpleproductfeeds.com"
    }
  },
  "servers": [
    {
      "url": "https://app.simpleproductfeeds.com/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Organization",
      "description": "Organization (agency) management — list connected client shops, members, and manage org API keys. Requires an organization API key (spf_org_sk_...)."
    },
    {
      "name": "Shop",
      "description": "Current shop information."
    },
    {
      "name": "Products",
      "description": "Source product data and merchant overrides."
    },
    {
      "name": "Extracts",
      "description": "Shop-level extractions of source product data from Shopify."
    },
    {
      "name": "Feeds",
      "description": "Output feeds (primary, language, market). Each feed is a configured transformation of the extracted source data."
    },
    {
      "name": "Feed Settings",
      "description": "Per-feed configuration: SEO, variant handling, ID format, inventory source, unpublished products."
    },
    {
      "name": "Extra Columns",
      "description": "Per-feed user-defined output columns."
    },
    {
      "name": "Column Mappings",
      "description": "Per-feed source-to-output column mappings."
    },
    {
      "name": "Rules",
      "description": "Per-feed transformation rules (set, exclude, modify, etc.)."
    },
    {
      "name": "Feed Runs",
      "description": "Per-feed transformation runs that produce the output feed file."
    },
    {
      "name": "Metafields",
      "description": "Shopify metafield references included in the source data."
    },
    {
      "name": "Channels",
      "description": "Channel integrations (Google, Meta, Microsoft, Pinterest, TikTok, Amazon)."
    },
    {
      "name": "Channel Datafeeds",
      "description": "Channel-specific datafeed registrations (Google Merchant Center datafeeds)."
    },
    {
      "name": "Webhooks",
      "description": "Outbound webhook subscriptions and delivery history."
    },
    {
      "name": "Plans",
      "description": "Available subscription plans."
    },
    {
      "name": "Subscription",
      "description": "Current subscription management."
    },
    {
      "name": "Admin",
      "description": "Admin-only endpoints. Requires `spf_admin_sk_...` key."
    },
    {
      "name": "Agents",
      "description": "The MCP endpoint for AI agents (Claude Code, Codex, Cursor). JSON-RPC over Streamable HTTP with API-key Bearer auth."
    }
  ],
  "paths": {
    "/org": {
      "get": {
        "operationId": "orgShow",
        "tags": [ "Organization" ],
        "summary": "Get the current organization",
        "description": "Returns the organization that owns the API key.\n\n**Required scope:** `read_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "responses": {
          "200": { "description": "The organization.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Organization" } }, "required": [ "data" ] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/org/invitations": {
      "post": {
        "operationId": "createOrgInvitation",
        "tags": [
          "Organization"
        ],
        "summary": "Invite a client shop to connect",
        "description": "Invites a merchant shop (by myshopify domain) to connect to your organization. The connection becomes live once the merchant approves it in their Team tab.\n\n**Required scope:** `write_org`",
        "security": [
          {
            "OrgBearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "shop_domain": {
                    "type": "string",
                    "description": "The shop's myshopify domain (e.g. `client-store.myshopify.com`)."
                  },
                  "client_label": {
                    "type": "string",
                    "description": "Optional label for this client in your roster."
                  }
                },
                "required": [
                  "shop_domain"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitation created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ClientShop"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/org/connections/{shop_id}": {
      "delete": {
        "operationId": "deleteOrgConnection",
        "tags": [
          "Organization"
        ],
        "summary": "Disconnect a client shop",
        "description": "Removes the connection between your organization and a client shop. This is currently a hard delete \u2014 the shop disappears from your roster and org keys immediately lose access to it.\n\n**Required scope:** `write_org`",
        "security": [
          {
            "OrgBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "The client shop's ID (as returned by `GET /org/shops`)."
          }
        ],
        "responses": {
          "204": {
            "description": "Connection removed."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/org/shops": {
      "get": {
        "operationId": "orgListShops",
        "tags": [ "Organization" ],
        "summary": "List connected client shops",
        "description": "Returns the client shops connected to the organization. Each `id` is the shop_id to pass to merchant data endpoints (e.g. `/feeds?shop_id=`).\n\n**Required scope:** `read_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "responses": {
          "200": { "description": "Connected client shops.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/ClientShop" } }, "meta": { "$ref": "#/components/schemas/PaginationMeta" } }, "required": [ "data" ] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/org/members": {
      "get": {
        "operationId": "orgListMembers",
        "tags": [ "Organization" ],
        "summary": "List organization members",
        "description": "Returns the people in the organization.\n\n**Required scope:** `read_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "responses": {
          "200": { "description": "Organization members.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/OrgMember" } }, "meta": { "$ref": "#/components/schemas/PaginationMeta" } }, "required": [ "data" ] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/org/keys": {
      "get": {
        "operationId": "orgListKeys",
        "tags": [ "Organization" ],
        "summary": "List organization API keys",
        "description": "Returns the organization's active API keys (metadata only — the secret is never returned).\n\n**Required scope:** `read_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "responses": {
          "200": { "description": "Organization keys.", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/OrgKey" } } }, "required": [ "data" ] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "operationId": "orgCreateKey",
        "tags": [ "Organization" ],
        "summary": "Create an organization API key",
        "description": "Creates a new organization API key. The raw key is returned **once** in the response.\n\n**Required scope:** `write_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "requestBody": { "required": false, "content": { "application/json": { "schema": { "type": "object", "properties": { "name": { "type": "string" }, "scopes": { "type": "array", "items": { "type": "string" } } } } } } },
        "responses": {
          "201": { "description": "The created key (includes raw_key, shown once).", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/OrgKey" } }, "required": [ "data" ] } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/org/keys/{kid}": {
      "delete": {
        "operationId": "orgRevokeKey",
        "tags": [ "Organization" ],
        "summary": "Revoke an organization API key",
        "description": "Revokes (deactivates) an organization API key.\n\n**Required scope:** `write_org`",
        "security": [ { "OrgBearerAuth": [] } ],
        "parameters": [ { "name": "kid", "in": "path", "required": true, "schema": { "type": "integer" } } ],
        "responses": {
          "204": { "description": "Revoked." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/shop": {
      "get": {
        "operationId": "getShop",
        "tags": [
          "Shop"
        ],
        "summary": "Get current shop",
        "description": "Returns the shop associated with the API key.\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Shop details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Shop"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products": {
      "get": {
        "operationId": "listProducts",
        "tags": [
          "Products"
        ],
        "summary": "List products",
        "description": "Returns a paginated list of products for the specified feed.\n\n**Required scope:** `read_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Required. Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Search across SKU, title, price, source data."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Column name to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "description": "Sort direction."
          },
          {
            "name": "excluded",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Filter by excluded status."
          },
          {
            "name": "condition",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "new",
                "refurbished",
                "used"
              ]
            },
            "description": "Filter by condition."
          },
          {
            "name": "has_overrides",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Filter to products with at least one override."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Product"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/{id}": {
      "get": {
        "operationId": "getProduct",
        "tags": [
          "Products"
        ],
        "summary": "Get a product",
        "description": "Returns a single product by ID.\n\n**Required scope:** `read_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed product ID (e.g., `prod_1234`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Product.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateProduct",
        "tags": [
          "Products"
        ],
        "summary": "Update a product",
        "description": "Updates merchant-controllable override fields on a product.\n\n**Required scope:** `write_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed product ID (e.g., `prod_1234`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Product override fields.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProductOverrideInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated product.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/{id}/restore": {
      "post": {
        "operationId": "restoreProduct",
        "tags": [
          "Products"
        ],
        "summary": "Restore a product",
        "description": "Clears all merchant overrides on a product, restoring source values.\n\n**Required scope:** `write_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed product ID (e.g., `prod_1234`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Restored product.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Product"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/batch": {
      "patch": {
        "operationId": "batchUpdateProducts",
        "tags": [
          "Products"
        ],
        "summary": "Batch update products",
        "description": "Updates up to 100 products in a single request. Each item may have its own validation errors; partial success is reported via the `errors` array.\n\n**Required scope:** `write_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Array of products to update (max 100).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "products": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/ProductOverrideInput"
                    }
                  }
                },
                "required": [
                  "products"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "updated": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/BatchItemError"
                          }
                        }
                      },
                      "required": [
                        "updated",
                        "errors"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/products/batch/restore": {
      "post": {
        "operationId": "batchRestoreProducts",
        "tags": [
          "Products"
        ],
        "summary": "Batch restore products",
        "description": "Clears overrides on up to 100 products in a single request.\n\n**Required scope:** `write_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Array of product IDs to restore (max 100).",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ids": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "restored": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "errors": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/BatchItemError"
                          }
                        }
                      },
                      "required": [
                        "restored",
                        "errors"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/extracts": {
      "get": {
        "operationId": "listExtracts",
        "tags": [
          "Extracts"
        ],
        "summary": "List extracts",
        "description": "Returns a paginated list of extracts for the shop, ordered newest first.\n\n**Required scope:** `read_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated extracts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Extract"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createExtract",
        "tags": [
          "Extracts"
        ],
        "summary": "Trigger an extract",
        "description": "Triggers a new extraction of source product data from Shopify. Use `type=full` for a full re-extract or `type=regenerate` to re-transform existing source data into a specific feed.\n\n**Required scope:** `write_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": false,
          "description": "Extract trigger options.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "type": {
                    "type": "string",
                    "enum": [
                      "full",
                      "regenerate"
                    ],
                    "default": "full"
                  },
                  "feed_id": {
                    "type": "string",
                    "description": "Required when type=regenerate. Prefixed feed ID."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted. Extract is queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Extract"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/extracts/{id}": {
      "get": {
        "operationId": "getExtract",
        "tags": [
          "Extracts"
        ],
        "summary": "Get an extract",
        "description": "Returns the status and details of a single extract.\n\n**Required scope:** `read_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed extract ID (e.g., `ext_568`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Extract.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Extract"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/extracts/latest": {
      "get": {
        "operationId": "getLatestExtract",
        "tags": [
          "Extracts"
        ],
        "summary": "Get the latest extract",
        "description": "Returns the most recent extract for the shop.\n\n**Required scope:** `read_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Latest extract.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Extract"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/extracts/{id}/download": {
      "get": {
        "operationId": "downloadExtract",
        "tags": [
          "Extracts"
        ],
        "summary": "Download extract source CSV",
        "description": "Returns a presigned URL to download the merged source CSV produced by this extract. URL expires in 5 minutes.\n\n**Required scope:** `read_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed extract ID (e.g., `ext_568`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DownloadUrl"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds": {
      "get": {
        "operationId": "listFeeds",
        "tags": [
          "Feeds"
        ],
        "summary": "List feeds",
        "description": "Returns all feeds (primary, language, market) configured for the shop.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Feeds list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Feed"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createFeed",
        "tags": [
          "Feeds"
        ],
        "summary": "Create a feed",
        "description": "Creates a market or language feed, inheriting column mapping, parsing, and per-feed settings from the primary feed. Requires a plan that allows additional feeds (Growth or Premium); free/Starter plans get 403 `plan_upgrade_required`.\n\n**Required scope:** `write_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedCreateInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Feed created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedDetail"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. missing label, malformed locale).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}": {
      "get": {
        "operationId": "getFeed",
        "tags": [
          "Feeds"
        ],
        "summary": "Get a feed",
        "description": "Returns generation status and details for a single feed.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Feed details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedDetail"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateFeed",
        "tags": [
          "Feeds"
        ],
        "summary": "Update a feed",
        "description": "Updates editable metadata on a non-primary feed: display_name, target_market, target_country. locale, product_selection_mode, and feed_type cannot be changed after creation; the primary feed cannot be edited.\n\n**Required scope:** `write_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedUpdateInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Feed updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedDetail"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}/regenerate": {
      "post": {
        "operationId": "regenerateFeed",
        "tags": [
          "Feeds"
        ],
        "summary": "Regenerate a feed",
        "description": "Re-runs the transform + publish pipeline for this feed from the already-extracted product snapshot and returns a pollable run. This does NOT re-pull products from Shopify \u2014 for a fresh extraction use `POST /v1/extracts` with `type: full`. Poll `GET /v1/feeds/{feed_id}/runs/{id}` until the run is `completed` or `failed`. Returns `409` with code `run_in_progress` if a run is already running for this feed \u2014 poll it instead of retrying.\n\n**Required scope:** `write_exports`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "202": {
            "description": "Regeneration accepted; a new run was created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedRun"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}/debug_rows": {
      "post": {
        "operationId": "debugFeedRows",
        "tags": [
          "Feeds"
        ],
        "summary": "Debug row transformations",
        "description": "Traces up to 5 source rows through the canonical transform pipeline and returns, per row: the merged source `input`, the transformed `output` (materialized even when the row is excluded), and the exclusion verdict (`excluded`, `exclude_reason`). Pass an optional `channel_slug` (e.g. `google_merchant_center`, `commission_junction`) to additionally include the channel-render view (`rendered.columns` + `rendered.values`) for non-excluded rows \u2014 exactly what the export for that channel would ship. `row_ids` are source variant IDs (the `source_data` `id` values returned by the products endpoints). Read-only: nothing is written.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Rows to debug.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "row_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 5,
                    "description": "Source variant IDs to trace (1\u20135)."
                  },
                  "channel_slug": {
                    "type": "string",
                    "description": "Optional channel slug (e.g. `google_merchant_center`). When given, non-excluded rows include the channel-render view. The channel must be connected to this feed."
                  }
                },
                "required": [
                  "row_ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row transform trace.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RowDebugResult"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (e.g. `row_ids` missing, not an array, or more than 5 ids).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}/scope": {
      "get": {
        "operationId": "getFeedScope",
        "tags": [
          "Feeds"
        ],
        "summary": "Get feed scope counts",
        "description": "Returns the variant include/exclude partition for a feed from its cached scope snapshot. `status` is `fresh` (counts current), `refreshing` (stale counts served while a refresh runs in the background), or `computing` (no snapshot yet — counts are null).\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Feed scope counts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedScope"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}/products/{product_id}/cells": {
      "patch": {
        "operationId": "updateProductCells",
        "tags": [
          "Feeds"
        ],
        "summary": "Set per-cell overrides on one product row",
        "description": "Writes individual cell overrides into the feed's cells_changes overlay — the same storage the in-app Source Data spreadsheet edits (applied pre-mapping, stage 1.25 of the transform pipeline). Merge semantics: only the named cells change; a null value clears that cell's override. Columns use the SOURCE vocabulary (the feed's columns_list); submitting a feed output column name returns a per-cell error naming the source column that feeds it. The response's propagates_to map shows which feed output columns each edited source column feeds. Pass preview: true to dry-run the row through the pipeline (before/after transformed output) without persisting. Merchant rules still take precedence over cell edits on conflict.\n\n**Required scope:** `write_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Feed ID (accepts `feed_` prefix)."
          },
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Product ID (`prod_` prefixed DB id) or a source row id."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Identical key replays the cached response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "cells"
                ],
                "properties": {
                  "cells": {
                    "type": "object",
                    "additionalProperties": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "description": "Source column -> value; null clears that cell's override."
                  },
                  "preview": {
                    "type": "boolean",
                    "description": "Dry-run without persisting; returns before/after transformed row."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-cell result: updated/cleared/errors, the row's current overlay, and the propagates_to source->output map (or the before/after preview when preview: true).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/UnprocessableEntity"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{id}/products": {
      "get": {
        "operationId": "listFeedProducts",
        "tags": [
          "Feeds"
        ],
        "summary": "List feed products",
        "description": "Returns a paginated list of transformed products as they appear in the output feed (rules applied, columns mapped). Each entry exposes the dynamic feed-column fields under `fields`.\n\n**Required scope:** `read_products`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Search across feed columns."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Column name to sort by."
          },
          {
            "name": "order",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "description": "Sort direction."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated feed products.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FeedProduct"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/settings": {
      "get": {
        "operationId": "getFeedSettings",
        "tags": [
          "Feed Settings"
        ],
        "summary": "Get feed settings",
        "description": "Returns the per-feed configuration: SEO, variants, inventory source, ID format, and unpublished-product handling.\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Feed settings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedSettings"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateFeedSettings",
        "tags": [
          "Feed Settings"
        ],
        "summary": "Update feed settings",
        "description": "Updates one or more feed settings. Omitted fields are unchanged.\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Feed settings to update.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FeedSettingsInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated feed settings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedSettings"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/extra_columns": {
      "get": {
        "operationId": "getExtraColumns",
        "tags": [
          "Extra Columns"
        ],
        "summary": "Get extra columns",
        "description": "Returns the user-defined extra output columns for a feed.\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Extra columns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExtraColumns"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateExtraColumns",
        "tags": [
          "Extra Columns"
        ],
        "summary": "Update extra columns",
        "description": "Replaces the extra columns list. Column names must match `[a-zA-Z][a-zA-Z0-9_]*`.\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Extra columns to set.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "extra_columns": {
                    "oneOf": [
                      {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      {
                        "type": "string",
                        "description": "Comma-separated list."
                      }
                    ]
                  }
                },
                "required": [
                  "extra_columns"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated extra columns.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ExtraColumns"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/margin_tiers": {
      "get": {
        "operationId": "getMarginTiers",
        "tags": [
          "Margin Tiers"
        ],
        "summary": "Get margin-tier configuration",
        "description": "Returns the feed's current margin-tier setup — the target custom_label slot and the tiers (each with a label and a band or category criterion) — plus cost-data coverage (how many products have cost, which gates the band path). Empty when not configured.\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Margin-tier configuration and cost coverage.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "patch": {
        "operationId": "updateMarginTiers",
        "tags": [
          "Margin Tiers"
        ],
        "summary": "Set margin tiers",
        "description": "Sets the feed's margin tiers, generating the tagged custom_label rules (idempotent — replaces any existing margin-tier rules, leaving your other rules untouched). Each tier has a `label` and a `criterion`: a margin `band` (`{type:'band', min, max}` over computed margin — needs cost data) or a `category` (`{type:'category', field, values}` over a source column like product_type — no cost needed).\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Identical key replays the cached response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "slot",
                  "tiers"
                ],
                "properties": {
                  "slot": {
                    "type": "string",
                    "description": "Target field: custom_label_0 .. custom_label_4."
                  },
                  "tiers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "label",
                        "criterion"
                      ],
                      "properties": {
                        "label": { "type": "string" },
                        "criterion": {
                          "type": "object",
                          "description": "{type:'band', min, max} or {type:'category', field, values}."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated margin-tier configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "operationId": "clearMarginTiers",
        "tags": [
          "Margin Tiers"
        ],
        "summary": "Clear margin tiers",
        "description": "Removes the feed's margin-tier rules (turns the feature off for the feed). Your other rules are untouched.\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Margin tiers cleared.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/column_mappings": {
      "get": {
        "operationId": "getColumnMappings",
        "tags": [
          "Column Mappings"
        ],
        "summary": "Get column mappings",
        "description": "Returns source-to-output column mappings for a feed, plus the available source and feed column lists.\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Column mappings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ColumnMappings"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateColumnMappings",
        "tags": [
          "Column Mappings"
        ],
        "summary": "Update column mappings",
        "description": "Replaces the source-to-output column mapping for a feed.\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Mappings to set.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "mappings": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "mappings"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated mappings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ColumnMappings"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/source_columns": {
      "get": {
        "operationId": "getFeedSourceColumns",
        "tags": [
          "Feeds"
        ],
        "summary": "List feed source columns",
        "description": "Returns the source-side column names available to this feed (the raw extracted columns rules and mappings can reference).\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Source column names.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source_columns": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "source_columns"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules": {
      "get": {
        "operationId": "listFeedRules",
        "tags": [
          "Rules"
        ],
        "summary": "List rules",
        "description": "Returns rules for a feed in `position` order.\n\n**Required scope:** `read_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "rule_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by rule type."
          }
        ],
        "responses": {
          "200": {
            "description": "Rules.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Rule"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Create a rule",
        "description": "Creates a new rule for the feed.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Rule definition.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rule": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "rule"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Rule"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules/{id}": {
      "get": {
        "operationId": "getFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Get a rule",
        "description": "Returns a single rule.\n\n**Required scope:** `read_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed rule ID (e.g., `rule_42`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Rule"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Update a rule",
        "description": "Updates a rule's definition.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed rule ID (e.g., `rule_42`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Rule fields to update.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rule": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "rule"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Rule"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Delete a rule",
        "description": "Permanently deletes a rule.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed rule ID (e.g., `rule_42`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules/{id}/activate": {
      "post": {
        "operationId": "activateFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Activate a rule",
        "description": "Sets the rule's `active` flag to true.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed rule ID (e.g., `rule_42`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Activated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Rule"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules/{id}/deactivate": {
      "post": {
        "operationId": "deactivateFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Deactivate a rule",
        "description": "Sets the rule's `active` flag to false.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed rule ID (e.g., `rule_42`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Deactivated rule.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Rule"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules/reorder": {
      "post": {
        "operationId": "reorderFeedRules",
        "tags": [
          "Rules"
        ],
        "summary": "Reorder rules",
        "description": "Reorders rules. Send rule IDs in the desired position order.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Ordered rule IDs.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rule_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "rule_type": {
                    "type": "string"
                  }
                },
                "required": [
                  "rule_ids"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rules in new order.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Rule"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/rules/preview": {
      "post": {
        "operationId": "previewFeedRule",
        "tags": [
          "Rules"
        ],
        "summary": "Preview a rule",
        "description": "Previews the effect of a rule against a sample of products without saving it.\n\n**Required scope:** `write_rules`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Rule to preview.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rule": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "rule"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Preview results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/RulePreviewResult"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/runs": {
      "get": {
        "operationId": "listFeedRuns",
        "tags": [
          "Feed Runs"
        ],
        "summary": "List feed runs",
        "description": "Returns a paginated list of runs for a feed (newest first).\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated runs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FeedRun"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/runs/{id}": {
      "get": {
        "operationId": "getFeedRun",
        "tags": [
          "Feed Runs"
        ],
        "summary": "Get a feed run",
        "description": "Returns a single feed run.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed run ID (e.g., `run_234`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedRun"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/runs/latest": {
      "get": {
        "operationId": "getLatestFeedRun",
        "tags": [
          "Feed Runs"
        ],
        "summary": "Get latest feed run",
        "description": "Returns the most recent completed run for a feed.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Latest run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/FeedRun"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/runs/latest/download": {
      "get": {
        "operationId": "downloadLatestFeedRun",
        "tags": [
          "Feed Runs"
        ],
        "summary": "Download latest feed run output",
        "description": "Returns a presigned URL to download the output feed file from the most recent run. URL expires in 5 minutes.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "feed_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Presigned download URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DownloadUrl"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels": {
      "get": {
        "operationId": "listChannels",
        "tags": [
          "Channels"
        ],
        "summary": "List channels",
        "description": "Returns all available channels and their connection status for the shop.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Channels.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Channel"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}": {
      "get": {
        "operationId": "getChannel",
        "tags": [
          "Channels"
        ],
        "summary": "Get a channel",
        "description": "Returns a single channel by slug.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Channel.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Channel"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateChannel",
        "tags": [
          "Channels"
        ],
        "summary": "Update a channel",
        "description": "Updates channel-level settings (sync mode, channel-specific configuration).\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Channel fields to update.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "sync_mode": {
                    "type": "string"
                  },
                  "settings": {
                    "type": "object",
                    "additionalProperties": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated channel.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Channel"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/connect": {
      "post": {
        "operationId": "connectChannel",
        "tags": [
          "Channels"
        ],
        "summary": "Connect a channel",
        "description": "Initiates the channel connection flow. For OAuth-based channels, returns an `oauth_url`.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Connection initiated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/disconnect": {
      "post": {
        "operationId": "disconnectChannel",
        "tags": [
          "Channels"
        ],
        "summary": "Disconnect a channel",
        "description": "Disconnects a channel and clears stored credentials.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Disconnected channel.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Channel"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/sync": {
      "post": {
        "operationId": "syncChannel",
        "tags": [
          "Channels"
        ],
        "summary": "Trigger channel sync",
        "description": "Triggers a sync of the current feed to the channel (for channels that support real-time sync, e.g., GMC API).\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "202": {
            "description": "Sync initiated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "message"
                      ]
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/sync_logs": {
      "get": {
        "operationId": "listChannelSyncLogs",
        "tags": [
          "Channels"
        ],
        "summary": "List channel sync logs",
        "description": "Returns recent sync log entries for a channel.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sync logs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "integer"
                          },
                          "status": {
                            "type": "string"
                          },
                          "started_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "completed_at": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "rows_synced": {
                            "type": "integer"
                          },
                          "error_details": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/merchant_accounts": {
      "get": {
        "operationId": "listChannelMerchantAccounts",
        "tags": [
          "Channels"
        ],
        "summary": "List channel merchant accounts",
        "description": "For multi-account channels (e.g., GMC), returns the available merchant accounts the connected user has access to.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "accounts": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              }
                            }
                          }
                        },
                        "current_merchant_id": {
                          "type": [
                            "string",
                            "null"
                          ]
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{slug}/select_merchant": {
      "post": {
        "operationId": "selectChannelMerchant",
        "tags": [
          "Channels"
        ],
        "summary": "Select channel merchant account",
        "description": "For multi-account channels (e.g., GMC), selects which merchant account to use for this shop.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Merchant ID to select.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "merchant_id": {
                    "type": "string"
                  }
                },
                "required": [
                  "merchant_id"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Merchant selected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "merchant_id": {
                          "type": "string"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds": {
      "get": {
        "operationId": "listChannelDatafeeds",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "List datafeeds",
        "description": "Returns datafeed registrations for a channel (e.g., Google Merchant Center datafeeds).\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Datafeeds.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Datafeed"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createChannelDatafeed",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Create a datafeed",
        "description": "Registers a new datafeed for a channel. Defaults `targets` to `[{country: 'US', language: 'en'}]` when omitted.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Datafeed configuration.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DatafeedInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created datafeed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Datafeed"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds/{id}": {
      "get": {
        "operationId": "getChannelDatafeed",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Get a datafeed",
        "description": "Returns a single datafeed registration.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "Datafeed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Datafeed"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateChannelDatafeed",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Update a datafeed",
        "description": "Updates a datafeed registration.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Fields to update.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DatafeedInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated datafeed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Datafeed"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteChannelDatafeed",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Delete a datafeed",
        "description": "Deletes a datafeed registration.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds/{id}/status": {
      "get": {
        "operationId": "getChannelDatafeedStatus",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Get datafeed status",
        "description": "Returns the channel-side processing status for a datafeed.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "Status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DatafeedStatus"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds/{id}/issues": {
      "get": {
        "operationId": "getChannelDatafeedIssues",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Get datafeed issues",
        "description": "Returns the channel-side data-quality issues for products in this datafeed.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "Issues.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DatafeedIssues"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds/{id}/fetch_now": {
      "post": {
        "operationId": "fetchChannelDatafeedNow",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Trigger immediate datafeed fetch",
        "description": "Asks the channel to fetch the datafeed immediately rather than waiting for the scheduled hour.\n\n**Required scope:** `write_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Datafeed ID (integer)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Fetch triggered.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/channels/{channel_slug}/datafeeds/options": {
      "get": {
        "operationId": "getChannelDatafeedOptions",
        "tags": [
          "Channel Datafeeds"
        ],
        "summary": "Get datafeed creation options",
        "description": "Returns the available choices for `hour`, `time_zone`, and `country` when creating a datafeed.\n\n**Required scope:** `read_channels`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "channel_slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Channel slug (e.g., `google`, `meta`, `microsoft`, `pinterest`, `tiktok`, `amazon`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Options.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/DatafeedOptions"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhooks",
        "description": "Returns all webhook subscriptions for the shop.\n\n**Required scope:** `read_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook",
        "description": "Creates a webhook subscription. The signing secret is returned **once** in the response \u2014 store it immediately.\n\n**Required scope:** `write_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Webhook configuration.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created webhook (includes raw secret).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks/{id}": {
      "get": {
        "operationId": "getWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Get a webhook",
        "description": "Returns a single webhook (without secret).\n\n**Required scope:** `read_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Update a webhook",
        "description": "Updates a webhook's URL, events, or status.\n\n**Required scope:** `write_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Fields to update.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated webhook.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook",
        "description": "Permanently deletes a webhook subscription.\n\n**Required scope:** `write_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks/{id}/test": {
      "post": {
        "operationId": "testWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test webhook",
        "description": "Queues a test delivery to the webhook's configured URL.\n\n**Required scope:** `write_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "202": {
            "description": "Test delivery queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/WebhookDelivery"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks/{id}/secret/rotate": {
      "post": {
        "operationId": "rotateWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate webhook secret",
        "description": "Generates a new signing secret. Returned **once** in the response \u2014 store it immediately.\n\n**Required scope:** `write_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook with new secret.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook deliveries",
        "description": "Returns a paginated list of past delivery attempts for a webhook.\n\n**Required scope:** `read_webhooks`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Prefixed webhook ID (e.g., `wh_8xk2`)."
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated deliveries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookDelivery"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/plans": {
      "get": {
        "operationId": "listPlans",
        "tags": [
          "Plans"
        ],
        "summary": "List plans",
        "description": "Returns all available subscription plans.\n\n**Required scope:** `read_subscription`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Plans.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Plan"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/subscription": {
      "get": {
        "operationId": "getSubscription",
        "tags": [
          "Subscription"
        ],
        "summary": "Get current subscription",
        "description": "Returns the shop's current subscription, if any.\n\n**Required scope:** `read_subscription`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Subscription"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createSubscription",
        "tags": [
          "Subscription"
        ],
        "summary": "Create a subscription",
        "description": "Initiates a new subscription. Returns a Shopify confirmation URL the merchant must visit to approve the charge.\n\n**Required scope:** `write_subscription`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Plan to subscribe to.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plan": {
                    "type": "string",
                    "description": "Plan code name (e.g., `growth`)."
                  },
                  "discount_code": {
                    "type": "string"
                  }
                },
                "required": [
                  "plan"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Subscription created (pending merchant approval).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "object": {
                          "type": "string",
                          "enum": [
                            "subscription"
                          ]
                        },
                        "confirmation_url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "delete": {
        "operationId": "cancelSubscription",
        "tags": [
          "Subscription"
        ],
        "summary": "Cancel subscription",
        "description": "Cancels the active subscription.\n\n**Required scope:** `write_subscription`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "object": {
                          "type": "string",
                          "enum": [
                            "subscription"
                          ]
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "cancelled"
                          ]
                        },
                        "message": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/findings": {
      "get": {
        "operationId": "listFindings",
        "tags": [
          "Findings"
        ],
        "summary": "List validation findings",
        "description": "Returns the channel's validation findings as a flat array of issue categories (each with an affected count and up to ~5 sample rows). The full row-level list is available via the findings export. Reading this also triggers (re)validation when the channel is unvalidated or its config changed (`meta.revalidating`); poll until `revalidating` is false. Channels without a validator return `meta.status: \"unsupported\"` and an empty array.\n\n**Required scope:** `read_feeds`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Prefixed feed ID (e.g., `feed_1`)." },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" }, "description": "Channel slug (e.g., `google`, `commission_junction`)." },
          { "name": "category", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Filter to a single finding category." }
        ],
        "responses": {
          "200": {
            "description": "Findings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } },
                    "meta": { "$ref": "#/components/schemas/FindingsMeta" }
                  },
                  "required": [ "data", "meta" ]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/findings/errors": {
      "get": {
        "operationId": "listFindingErrors",
        "tags": [ "Findings" ],
        "summary": "List error-severity findings",
        "description": "Same as listing findings, narrowed to `severity: error`.\n\n**Required scope:** `read_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "category", "in": "query", "required": false, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Error findings.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } }, "meta": { "$ref": "#/components/schemas/FindingsMeta" } }, "required": [ "data", "meta" ] } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/findings/warnings": {
      "get": {
        "operationId": "listFindingWarnings",
        "tags": [ "Findings" ],
        "summary": "List warning-severity findings",
        "description": "Same as listing findings, narrowed to `severity: warning`.\n\n**Required scope:** `read_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "category", "in": "query", "required": false, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Warning findings.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Finding" } }, "meta": { "$ref": "#/components/schemas/FindingsMeta" } }, "required": [ "data", "meta" ] } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/finding_mutes": {
      "post": {
        "operationId": "createFindingMute",
        "tags": [ "Findings" ],
        "summary": "Mute a finding",
        "description": "Suppresses a specific finding (category + field + row_id) from the active report. Idempotent on that triple. Expiry is `muted_until` (a timestamp; null = permanent); `duration` (e.g. `30d`, `permanent`) and `days` are convenience inputs that resolve to it.\n\n**Required scope:** `write_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FindingMuteInput" } } } },
        "responses": {
          "201": {
            "description": "Mute created.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/FindingMute" } }, "required": [ "data" ] } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/finding_mutes/{id}": {
      "delete": {
        "operationId": "deleteFindingMute",
        "tags": [ "Findings" ],
        "summary": "Remove a mute",
        "description": "Deletes a mute, un-suppressing its finding.\n\n**Required scope:** `write_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "204": { "description": "Mute removed." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/findings_exports": {
      "post": {
        "operationId": "createFindingsExport",
        "tags": [ "Findings" ],
        "summary": "Export findings to CSV",
        "description": "Triggers an async CSV export of the full row-level findings for a channel. Optional `categories` narrows the export; omitting it exports all. In-flight exports with the same filter are deduped. Poll the show endpoint until `status` is `ready`, then use `download_url`.\n\n**Required scope:** `write_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": false,
          "content": { "application/json": { "schema": { "type": "object", "properties": { "categories": { "type": "array", "items": { "type": "object", "properties": { "category": { "type": "string" }, "field": { "type": "string" } } } } } } } }
        },
        "responses": {
          "201": {
            "description": "Export queued.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/FindingsExport" } }, "required": [ "data" ] } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/ValidationError" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/feeds/{feed_id}/channels/{channel_slug}/findings_exports/{id}": {
      "get": {
        "operationId": "getFindingsExport",
        "tags": [ "Findings" ],
        "summary": "Get findings export status",
        "description": "Poll a findings export. `download_url` is present once `status` is `ready`.\n\n**Required scope:** `read_feeds`",
        "security": [ { "BearerAuth": [] } ],
        "parameters": [
          { "name": "feed_id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "channel_slug", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Export status.",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/FindingsExport" } }, "required": [ "data" ] } } }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/mcp": {
      "post": {
        "operationId": "mcpEndpoint",
        "tags": [
          "Agents"
        ],
        "summary": "MCP endpoint (JSON-RPC)",
        "description": "The Model Context Protocol endpoint for AI agents (Claude Code, Codex, Cursor, and any MCP client): a stateless Streamable HTTP server speaking JSON-RPC 2.0. Connect with your API key as a Bearer token; organization keys select the client shop via `?shop_id=` on the connection URL. Exposes read-only tools (`spf_list_feeds`, `spf_feed_health`, `spf_debug_row`). Each POST body is a single JSON-RPC request (no batching); notifications return `202`; `GET` returns `405` (no server-initiated streams). See the Connect an AI agent guide in the docs.\n\n**Required scope:** varies per tool (each tool enforces its own, e.g. `read_feeds`)",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "description": "A single JSON-RPC 2.0 request or notification.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "enum": [
                      "2.0"
                    ]
                  },
                  "id": {
                    "type": [
                      "string",
                      "integer",
                      "null"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "description": "e.g. `initialize`, `tools/list`, `tools/call`."
                  },
                  "params": {
                    "type": "object",
                    "additionalProperties": true
                  }
                },
                "required": [
                  "jsonrpc",
                  "method"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "202": {
            "description": "Notification accepted (empty body)."
          },
          "400": {
            "description": "Malformed JSON-RPC (e.g. batch arrays, unsupported protocol version).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/metafields": {
      "get": {
        "operationId": "getMetafields",
        "tags": [
          "Metafields"
        ],
        "summary": "Get metafields configuration",
        "description": "Returns the configured Shopify metafield references included in the source extraction. Shop-scoped (not per-feed).\n\n**Required scope:** `read_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Metafields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Metafields"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "patch": {
        "operationId": "updateMetafields",
        "tags": [
          "Metafields"
        ],
        "summary": "Update metafields configuration",
        "description": "Replaces the configured metafield references. Maximum 10 entries.\n\n**Required scope:** `write_settings`",
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Metafields to set.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetafieldInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated metafields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Metafields"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "summary": "Get this OpenAPI specification",
        "description": "Returns this OpenAPI 3.1 specification document. Unauthenticated.",
        "security": [],
        "responses": {
          "200": {
            "description": "OpenAPI specification.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/admin/keys": {
      "get": {
        "operationId": "adminListKeys",
        "tags": [
          "Admin"
        ],
        "summary": "List admin keys",
        "description": "Returns all active admin API keys.\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Admin keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminKey"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "adminCreateKey",
        "tags": [
          "Admin"
        ],
        "summary": "Create an admin key",
        "description": "Creates a new admin API key. The raw key is returned **once** in the response.\n\n**Required scope:** `write_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "Admin key configuration.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "default": "Admin key"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "default": [
                      "read_admin",
                      "write_admin"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created admin key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdminKey"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/keys/{kid}": {
      "delete": {
        "operationId": "adminDeleteKey",
        "tags": [
          "Admin"
        ],
        "summary": "Revoke an admin key",
        "description": "Revokes an admin API key. Irreversible.\n\n**Required scope:** `write_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Admin key prefix (kid)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops": {
      "get": {
        "operationId": "adminListShops",
        "tags": [
          "Admin"
        ],
        "summary": "List shops",
        "description": "Returns a paginated list of all shops.\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by Shopify domain (partial match)."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated shops.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AdminShop"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops/{id}": {
      "get": {
        "operationId": "adminGetShop",
        "tags": [
          "Admin"
        ],
        "summary": "Get a shop",
        "description": "Returns detailed information about a single shop.\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "Shop.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/AdminShop"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops/{shop_id}/api_keys": {
      "get": {
        "operationId": "adminListShopApiKeys",
        "tags": [
          "Admin"
        ],
        "summary": "List API keys for a shop",
        "description": "Returns all merchant API keys for a shop (excludes admin keys).\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "API keys.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiKey"
                      }
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "adminCreateShopApiKey",
        "tags": [
          "Admin"
        ],
        "summary": "Create an API key for a shop",
        "description": "Creates a new merchant API key for a shop. The raw key is returned **once** in the response.\n\n**Required scope:** `write_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "requestBody": {
          "required": true,
          "description": "API key configuration.",
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "default": "Admin-created key"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "default": [
                      "full_access"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created API key.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/ApiKey"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops/{shop_id}/api_keys/{kid}": {
      "delete": {
        "operationId": "adminDeleteShopApiKey",
        "tags": [
          "Admin"
        ],
        "summary": "Revoke a shop API key",
        "description": "Revokes a merchant API key with reason `admin_revoked`.\n\n**Required scope:** `write_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          },
          {
            "name": "kid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "API key prefix (kid)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked."
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops/{shop_id}/extracts": {
      "get": {
        "operationId": "adminListShopExtracts",
        "tags": [
          "Admin"
        ],
        "summary": "List extracts for a shop",
        "description": "Returns a paginated list of extracts for a shop.\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PerPage"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated extracts.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Extract"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "adminCreateShopExtract",
        "tags": [
          "Admin"
        ],
        "summary": "Trigger an extract for a shop",
        "description": "Triggers a full extract for the specified shop.\n\n**Required scope:** `write_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "maxLength": 64
            },
            "description": "Optional. Echoed in response. Identical key replays the cached response for 24h."
          }
        ],
        "responses": {
          "202": {
            "description": "Extract queued.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Extract"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/admin/shops/{shop_id}/extracts/latest": {
      "get": {
        "operationId": "adminGetLatestShopExtract",
        "tags": [
          "Admin"
        ],
        "summary": "Get latest extract for a shop",
        "description": "Returns the most recent extract for a shop.\n\n**Required scope:** `read_admin`",
        "security": [
          {
            "AdminBearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "shop_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Shop ID (integer)."
          }
        ],
        "responses": {
          "200": {
            "description": "Latest extract.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Extract"
                    }
                  },
                  "required": [
                    "data"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Merchant API key (spf_live_sk_...)"
      },
      "AdminBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Admin API key (spf_admin_sk_...)"
      },
      "OrgBearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Organization API key (spf_org_sk_...)"
      }
    },
    "parameters": {
      "Page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPage": {
        "name": "per_page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      }
    },
    "schemas": {
      "Organization": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "example": "organization" },
          "name": { "type": "string" },
          "slug": { "type": "string" },
          "plan": { "type": "string" },
          "shop_count": { "type": "integer" },
          "member_count": { "type": "integer" },
          "created_at": { "type": "string", "format": "date-time" },
          "updated_at": { "type": "string", "format": "date-time" }
        },
        "required": [ "id", "object", "name", "slug" ]
      },
      "ClientShop": {
        "type": "object",
        "description": "A client shop connected to the organization. `id` is the shop_id to pass to merchant data endpoints (e.g. /feeds?shop_id=).",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "example": "client_shop" },
          "domain": { "type": "string" },
          "name": { "type": "string", "nullable": true },
          "client_label": { "type": "string", "nullable": true },
          "connected_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        },
        "required": [ "id", "object", "domain" ]
      },
      "OrgMember": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "example": "org_member" },
          "user_id": { "type": "integer" },
          "email": { "type": "string" },
          "name": { "type": "string", "nullable": true },
          "role": { "type": "string", "enum": [ "owner", "admin", "member" ] },
          "status": { "type": "string", "enum": [ "active", "pending" ] },
          "accepted_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" }
        },
        "required": [ "id", "object", "email", "role", "status" ]
      },
      "OrgKey": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "example": "org_key" },
          "name": { "type": "string" },
          "key_prefix": { "type": "string" },
          "scopes": { "type": "array", "items": { "type": "string" } },
          "last_used_at": { "type": "string", "format": "date-time", "nullable": true },
          "request_count": { "type": "integer" },
          "revoked_at": { "type": "string", "format": "date-time", "nullable": true },
          "created_at": { "type": "string", "format": "date-time" },
          "raw_key": { "type": "string", "description": "Only present in the POST response — the secret, shown once." }
        },
        "required": [ "id", "object", "name", "key_prefix", "scopes" ]
      },
      "Shop": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "shop_1"
          },
          "object": {
            "type": "string",
            "const": "shop"
          },
          "domain": {
            "type": "string",
            "example": "my-store.myshopify.com"
          },
          "name": {
            "type": "string"
          },
          "subscription_plan": {
            "type": "string"
          },
          "subscription_status": {
            "type": "string",
            "enum": [
              "active",
              "none",
              "unknown"
            ]
          },
          "product_count": {
            "type": "integer"
          },
          "feed_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "last_sync_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "primary_locale": {
            "type": [
              "string",
              "null"
            ]
          },
          "languages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "onboarding_complete": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "prod_123"
          },
          "object": {
            "type": "string",
            "const": "product"
          },
          "shopify_product_id": {
            "type": "string"
          },
          "shopify_variant_id": {
            "type": "string"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "brand": {
            "type": [
              "string",
              "null"
            ]
          },
          "price": {
            "type": [
              "string",
              "null"
            ]
          },
          "compare_at_price": {
            "type": [
              "string",
              "null"
            ]
          },
          "inventory_quantity": {
            "type": [
              "integer",
              "null"
            ]
          },
          "image_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "vendor": {
            "type": [
              "string",
              "null"
            ]
          },
          "product_type": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string"
          },
          "gtin": {
            "type": [
              "string",
              "null"
            ]
          },
          "mpn": {
            "type": [
              "string",
              "null"
            ]
          },
          "condition": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "new",
              "refurbished",
              "used"
            ]
          },
          "excluded": {
            "type": "boolean"
          },
          "excluded_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "custom_labels": {
            "type": "object",
            "properties": {
              "custom_label_0": {
                "type": "string"
              },
              "custom_label_1": {
                "type": "string"
              },
              "custom_label_2": {
                "type": "string"
              },
              "custom_label_3": {
                "type": "string"
              },
              "custom_label_4": {
                "type": "string"
              }
            },
            "additionalProperties": false
          },
          "has_overrides": {
            "type": "boolean"
          },
          "extracted_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ProductOverrideInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "brand": {
            "type": "string"
          },
          "gtin": {
            "type": "string"
          },
          "mpn": {
            "type": "string"
          },
          "condition": {
            "type": "string",
            "enum": [
              "new",
              "refurbished",
              "used"
            ]
          },
          "excluded": {
            "type": "boolean"
          },
          "excluded_reason": {
            "type": "string"
          },
          "custom_labels": {
            "type": "object",
            "properties": {
              "custom_label_0": {
                "type": "string"
              },
              "custom_label_1": {
                "type": "string"
              },
              "custom_label_2": {
                "type": "string"
              },
              "custom_label_3": {
                "type": "string"
              },
              "custom_label_4": {
                "type": "string"
              }
            },
            "additionalProperties": false
          }
        }
      },
      "BatchItemError": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "error": {
            "type": "string"
          }
        }
      },
      "Feed": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "feed_1",
            "description": "Prefixed feed ID."
          },
          "object": {
            "type": "string",
            "enum": [
              "feed"
            ]
          },
          "feed_type": {
            "type": "string",
            "enum": [
              "primary",
              "language",
              "market"
            ],
            "description": "Feed type discriminator. `primary` is the default feed; `language` is locale-scoped; `market` is country/market-scoped."
          },
          "locale": {
            "type": [
              "string",
              "null"
            ],
            "example": "fr",
            "description": "Locale code for language feeds. Null for primary and market feeds."
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ],
            "example": "French",
            "description": "User-facing feed label."
          },
          "feed_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri",
            "description": "Public URL of the generated feed file."
          },
          "product_count": {
            "type": "integer",
            "description": "Count of products in the most recent run."
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO8601 timestamp of last successful feed run."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "feed_type"
        ]
      },
      "FeedProduct": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "feed_product"
            ]
          },
          "excluded": {
            "type": "boolean"
          },
          "excluded_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "fields": {
            "type": "object",
            "additionalProperties": true,
            "description": "Dynamic fields representing the transformed product row. Keys depend on the feed's column configuration."
          }
        },
        "required": [
          "object",
          "excluded",
          "fields"
        ]
      },
      "FeedSettings": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "feed_settings"
            ]
          },
          "feed_id": {
            "type": [
              "string",
              "null"
            ],
            "example": "feed_1"
          },
          "seo": {
            "type": "boolean"
          },
          "variants": {
            "type": "boolean"
          },
          "use_shopify_quantity": {
            "type": "boolean"
          },
          "import_unpublish_product": {
            "type": "boolean"
          },
          "id_format": {
            "type": "string",
            "enum": [
              "global",
              "shopify"
            ]
          }
        },
        "required": [
          "object",
          "seo",
          "use_shopify_quantity",
          "import_unpublish_product",
          "id_format"
        ]
      },
      "FeedSettingsInput": {
        "type": "object",
        "properties": {
          "seo": {
            "type": "boolean"
          },
          "variants": {
            "type": "boolean"
          },
          "use_shopify_quantity": {
            "type": "boolean"
          },
          "import_unpublish_product": {
            "type": "boolean"
          },
          "id_format": {
            "type": "string",
            "enum": [
              "global",
              "shopify"
            ]
          }
        },
        "additionalProperties": false
      },
      "ExtraColumns": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "extra_columns"
            ]
          },
          "feed_id": {
            "type": [
              "string",
              "null"
            ],
            "example": "feed_1"
          },
          "extra_columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "object",
          "extra_columns"
        ]
      },
      "Metafields": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "metafields"
          },
          "pull_metafields": {
            "type": "boolean"
          },
          "metafields": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer"
                },
                "namespace": {
                  "type": "string"
                },
                "key": {
                  "type": "string"
                }
              }
            }
          },
          "max_metafields": {
            "type": "integer"
          }
        }
      },
      "MetafieldInput": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Include to update existing; omit to create new"
          },
          "namespace": {
            "type": "string"
          },
          "key": {
            "type": "string"
          }
        },
        "required": [
          "namespace",
          "key"
        ]
      },
      "ColumnMappings": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "enum": [
              "column_mappings"
            ]
          },
          "source_columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "feed_columns": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "mappings": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Map of source column name \u2192 target feed column name."
          }
        },
        "required": [
          "object",
          "source_columns",
          "feed_columns",
          "mappings"
        ]
      },
      "Rule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "rule_123"
          },
          "object": {
            "type": "string",
            "const": "rule"
          },
          "rule_type": {
            "type": "string"
          },
          "rule": {
            "type": "object",
            "description": "Raw rule definition"
          },
          "target_column": {
            "type": [
              "string",
              "null"
            ]
          },
          "condition": {
            "type": [
              "string",
              "null"
            ]
          },
          "value": {
            "type": [
              "string",
              "null"
            ]
          },
          "active": {
            "type": "boolean"
          },
          "position": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RulePreviewResult": {
        "type": "object",
        "properties": {
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "product_title": {
                  "type": "string"
                },
                "excluded": {
                  "type": "boolean"
                },
                "changes": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "field": {
                        "type": "string"
                      },
                      "before": {
                        "type": "string"
                      },
                      "after": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "required": [
          "results"
        ]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "wh_123"
          },
          "object": {
            "type": "string",
            "const": "webhook"
          },
          "endpoint_url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "extract.started",
                "extract.progress",
                "extract.completed",
                "extract.failed",
                "feed.created",
                "feed.updated",
                "product.updated",
                "products.imported",
                "rules.changed",
                "api_key.created",
                "api_key.revoked",
                "findings.updated",
                "finding_mute.created",
                "finding_mute.removed",
                "subscription.changed"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          },
          "failure_count": {
            "type": "integer"
          },
          "last_delivery_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "disabled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "disabled_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookInput": {
        "type": "object",
        "properties": {
          "endpoint_url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "extract.started",
                "extract.progress",
                "extract.completed",
                "extract.failed",
                "feed.created",
                "feed.updated",
                "product.updated",
                "products.imported",
                "rules.changed",
                "api_key.created",
                "api_key.revoked",
                "findings.updated",
                "finding_mute.created",
                "finding_mute.removed",
                "subscription.changed"
              ]
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "disabled"
            ]
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "whd_123"
          },
          "object": {
            "type": "string",
            "const": "webhook_delivery"
          },
          "event": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "delivered",
              "failed"
            ]
          },
          "attempt_count": {
            "type": "integer"
          },
          "response_status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "response_time_ms": {
            "type": [
              "integer",
              "null"
            ]
          },
          "error_message": {
            "type": [
              "string",
              "null"
            ]
          },
          "delivered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "next_retry_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Channel": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "example": "google"
          },
          "object": {
            "type": "string",
            "const": "channel"
          },
          "type": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "available": {
            "type": "boolean"
          },
          "status": {
            "type": "string",
            "enum": [
              "connected",
              "disconnected",
              "error"
            ]
          },
          "sync_mode": {
            "type": [
              "string",
              "null"
            ]
          },
          "connected_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_synced_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Plan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "const": "plan"
          },
          "name": {
            "type": "string"
          },
          "code_name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "price": {
            "type": "number"
          },
          "skus_min": {
            "type": "integer"
          },
          "skus_max": {
            "type": [
              "integer",
              "null"
            ]
          },
          "daily_export_count": {
            "type": "integer"
          },
          "recommended": {
            "type": "boolean"
          },
          "is_free": {
            "type": "boolean"
          }
        }
      },
      "Subscription": {
        "type": "object",
        "properties": {
          "object": {
            "type": "string",
            "const": "subscription"
          },
          "plan": {
            "type": "string"
          },
          "plan_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "legacy",
              "none"
            ]
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "AdminShop": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "const": "shop"
          },
          "shopify_domain": {
            "type": "string"
          },
          "shopify_shop_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "shopify_shop_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "shopify_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "shopify_plan_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "onboarding_step": {
            "type": [
              "string",
              "null"
            ]
          },
          "gmcfeed_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "product_count": {
            "type": "integer"
          },
          "api_key_count": {
            "type": "integer"
          },
          "last_export_triggered_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdminKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "const": "admin_key"
          },
          "name": {
            "type": "string"
          },
          "key_prefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "request_count": {
            "type": "integer"
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ApiKey": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "const": "api_key"
          },
          "name": {
            "type": "string"
          },
          "key_prefix": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "last_used_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "request_count": {
            "type": "integer"
          },
          "revoked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "per_page": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "description": "Error category (e.g. authentication_error, validation_error, not_found)"
              },
              "message": {
                "type": "string"
              },
              "code": {
                "type": "string",
                "description": "Machine-readable error code"
              },
              "request_id": {
                "type": "string"
              },
              "param": {
                "type": "string",
                "description": "The parameter that caused the error (when applicable)"
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "Detailed validation errors (when applicable)"
              }
            },
            "required": [
              "type",
              "message",
              "code",
              "request_id"
            ]
          }
        }
      },
      "FeedDetail": {
        "type": "object",
        "description": "Detail view of a feed (GET /v1/feeds/:id). A superset of the feed summary returned by GET /v1/feeds, with the feed-scoped run status and configuration fields. All run/status fields are scoped to this specific feed, not the shop.",
        "properties": {
          "id": {
            "type": "string",
            "example": "feed_42"
          },
          "object": {
            "type": "string",
            "enum": [
              "feed"
            ]
          },
          "feed_type": {
            "type": "string",
            "enum": [
              "primary",
              "language",
              "market"
            ]
          },
          "locale": {
            "type": [
              "string",
              "null"
            ]
          },
          "display_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "description": "Feed-scoped run status derived from this feed's runs.",
            "enum": [
              "generating",
              "fresh",
              "never_generated"
            ]
          },
          "product_count": {
            "type": "integer"
          },
          "scope_count": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total variant count from the feed's scope snapshot; null if not yet computed."
          },
          "target_market": {
            "type": [
              "string",
              "null"
            ]
          },
          "product_selection_mode": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "all",
              "collection",
              "manual",
              null
            ]
          },
          "feed_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "last_run_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "last_run_id": {
            "type": [
              "string",
              "null"
            ],
            "example": "run_567"
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "status"
        ]
      },
      "FeedCreateInput": {
        "type": "object",
        "properties": {
          "feed_type": {
            "type": "string",
            "enum": [
              "market",
              "language"
            ],
            "description": "Only market and language feeds can be created via the API; the primary feed is created at onboarding."
          },
          "display_name": {
            "type": "string",
            "description": "Human label for the feed; also produces the feed slug."
          },
          "target_market": {
            "type": "string",
            "description": "Market code, e.g. `GB` (uppercased)."
          },
          "target_country": {
            "type": "string"
          },
          "locale": {
            "type": "string",
            "description": "Language code for a language feed, e.g. `fr`. Requires translation scopes."
          },
          "product_selection_mode": {
            "type": "string",
            "enum": [
              "all",
              "collection",
              "manual"
            ],
            "default": "all"
          },
          "selected_collection_id": {
            "type": "string"
          },
          "selected_collection_title": {
            "type": "string",
            "description": "Required when product_selection_mode is `collection`; must match a real collection in the store."
          }
        },
        "required": [
          "feed_type",
          "display_name"
        ]
      },
      "FeedUpdateInput": {
        "type": "object",
        "description": "Editable feed metadata. locale, product_selection_mode, and feed_type are create-only and not accepted here.",
        "properties": {
          "display_name": {
            "type": "string"
          },
          "target_market": {
            "type": "string"
          },
          "target_country": {
            "type": "string"
          }
        }
      },
      "RowDebugResult": {
        "type": "object",
        "description": "Result of a row-debug request: per-row transform trace, optionally with the channel-render view.",
        "properties": {
          "feed_id": {
            "type": "string",
            "description": "Prefixed feed ID (e.g., `feed_1`)."
          },
          "channel_slug": {
            "type": "string",
            "description": "Present when the request included a channel_slug."
          },
          "rows": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "row_id": {
                  "type": "string",
                  "description": "Source variant ID."
                },
                "input": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Merged source row (raw source columns + merchant overrides) fed into the pipeline."
                },
                "output": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Transformed feed row. Materialized even when `excluded` is true, so the would-be output is visible."
                },
                "excluded": {
                  "type": "boolean",
                  "description": "Whether the pipeline excluded this row from the feed."
                },
                "exclude_reason": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Why the row was excluded (null when included)."
                },
                "rendered": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "description": "Channel-render view. Only present when `channel_slug` was given; null for excluded rows (production never renders an excluded row).",
                  "properties": {
                    "renderer": {
                      "type": "string",
                      "description": "Renderer that produced the values (e.g. `GoogleShopping`, `CjStandard`)."
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The channel's ordered output columns."
                    },
                    "values": {
                      "type": "object",
                      "additionalProperties": true,
                      "description": "Rendered values keyed by column name \u2014 the values the export would ship."
                    }
                  }
                }
              },
              "required": [
                "row_id",
                "input",
                "output",
                "excluded"
              ]
            }
          }
        },
        "required": [
          "feed_id",
          "rows"
        ]
      },
      "FeedScope": {
        "type": "object",
        "properties": {
          "feed_id": {
            "type": "string",
            "example": "feed_42"
          },
          "status": {
            "type": "string",
            "enum": [
              "fresh",
              "refreshing",
              "computing"
            ]
          },
          "included_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "excluded_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "total_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "computed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "feed_id",
          "status"
        ]
      },
      "Finding": {
        "type": "object",
        "description": "One validation issue category for a feed+channel: an issue type with an affected count and up to ~5 sample rows.",
        "properties": {
          "object": { "type": "string", "enum": [ "finding" ] },
          "category": { "type": "string" },
          "severity": { "type": "string", "enum": [ "error", "warning" ] },
          "field": { "type": [ "string", "null" ] },
          "affected_count": { "type": "integer" },
          "samples": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "row_id": { "type": [ "string", "null" ] },
                "message": { "type": [ "string", "null" ] },
                "field_value": { "type": [ "string", "null" ] },
                "shopify_admin_url": { "type": [ "string", "null" ] }
              }
            }
          }
        },
        "required": [ "object", "category", "severity" ]
      },
      "FindingsMeta": {
        "type": "object",
        "description": "Pagination + validation summary for a findings list.",
        "properties": {
          "page": { "type": "integer" },
          "per_page": { "type": "integer" },
          "total": { "type": "integer" },
          "total_pages": { "type": "integer" },
          "has_more": { "type": "boolean" },
          "status": { "type": "string", "enum": [ "clean", "errors", "warnings", "unvalidated", "unsupported" ] },
          "errors_count": { "type": "integer" },
          "warnings_count": { "type": "integer" },
          "validated_at": { "type": [ "string", "null" ], "format": "date-time" },
          "revalidating": { "type": "boolean", "description": "True when a (re)validation was triggered; poll until false for fresh findings." }
        }
      },
      "FindingMute": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "enum": [ "finding_mute" ] },
          "category": { "type": "string" },
          "field": { "type": "string" },
          "row_id": { "type": [ "string", "null" ] },
          "muted_until": { "type": [ "string", "null" ], "format": "date-time", "description": "Absolute expiry (UTC); null = permanent." },
          "created_at": { "type": [ "string", "null" ], "format": "date-time" }
        },
        "required": [ "id", "object", "category" ]
      },
      "FindingMuteInput": {
        "type": "object",
        "description": "Expiry precedence: muted_until > duration > days; default is permanent.",
        "properties": {
          "category": { "type": "string" },
          "field": { "type": "string" },
          "row_id": { "type": "string" },
          "muted_until": { "type": "string", "format": "date-time", "description": "Absolute expiry (ISO-8601)." },
          "duration": { "type": "string", "description": "Relative expiry, e.g. `30d`, `90d`, or `permanent`." },
          "days": { "type": "integer", "description": "Relative expiry in days." }
        },
        "required": [ "category" ]
      },
      "FindingsExport": {
        "type": "object",
        "properties": {
          "id": { "type": "integer" },
          "object": { "type": "string", "enum": [ "findings_export" ] },
          "status": { "type": "string", "enum": [ "pending", "processing", "ready", "failed" ] },
          "row_count": { "type": [ "integer", "null" ] },
          "download_url": { "type": [ "string", "null" ], "description": "Presigned CSV URL; present when status is ready." },
          "error": { "type": [ "string", "null" ] }
        },
        "required": [ "id", "object", "status" ]
      },
      "Extract": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "ext_568"
          },
          "object": {
            "type": "string",
            "enum": [
              "extract"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed",
              "cancelled"
            ]
          },
          "progress": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "product_count": {
            "type": "integer"
          },
          "excluded_count": {
            "type": "integer"
          },
          "started_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "failed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "error_details": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_source_csv": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "status",
          "progress",
          "has_source_csv",
          "created_at"
        ]
      },
      "FeedRun": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "run_234"
          },
          "object": {
            "type": "string",
            "enum": [
              "run"
            ]
          },
          "feed_id": {
            "type": "string",
            "example": "feed_1"
          },
          "status": {
            "type": "string",
            "enum": [
              "running",
              "completed",
              "failed"
            ]
          },
          "has_output": {
            "type": "boolean"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "feed_id",
          "status",
          "has_output",
          "created_at"
        ]
      },
      "Datafeed": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "object": {
            "type": "string",
            "enum": [
              "datafeed"
            ]
          },
          "datafeed_id": {
            "type": "string",
            "description": "Channel-side ID (e.g., Google datafeed ID)."
          },
          "datafeed_name": {
            "type": "string"
          },
          "hour": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23
          },
          "time_zone": {
            "type": "string",
            "example": "America/New_York"
          },
          "fetch_url": {
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "country": {
                  "type": "string",
                  "example": "US"
                },
                "language": {
                  "type": "string",
                  "example": "en"
                }
              },
              "required": [
                "country",
                "language"
              ]
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "object",
          "datafeed_id",
          "datafeed_name",
          "hour",
          "time_zone",
          "targets"
        ]
      },
      "DatafeedInput": {
        "type": "object",
        "properties": {
          "datafeed_name": {
            "type": "string"
          },
          "hour": {
            "type": "integer",
            "minimum": 0,
            "maximum": 23
          },
          "time_zone": {
            "type": "string"
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "country": {
                  "type": "string"
                },
                "language": {
                  "type": "string"
                }
              },
              "required": [
                "country",
                "language"
              ]
            }
          }
        },
        "required": [
          "datafeed_name",
          "hour",
          "time_zone"
        ]
      },
      "DatafeedStatus": {
        "type": "object",
        "properties": {
          "datafeed_id": {
            "type": "string"
          },
          "processing_status": {
            "type": "string"
          },
          "items_total": {
            "type": "integer"
          },
          "items_valid": {
            "type": "integer"
          },
          "last_upload_date": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "datafeed_id",
          "processing_status"
        ]
      },
      "DatafeedIssues": {
        "type": "object",
        "properties": {
          "total_products": {
            "type": "integer"
          },
          "products_with_issues": {
            "type": "integer"
          },
          "issues": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          }
        },
        "required": [
          "total_products",
          "products_with_issues",
          "issues"
        ]
      },
      "DatafeedOptions": {
        "type": "object",
        "properties": {
          "hours": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "integer"
                }
              }
            }
          },
          "time_zones": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          }
        },
        "required": [
          "hours",
          "time_zones",
          "countries"
        ]
      },
      "DownloadUrl": {
        "type": "object",
        "properties": {
          "download_url": {
            "type": "string",
            "format": "uri",
            "description": "Presigned S3 URL. Expires in `expires_in` seconds."
          },
          "filename": {
            "type": "string"
          },
          "expires_in": {
            "type": "integer",
            "example": 300
          }
        },
        "required": [
          "download_url",
          "filename",
          "expires_in"
        ]
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Authentication required or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "X-Request-Id": {
            "schema": {
              "type": "string"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient scope or wrong key type",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflict (e.g. export already in progress)",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        },
        "headers": {
          "X-RateLimit-Limit": {
            "schema": {
              "type": "integer"
            },
            "description": "Requests allowed per minute"
          },
          "X-RateLimit-Remaining": {
            "schema": {
              "type": "integer"
            },
            "description": "Requests remaining in window"
          },
          "X-RateLimit-Reset": {
            "schema": {
              "type": "integer"
            },
            "description": "Unix timestamp when window resets"
          }
        }
      }
    },
    "headers": {
      "X-RateLimit-Limit": {
        "description": "Max requests per minute (120 merchant, 60 admin, 20 unauthenticated)",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Remaining": {
        "description": "Requests remaining in current window",
        "schema": {
          "type": "integer"
        }
      },
      "X-RateLimit-Reset": {
        "description": "Unix timestamp when the rate limit window resets",
        "schema": {
          "type": "integer"
        }
      },
      "X-Request-Id": {
        "description": "Unique request identifier for debugging",
        "schema": {
          "type": "string"
        }
      }
    }
  }
}
