{
  "openapi": "3.1.0",
  "info": {
    "title": "Agent Friendly public benchmark API",
    "version": "1.0.0",
    "description": "Public HTML analysis; not proof of checkout readiness. Jobs expire after six hours following completion or a server restart. Saved runs retain the last 120 per site."
  },
  "servers": [
    {
      "url": "/"
    }
  ],
  "paths": {
    "/api/analyze": {
      "post": {
        "summary": "Analyze and save to the confirmed user; reuses current measured results for six hours, refresh uses a one-minute cooldown.",
        "security": [
          {
            "Session": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048
                  },
                  "refresh": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cached result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "202": {
            "description": "Queued or running job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Sign-in or key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds 4096 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying; this beta limits benchmark requests to 12 per hour per socket IP.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/benchmarks": {
      "post": {
        "summary": "CLI benchmark; five-minute same-site cooldown. Does not save to a user dashboard.",
        "security": [
          {
            "Session": []
          },
          {
            "BenchmarkKey": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "maxLength": 2048
                  },
                  "refresh": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cached result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "202": {
            "description": "Queued or running job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Sign-in or key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds 4096 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying; this beta limits benchmark requests to 12 per hour per socket IP.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/discover": {
      "post": {
        "summary": "Public domain discovery. Returns cached indexed results; refresh requests may enqueue another check after one minute. Does not save to a dashboard.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "maxLength": 2048
                  },
                  "refresh": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cached result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "202": {
            "description": "Queued or running job",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Invalid input",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Sign-in or key required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Body exceeds 4096 characters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "headers": {
              "Retry-After": {
                "description": "Seconds before retrying; this beta limits benchmark requests to 12 per hour per socket IP.",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "503": {
            "description": "Service unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/jobs/{id}": {
      "get": {
        "summary": "Poll job state",
        "security": [],
        "responses": {
          "200": {
            "description": "Public result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/runs/{id}": {
      "get": {
        "summary": "Read a saved immutable run",
        "security": [],
        "responses": {
          "200": {
            "description": "Public result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Run"
                }
              }
            }
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/sites/{domain}": {
      "get": {
        "summary": "Read site summary, latest and history",
        "security": [],
        "responses": {
          "200": {
            "description": "Public result"
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/api/sites": {
      "get": {
        "summary": "List site summaries, including unscored records",
        "security": [],
        "responses": {
          "200": {
            "description": "Public result"
          },
          "404": {
            "description": "Resource missing or expired",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/agent-offers/simulate": {
      "post": {
        "summary": "Simulate a non-binding price negotiation. No tax calculation, checkout or payment.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "/agent-offers.schema.json"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sandbox offer; purchase_allowed is always false."
          },
          "400": {
            "description": "Invalid pricing or currency."
          },
          "429": {
            "description": "Rate limit; retry later."
          }
        }
      }
    },
    "/api/smb/observations/validate": {
      "post": {
        "summary": "Check report format and detail before submitting. No storage, AI assessment, payment or authentication.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "agent_name",
                  "task",
                  "problem",
                  "page_url",
                  "observed",
                  "expected",
                  "steps",
                  "price_context",
                  "observed_at"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "agent_name": {
                    "type": "string"
                  },
                  "task": {
                    "type": "string"
                  },
                  "problem": {
                    "type": "string"
                  },
                  "page_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "observed": {
                    "type": "string"
                  },
                  "expected": {
                    "type": "string"
                  },
                  "steps": {
                    "type": "string"
                  },
                  "price_context": {
                    "type": "string"
                  },
                  "observed_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "followup_consent": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid fields with completeness checks; saved and submitted are false. Does not establish truth or business eligibility."
          },
          "400": {
            "description": "Malformed report, stale observation or mismatched source domain."
          },
          "429": {
            "description": "Rate limit; retry later."
          }
        }
      }
    },
    "/api/smb/fix": {
      "post": {
        "summary": "Record a business-reported fix; sharing is explicit, not confirmation.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "fingerprint",
                  "summary",
                  "publish"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "fingerprint": {
                    "type": "string"
                  },
                  "summary": {
                    "type": "string",
                    "minLength": 20,
                    "maxLength": 600
                  },
                  "publish": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated private observation; no verified purchase."
          },
          "400": {
            "description": "Invalid evidence."
          },
          "401": {
            "description": "Authentication required."
          },
          "403": {
            "description": "Actor is not authorized."
          },
          "409": {
            "description": "Follow-ups disabled or fix reference is stale."
          }
        }
      }
    },
    "/api/smb/retest": {
      "post": {
        "summary": "Original reporting agent records the outcome of retesting the latest fix.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "fingerprint",
                  "fix_reported_at",
                  "result",
                  "observed",
                  "steps"
                ],
                "properties": {
                  "domain": {
                    "type": "string"
                  },
                  "fingerprint": {
                    "type": "string"
                  },
                  "fix_reported_at": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "result": {
                    "type": "string",
                    "enum": [
                      "fixed",
                      "still_blocked"
                    ]
                  },
                  "observed": {
                    "type": "string",
                    "minLength": 20
                  },
                  "steps": {
                    "type": "string",
                    "minLength": 30
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated private observation; no verified purchase."
          },
          "400": {
            "description": "Invalid evidence."
          },
          "401": {
            "description": "Authentication required."
          },
          "403": {
            "description": "Actor is not authorized."
          },
          "409": {
            "description": "Follow-ups disabled or fix reference is stale."
          }
        }
      }
    },
    "/api/smb/fixes": {
      "get": {
        "summary": "Opt-in community fixes. Excludes private report text and replies.",
        "security": [],
        "responses": {
          "200": {
            "description": "Public updates; purchases_measured is false."
          }
        }
      }
    },
    "/api/smb/agent-inbox": {
      "get": {
        "summary": "Submitting operator reads up to 100 indexed reports and current fix/retest requests.",
        "responses": {
          "200": {
            "description": "Private reports belonging to the authenticated operator only; payouts disabled."
          },
          "401": {
            "description": "Operator session or agent key required."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "Session": {
        "type": "http",
        "scheme": "bearer",
        "description": "Confirmed Supabase user access token; never a service-role secret."
      },
      "BenchmarkKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Private deployment benchmark key; only for /api/benchmarks."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error",
          "code",
          "request_id"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          }
        }
      },
      "Job": {
        "type": "object",
        "required": [
          "domain",
          "status"
        ],
        "properties": {
          "domain": {
            "type": "string"
          },
          "status": {
            "enum": [
              "queued",
              "running",
              "cached",
              "complete",
              "failed"
            ]
          },
          "id": {
            "type": "string"
          },
          "run_id": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "saved": {
            "type": "boolean"
          }
        }
      },
      "Run": {
        "type": "object",
        "required": [
          "id",
          "domain",
          "version",
          "profile",
          "status",
          "score",
          "coverage",
          "recommendations",
          "evidence"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "profile": {
            "type": "string"
          },
          "status": {
            "enum": [
              "measured",
              "limited",
              "unavailable"
            ]
          },
          "score": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0,
            "maximum": 100
          },
          "coverage": {
            "type": "object"
          },
          "recommendations": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "evidence": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "limitations": {
            "type": "string"
          }
        }
      }
    }
  }
}
