{
  "openapi": "3.0.3",
  "info": {
    "title": "SiteProof API",
    "version": "1.0.0",
    "description": "WCAG accessibility scanning, AI Engine Optimization (AEO), and EAA compliance checking for websites. Authenticate with an API key via the `x-api-key` header.",
    "contact": {
      "name": "Deveras",
      "url": "https://deveras.no"
    }
  },
  "servers": [
    {
      "url": "https://api.deveras.no"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "API key in format sp_live_xxx or sp_test_xxx"
      }
    }
  },
  "paths": {
    "/v1/scan": {
      "post": {
        "summary": "Run WCAG + UX accessibility scan",
        "description": "Scans a URL for WCAG 2.1 accessibility issues and UX problems. Returns score, grade, issues with fix suggestions, and recommendations.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "https://example.com",
                    "description": "URL to scan"
                  },
                  "depth": {
                    "type": "string",
                    "enum": [
                      "quick",
                      "deep"
                    ],
                    "default": "quick",
                    "description": "quick = regex (~2s), deep = browser + axe-core (~15s, Pro only)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan results with score, grade, issues, and recommendations"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "Deep scans require Pro tier"
          },
          "429": {
            "description": "Daily quota exceeded or IP rate limited"
          }
        }
      }
    },
    "/v1/recipe": {
      "post": {
        "summary": "Get structured fix recipe (Pro only)",
        "description": "Returns a prioritized, machine-readable fix plan for accessibility issues. Provide either a URL to scan, or bring your own axe-core violations JSON (BYOV) to skip the scan. Auto-detects the site framework (React, Vue, Next.js, Angular, Svelte, etc.) and returns framework-specific before/after code. You can also specify a framework explicitly. Designed for AI agents and automated remediation tools.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "https://example.com",
                    "description": "URL to scan. Required if violations is not provided."
                  },
                  "violations": {
                    "type": "array",
                    "description": "Bring your own axe-core violations JSON instead of scanning. Pass the violations array from axe.run() results. Required if url is not provided.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "impact",
                        "nodes"
                      ],
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "image-alt",
                          "description": "axe-core rule ID"
                        },
                        "impact": {
                          "type": "string",
                          "enum": [
                            "critical",
                            "serious",
                            "moderate",
                            "minor"
                          ]
                        },
                        "description": {
                          "type": "string"
                        },
                        "help": {
                          "type": "string"
                        },
                        "helpUrl": {
                          "type": "string"
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "nodes": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Affected DOM elements from axe-core"
                        }
                      }
                    }
                  },
                  "issues": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Optional: filter to specific rule IDs (e.g., [\"image-alt\", \"color-contrast\"])"
                  },
                  "framework": {
                    "type": "string",
                    "example": "react",
                    "enum": [
                      "react",
                      "nextjs",
                      "vue",
                      "nuxt",
                      "angular",
                      "svelte",
                      "wordpress",
                      "shopify"
                    ],
                    "description": "Optional: override auto-detected framework. Auto-detection uses platform heuristics (headers, HTML markers)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Structured fix recipe with prioritized steps, code transforms, and validation criteria"
          },
          "400": {
            "description": "Missing input — provide either url or violations"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "Fix recipes require Pro tier"
          },
          "429": {
            "description": "Daily quota exceeded or rate limited"
          }
        }
      }
    },
    "/v1/aeo": {
      "post": {
        "summary": "AI Engine Optimization scan",
        "description": "Scans a URL for AI-readiness across 5 categories: Structured Data, Content Structure, Technical SEO, Authority, and Citation Readiness. Each category scores 0-20 for a total of 0-100. Useful for optimizing content to be cited by AI search engines (ChatGPT, Perplexity, Google AI Overviews, etc.).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "https://example.com",
                    "description": "URL to scan for AI-readiness"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AEO scan results with score breakdown across 5 categories, individual checks, and recommendations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string"
                        },
                        "domain": {
                          "type": "string"
                        },
                        "score": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "integer",
                              "example": 72,
                              "description": "Overall AEO score (0-100)"
                            },
                            "categories": {
                              "type": "object",
                              "properties": {
                                "structuredData": {
                                  "type": "integer",
                                  "example": 15,
                                  "description": "Structured data score (0-20)"
                                },
                                "contentStructure": {
                                  "type": "integer",
                                  "example": 18,
                                  "description": "Content structure score (0-20)"
                                },
                                "technical": {
                                  "type": "integer",
                                  "example": 14,
                                  "description": "Technical SEO score (0-20)"
                                },
                                "authority": {
                                  "type": "integer",
                                  "example": 12,
                                  "description": "Authority signals score (0-20)"
                                },
                                "citationReadiness": {
                                  "type": "integer",
                                  "example": 13,
                                  "description": "Citation readiness score (0-20)"
                                }
                              }
                            }
                          }
                        },
                        "grade": {
                          "type": "string",
                          "example": "B"
                        },
                        "checks": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Individual check results"
                        },
                        "recommendations": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Actionable improvement suggestions"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "429": {
            "description": "Daily quota exceeded or IP rate limited"
          }
        }
      }
    },
    "/v1/agentproof": {
      "post": {
        "summary": "AI agent config security scan",
        "description": "Scans an OpenClaw AI agent configuration for security vulnerabilities across 4 categories: Secrets Management, Access Control, Sandbox Isolation, and Network Security. Each category scores 0-25 for a total of 0-100. Useful for auditing AI agent deployments before production.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "config"
                ],
                "properties": {
                  "config": {
                    "type": "object",
                    "description": "OpenClaw AI agent configuration object to scan for vulnerabilities",
                    "example": {
                      "name": "my-agent",
                      "tools": [
                        {
                          "type": "web_search"
                        }
                      ],
                      "permissions": {
                        "network": true
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AgentProof scan results with score breakdown across 4 categories, individual checks, and recommendations",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "score": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "integer",
                              "example": 68,
                              "description": "Overall security score (0-100)"
                            },
                            "categories": {
                              "type": "object",
                              "properties": {
                                "secrets": {
                                  "type": "integer",
                                  "example": 20,
                                  "description": "Secrets management score (0-25)"
                                },
                                "access": {
                                  "type": "integer",
                                  "example": 15,
                                  "description": "Access control score (0-25)"
                                },
                                "sandbox": {
                                  "type": "integer",
                                  "example": 18,
                                  "description": "Sandbox isolation score (0-25)"
                                },
                                "network": {
                                  "type": "integer",
                                  "example": 15,
                                  "description": "Network security score (0-25)"
                                }
                              }
                            }
                          }
                        },
                        "grade": {
                          "type": "string",
                          "example": "C"
                        },
                        "summary": {
                          "type": "string",
                          "description": "Human-readable summary of findings"
                        },
                        "checks": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Individual check results (18 checks)"
                        },
                        "recommendations": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          },
                          "description": "Actionable security improvement suggestions"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "429": {
            "description": "Daily quota exceeded or IP rate limited"
          }
        }
      }
    },
    "/v1/compliance": {
      "post": {
        "summary": "EAA compliance estimate (Pro only)",
        "description": "Checks a website against the European Accessibility Act (EAA) / EN 301 549 requirements based on WCAG 2.1 AA automated checks.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "https://example.com"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Compliance status with EAA score and failing criteria by POUR principle"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "Compliance reports require Pro tier"
          }
        }
      }
    },
    "/v1/scan/{id}": {
      "get": {
        "summary": "Retrieve a saved scan",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved scan data"
          },
          "404": {
            "description": "Scan not found"
          }
        }
      }
    },
    "/v1/keys": {
      "post": {
        "summary": "Generate a new API key",
        "description": "Creates a new API key. Requires a Supabase JWT (Bearer token from the dashboard), not an API key. The raw key is shown once and cannot be retrieved again.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "default": "Unnamed key",
                    "description": "Label for this key"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "live",
                      "test"
                    ],
                    "default": "live"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "API key created — save the key immediately, it cannot be retrieved again"
          },
          "401": {
            "description": "Invalid or missing Bearer token"
          }
        }
      }
    },
    "/v1/edge-fixes": {
      "post": {
        "summary": "Create/update domain edge-fix config (Pro)",
        "description": "Registers a domain for automatic accessibility fixes via the Edge Fixer proxy. Requires a Pro API key.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain",
                  "originUrl",
                  "enabledRules"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "example.com",
                    "description": "Hostname to proxy (no protocol)"
                  },
                  "originUrl": {
                    "type": "string",
                    "example": "https://example.com",
                    "description": "Origin URL to fetch content from"
                  },
                  "enabledRules": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "image-alt",
                        "html-has-lang",
                        "document-title",
                        "meta-viewport",
                        "bypass",
                        "no-autoplay-audio",
                        "marquee-blink",
                        "focus-visible",
                        "tabindex",
                        "landmark-regions"
                      ]
                    },
                    "description": "Accessibility fix rules to apply"
                  },
                  "lang": {
                    "type": "string",
                    "example": "nb",
                    "description": "Default lang attribute value"
                  },
                  "showBadge": {
                    "type": "boolean",
                    "default": true,
                    "description": "Show AccessFix badge on site"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain config created"
          },
          "400": {
            "description": "Invalid domain, URL, or rules"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "Edge Fixer requires Pro tier"
          }
        }
      },
      "get": {
        "summary": "List managed domains (Pro)",
        "description": "Returns all domains configured for edge fixing by the authenticated user.",
        "responses": {
          "200": {
            "description": "Array of domain configs"
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "403": {
            "description": "Edge Fixer requires Pro tier"
          }
        }
      },
      "patch": {
        "summary": "Partial update domain config (Pro)",
        "description": "Updates specific fields of an existing domain config without replacing the entire object.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "example.com",
                    "description": "Domain to update"
                  },
                  "enabledRules": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Updated rule list"
                  },
                  "lang": {
                    "type": "string",
                    "description": "Updated lang attribute"
                  },
                  "showBadge": {
                    "type": "boolean",
                    "description": "Updated badge visibility"
                  },
                  "active": {
                    "type": "boolean",
                    "description": "Enable or disable fixing"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated domain config"
          },
          "400": {
            "description": "Invalid input"
          },
          "403": {
            "description": "Pro tier required or not domain owner"
          },
          "404": {
            "description": "Domain config not found"
          }
        }
      },
      "delete": {
        "summary": "Remove domain (Pro)",
        "description": "Deletes a domain config and all associated stats. This action is irreversible.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "domain"
                ],
                "properties": {
                  "domain": {
                    "type": "string",
                    "example": "example.com",
                    "description": "Domain to remove"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain deleted"
          },
          "403": {
            "description": "Pro tier required or not domain owner"
          },
          "404": {
            "description": "Domain config not found"
          }
        }
      }
    },
    "/v1/edge-fixes/stats": {
      "get": {
        "summary": "Domain fix statistics (Pro)",
        "description": "Returns daily and aggregate fix counts per accessibility rule for a managed domain.",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Domain to get stats for"
          },
          {
            "name": "days",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 7,
              "maximum": 90
            },
            "description": "Number of days to include (max 90)"
          }
        ],
        "responses": {
          "200": {
            "description": "Daily and total fix counts"
          },
          "400": {
            "description": "Missing domain parameter"
          },
          "403": {
            "description": "Pro tier required or not domain owner"
          },
          "404": {
            "description": "Domain config not found"
          }
        }
      }
    }
  }
}