{
  "openapi": "3.1.0",
  "info": {
    "title": "Build My Digital API",
    "version": "1.0.0",
    "summary": "Free website scan for UK local businesses, usable by people and agents.",
    "description": "One public, keyless endpoint: scan any public website and get a 0 to 100 score across SEO, AI search (GEO), local signals, trust, conversion and speed, with the checks and the fixes in priority order. Versioning: stable paths live under /api/v1/; a breaking change would open /api/v2/ and the old path would keep working for at least six months with a Deprecation header. Errors are RFC 9457 problem details (application/problem+json) that also carry a plain `error` line. Rate limits: 5 scans per address per 10 minutes and 300 a day, announced in RateLimit-Policy and RateLimit headers, with Retry-After on 429. No authentication, no key, no sandbox needed: every call is a real scan of a public site. The same scan is an MCP tool at https://buildmydigital.co.uk/mcp/. Sandbox: url=sandbox returns a fixed sample report outside the allowance. POST accepts an Idempotency-Key header; a retry with the same key within ten minutes returns the same answer. Batch: POST /api/v1/scan/batch/ with up to three urls.",
    "contact": {
      "name": "Build My Digital",
      "email": "hello@buildmydigital.co.uk",
      "url": "https://buildmydigital.co.uk/developers/"
    },
    "license": {
      "name": "Free to use, no key",
      "url": "https://buildmydigital.co.uk/terms/"
    },
    "x-deprecation-policy": "Stable paths live under /api/v1/. A breaking change opens /api/v2/; the old path keeps working for at least six months and answers with Deprecation and Sunset headers (RFC 9745 and RFC 8594) pointing at the replacement and the removal date. Policy: https://buildmydigital.co.uk/developers/#deprecation"
  },
  "servers": [
    {
      "url": "https://buildmydigital.co.uk"
    }
  ],
  "paths": {
    "/api/": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "Index of the API, its docs and the MCP endpoint",
        "responses": {
          "200": {
            "description": "Index",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            },
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scan/": {
      "get": {
        "operationId": "scanWebsiteGet",
        "summary": "Scan a website",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "yourbusiness.co.uk",
            "description": "The website address. The literal value sandbox returns a fixed sample report outside the allowance."
          },
          {
            "$ref": "#/components/parameters/Prefer"
          }
        ],
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Site unreachable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many scans",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "Scan failed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "202": {
            "description": "Accepted as a job (Prefer: respond-async). Poll the Location until status is done or failed.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "Preference-Applied": {
                "$ref": "#/components/headers/Preference-Applied"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "scanWebsite",
        "summary": "Scan a website",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "yourbusiness.co.uk"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/Idempotency-Key"
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Site unreachable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many scans",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "Scan failed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "202": {
            "description": "Accepted as a job (Prefer: respond-async). Poll the Location until status is done or failed.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "Preference-Applied": {
                "$ref": "#/components/headers/Preference-Applied"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/Prefer"
          }
        ]
      }
    },
    "/api/scan/": {
      "get": {
        "operationId": "scanWebsiteGetAlias",
        "summary": "Scan a website",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "yourbusiness.co.uk"
          },
          {
            "$ref": "#/components/parameters/Prefer"
          }
        ],
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Site unreachable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many scans",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "Scan failed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "202": {
            "description": "Accepted as a job (Prefer: respond-async). Poll the Location until status is done or failed.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "Preference-Applied": {
                "$ref": "#/components/headers/Preference-Applied"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        },
        "description": "Unversioned alias of /api/v1/scan/ kept for existing callers. If it is ever superseded it will answer with Deprecation and Sunset headers for at least six months first."
      },
      "post": {
        "operationId": "scanWebsiteAlias",
        "summary": "Scan a website",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "example": "yourbusiness.co.uk"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                }
              }
            },
            "headers": {
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              },
              "Idempotency-Key": {
                "$ref": "#/components/headers/Idempotency-Key"
              },
              "Deprecation": {
                "$ref": "#/components/headers/Deprecation"
              },
              "Sunset": {
                "$ref": "#/components/headers/Sunset"
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Site unreachable",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Too many scans",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "502": {
            "description": "Scan failed",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "202": {
            "description": "Accepted as a job (Prefer: respond-async). Poll the Location until status is done or failed.",
            "headers": {
              "Location": {
                "$ref": "#/components/headers/Location"
              },
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              },
              "Preference-Applied": {
                "$ref": "#/components/headers/Preference-Applied"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimit-Policy"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          },
          {
            "$ref": "#/components/parameters/Prefer"
          }
        ],
        "description": "Unversioned alias of /api/v1/scan/ kept for existing callers. If it is ever superseded it will answer with Deprecation and Sunset headers for at least six months first."
      },
      "description": "Unversioned alias of /api/v1/scan/ kept for existing callers."
    },
    "/api/v1/scan/batch/": {
      "post": {
        "operationId": "scanWebsitesBatch",
        "summary": "Scan up to three websites in one request",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "urls"
                ],
                "properties": {
                  "urls": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 3,
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One result per url, in order; a refused or failed site is reported in place",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "ok": {
                            "type": "boolean"
                          },
                          "id": {
                            "type": "string",
                            "nullable": true
                          },
                          "report": {
                            "$ref": "#/components/schemas/Report"
                          },
                          "error": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp/": {
      "post": {
        "operationId": "mcpProduct",
        "summary": "MCP server (Streamable HTTP): scan_website, list_services, get_page",
        "description": "Model Context Protocol endpoint, not a REST resource. Server card at /.well-known/mcp/server-card.json.",
        "responses": {
          "200": {
            "description": "JSON-RPC response or SSE stream"
          },
          "default": {
            "description": "Error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services/": {
      "get": {
        "operationId": "listServices",
        "summary": "List Build My Digital's services with published prices (cursor-paginated)",
        "description": "The same list the MCP tool list_services returns: every service Build My Digital runs for UK local businesses, the published price and the page that explains it. Cursor pagination: follow next_cursor until it is null. No key, no scan allowance used.",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 80
            },
            "description": "Words to filter by, for example reviews, ads or website"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            },
            "description": "Items per page"
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "The next_cursor from the previous page"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of services",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServicePage"
                }
              }
            }
          },
          "400": {
            "description": "Bad cursor or limit",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Any other error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/jobs/{id}/": {
      "get": {
        "operationId": "getScanJob",
        "summary": "Read a scan job or any earlier scan by id",
        "description": "The async job pattern: a scan requested with Prefer: respond-async is a job here. pending answers carry Retry-After; done answers carry the report; failed answers carry the error. The id a synchronous scan returns can be read from the same place.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The job",
            "headers": {
              "Retry-After": {
                "$ref": "#/components/headers/Retry-After"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Job"
                }
              }
            }
          },
          "400": {
            "description": "Not a job id",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "404": {
            "description": "No job or scan with that id",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "default": {
            "description": "Any other error",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Error": {
        "description": "RFC 9457 problem details",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problem"
            }
          }
        }
      }
    },
    "schemas": {
      "Check": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "cat": {
            "type": "string"
          },
          "cat_label": {
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "weight": {
            "type": "integer"
          },
          "hint": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "Report": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "final_url": {
            "type": "string"
          },
          "total": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "categories": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          },
          "category_labels": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "lighthouse": {
            "type": "object",
            "nullable": true,
            "additionalProperties": {
              "type": "integer"
            }
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Check"
            }
          },
          "priorities": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "hint": {
                  "type": "string",
                  "nullable": true
                },
                "cat": {
                  "type": "string"
                }
              }
            }
          },
          "scanned_at": {
            "type": "string",
            "format": "date-time"
          },
          "agent": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/AgentReport"
              },
              {
                "type": "null"
              }
            ],
            "description": "The separate agent-readiness dial. Absent or null only when the page could not be analysed."
          }
        }
      },
      "ScanResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "nullable": true
          },
          "report": {
            "$ref": "#/components/schemas/Report"
          }
        }
      },
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details, plus the plain `error` line older callers read.",
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "error"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "stage": {
            "type": "string"
          }
        }
      },
      "Service": {
        "type": "object",
        "required": [
          "name",
          "price",
          "summary",
          "url"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "price": {
            "type": "string",
            "description": "The published price as shown on the page, empty when the page does not carry one"
          },
          "summary": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ServicePage": {
        "type": "object",
        "required": [
          "items",
          "next_cursor",
          "total"
        ],
        "description": "One page of a cursor-paginated list. Pass next_cursor back as ?cursor= until it is null.",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Service"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque cursor for the next page, null on the last page"
          },
          "total": {
            "type": "integer",
            "description": "Matching services across all pages"
          }
        }
      },
      "Job": {
        "type": "object",
        "required": [
          "id",
          "status",
          "url",
          "status_url"
        ],
        "description": "A scan job. pending: poll status_url again after Retry-After seconds. done: the report is in `report`. failed: the reason is in `error`.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "done",
              "failed"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The site being scanned"
          },
          "status_url": {
            "type": "string",
            "format": "uri",
            "description": "Where to poll: GET /api/v1/jobs/{id}/"
          },
          "report": {
            "$ref": "#/components/schemas/Report"
          },
          "error": {
            "type": "string",
            "description": "Why the scan failed (status failed only)"
          },
          "stage": {
            "type": "string",
            "description": "Where it failed: auth, scan or score"
          }
        }
      },
      "AgentCheck": {
        "type": "object",
        "required": [
          "id",
          "label",
          "layer",
          "ok",
          "weight"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "layer": {
            "type": "string",
            "enum": [
              "discovery",
              "access",
              "usability"
            ]
          },
          "ok": {
            "type": "boolean"
          },
          "weight": {
            "type": "integer"
          },
          "hint": {
            "type": [
              "string",
              "null"
            ],
            "description": "The fix, present when the check fails"
          },
          "na": {
            "type": "boolean",
            "description": "true when the check does not apply to this site (no API, no MCP server, no form) and was left out of the score"
          }
        }
      },
      "AgentReport": {
        "type": "object",
        "description": "The agent-readiness dial: can an AI agent find, read and act on the site. Scored 0 to 100 over the checks that apply; it never changes the report's total.",
        "required": [
          "score",
          "layers",
          "checks",
          "priorities",
          "surfaces",
          "not_applicable",
          "ora"
        ],
        "properties": {
          "score": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100
          },
          "layers": {
            "type": "object",
            "description": "discovery, access and usability, each with its own 0 to 100 (null when nothing in the layer applied)",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "score": {
                  "type": [
                    "integer",
                    "null"
                  ]
                },
                "pts": {
                  "type": "integer"
                },
                "max": {
                  "type": "integer"
                }
              }
            }
          },
          "checks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AgentCheck"
            }
          },
          "priorities": {
            "type": "array",
            "description": "Failing applicable checks, heaviest first",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string"
                },
                "hint": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "layer": {
                  "type": "string"
                }
              }
            }
          },
          "surfaces": {
            "type": "object",
            "properties": {
              "api": {
                "type": "boolean"
              },
              "mcp": {
                "type": "boolean"
              },
              "markdown": {
                "type": "boolean"
              }
            }
          },
          "not_applicable": {
            "type": "integer"
          },
          "ora": {
            "type": [
              "object",
              "null"
            ],
            "description": "Ora's (ora.ai) cached agent-readiness score for the domain when it has one, with a link to their report. Their scan, their checks.",
            "properties": {
              "score": {
                "type": "integer"
              },
              "grade": {
                "type": "string"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "scanned_at": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      }
    },
    "headers": {
      "RateLimit": {
        "description": "IETF RateLimit field: limit, remaining, reset (seconds)",
        "schema": {
          "type": "string"
        }
      },
      "RateLimit-Policy": {
        "description": "IETF RateLimit-Policy field",
        "schema": {
          "type": "string"
        }
      },
      "Deprecation": {
        "description": "RFC 9745. Present on a path that has been superseded; the value is the date the deprecation took effect.",
        "schema": {
          "type": "string"
        }
      },
      "Sunset": {
        "description": "RFC 8594. Present on a superseded path; the date the path stops answering, at least six months after Deprecation.",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "Idempotency-Key": {
        "description": "Echoed when the request carried one.",
        "schema": {
          "type": "string"
        }
      },
      "Location": {
        "description": "The job's status URL (202 answers only)",
        "schema": {
          "type": "string"
        }
      },
      "Retry-After": {
        "description": "Seconds to wait before polling again (pending jobs) or before the next scan (429)",
        "schema": {
          "type": "integer"
        }
      },
      "Preference-Applied": {
        "description": "respond-async, when the scan was accepted as a job",
        "schema": {
          "type": "string"
        }
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "maxLength": 128
        },
        "description": "Any unique string. A retried POST with the same key within ten minutes returns the same response instead of running a second scan."
      },
      "Prefer": {
        "name": "Prefer",
        "in": "header",
        "required": false,
        "schema": {
          "type": "string",
          "enum": [
            "respond-async"
          ]
        },
        "description": "RFC 7240. respond-async: answer 202 at once with a job id and Location to poll, instead of holding the connection for the scan (up to a minute). Ignored, and the scan runs inline, if a job cannot be created."
      }
    }
  },
  "externalDocs": {
    "description": "Developer page: errors, limits, versioning and the deprecation and sunset policy",
    "url": "https://buildmydigital.co.uk/developers/#deprecation"
  }
}
