{
  "openapi": "3.0.3",
  "info": {
    "title": "NessGate API",
    "version": "1.0.0",
    "description": "The verified data resolver for AI: a DNS-like lookup that resolves a verified domain to its official, self-published, machine-readable JSON URL. Read endpoints are public, unauthenticated, and CORS-open. The v1 response contract is stable: new optional fields may be added, existing fields will not change meaning; clients must ignore unknown fields.",
    "contact": { "email": "contact@nessgate.com", "url": "https://nessgate.com/contact" },
    "termsOfService": "https://nessgate.com/terms"
  },
  "servers": [{ "url": "https://nessgate.com" }],
  "paths": {
    "/resolve/{domain}": {
      "get": {
        "operationId": "resolveDomain",
        "summary": "Resolve a domain to its verified official JSON URL",
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "Domain name, e.g. example.com. Scheme, path, port, and a leading www. are ignored; ASCII/punycode form required.",
            "schema": { "type": "string", "example": "example.com" }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain is registered and verified.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Resolution" } } }
          },
          "404": {
            "description": "Domain is not registered. Body has verified=false and json_url=null.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Resolution" } } }
          },
          "400": { "description": "Input is not a valid domain.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "503": { "description": "Registry temporarily unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/version": {
      "get": {
        "operationId": "getVersion",
        "summary": "Deployed build identifier",
        "responses": {
          "200": {
            "description": "The git commit deployed to production.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "build": { "type": "string", "example": "c65632e" },
                    "spec": { "type": "string", "example": "v1" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/registry.json": {
      "get": {
        "operationId": "getRegistry",
        "summary": "Full public registry",
        "responses": {
          "200": {
            "description": "Array of all verified mappings.",
            "content": {
              "application/json": {
                "schema": { "type": "array", "items": { "$ref": "#/components/schemas/RegistryEntry" } }
              }
            }
          },
          "503": { "description": "Registry temporarily unavailable.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/register": {
      "post": {
        "operationId": "requestChallenge",
        "summary": "Request a domain-ownership verification challenge",
        "description": "Returns a one-time challenge code (expires in 3600 s). Prove control of the domain by placing the code in any one of the returned locations, then call /api/verify. Rate limited per IP.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "action": { "type": "string", "enum": ["register", "delete"], "default": "register" },
                  "domain": { "type": "string", "example": "example.com" },
                  "json_url": {
                    "type": "string",
                    "description": "Required for register. HTTPS URL on the domain or one of its subdomains.",
                    "example": "https://example.com/data/ai-info.json"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Challenge issued.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Challenge" } } } },
          "400": { "description": "Invalid domain or JSON URL.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "404": { "description": "Delete requested for a domain that is not registered.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/api/verify": {
      "post": {
        "operationId": "verifyChallenge",
        "summary": "Verify domain ownership and apply the registration, update, or removal",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": { "token": { "type": "string", "description": "The token returned by /api/register." } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ownership proven; registry updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" },
                    "action": { "type": "string", "enum": ["register", "delete"] },
                    "domain": { "type": "string" },
                    "json_url": { "type": "string", "nullable": true }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid, expired, or already-used token.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "422": { "description": "Ownership proof not found, or the JSON URL check failed. The message explains what to fix.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limit exceeded.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "502": { "description": "Registry write failed; retry shortly.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Resolution": {
        "type": "object",
        "properties": {
          "domain": { "type": "string", "example": "example.com" },
          "json_url": { "type": "string", "nullable": true, "example": "https://example.com/data/ai-info.json" },
          "verified": { "type": "boolean" },
          "verified_at": { "type": "string", "description": "Date (YYYY-MM-DD) ownership was last proven. Present when verified is true. Verifications are valid for 365 days.", "example": "2026-09-08" }
        },
        "required": ["domain", "json_url", "verified"]
      },
      "RegistryEntry": {
        "type": "object",
        "properties": {
          "domain": { "type": "string" },
          "json_url": { "type": "string" },
          "verified_at": { "type": "string", "example": "2026-09-08" }
        },
        "required": ["domain", "json_url"]
      },
      "Challenge": {
        "type": "object",
        "properties": {
          "token": { "type": "string", "description": "Opaque signed token; pass back to /api/verify." },
          "code": { "type": "string", "description": "The challenge code to place." },
          "action": { "type": "string", "enum": ["register", "delete"] },
          "domain": { "type": "string" },
          "expires_in": { "type": "integer", "example": 3600 },
          "verification": {
            "type": "object",
            "properties": {
              "file_url": { "type": "string", "description": "Place a file here containing file_content." },
              "file_content": { "type": "string", "example": "nessgate-verification=<code>" },
              "dns_record": {
                "type": "object",
                "properties": {
                  "type": { "type": "string", "example": "TXT" },
                  "name": { "type": "string", "example": "_nessgate.example.com" },
                  "value": { "type": "string", "example": "nessgate-verification=<code>" }
                }
              },
              "json_field": {
                "type": "object",
                "nullable": true,
                "description": "Only offered when the JSON URL is on the apex domain itself.",
                "properties": {
                  "url": { "type": "string" },
                  "field": { "type": "string", "example": "nessgate_verification" },
                  "value": { "type": "string" }
                }
              }
            }
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": { "error": { "type": "string" } },
        "required": ["error"]
      }
    }
  }
}
