{
  "openapi": "3.1.0",
  "info": {
    "title": "audit.domains public API",
    "version": "1.0.0",
    "description": "Deterministic domain appraisals, comparable sales, bulk valuation, and recorded-sales search.\n\nAPI access is included with paid plans: every request requires an `ad_live_` API key (create one at https://audit.domains/profile?tab=api), keys work only on paid plans, and appraisal-producing calls consume the account's monthly plan appraisal credits - the same quota the site meters. `X-RateLimit-Limit` / `X-RateLimit-Remaining` response headers report the credit meter.\n\nDeterminism guarantee: the same domain on the same engine version always returns the same result. Every appraisal carries its ODVS hashes (appraisalHash, inputCommitment, resultDigest) so the result can be verified independently.",
    "contact": { "url": "https://audit.domains/contact" }
  },
  "servers": [{ "url": "https://audit.domains" }],
  "security": [{ "bearerKey": [] }, { "headerKey": [] }],
  "paths": {
    "/api/v1/appraise": {
      "post": {
        "summary": "Appraise one domain (1 credit)",
        "operationId": "appraiseDomain",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domain"],
                "properties": {
                  "domain": { "type": "string", "examples": ["example.com"] }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The locked public appraisal projection.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Appraisal" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/AuthUnavailable" }
        }
      }
    },
    "/api/v1/comps": {
      "get": {
        "summary": "Comparable sales for a domain (1 credit)",
        "operationId": "getComps",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "schema": { "type": "string" }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": { "type": "integer", "minimum": 1, "maximum": 5, "default": 5 }
          }
        ],
        "responses": {
          "200": {
            "description": "Top comparable sales, indexed by the published methodology.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": { "type": "string" },
                    "comps": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Comp" }
                    },
                    "methodologyVersion": { "type": ["string", "null"] },
                    "dataEdition": { "type": ["string", "null"] },
                    "generatedAt": { "type": "string", "format": "date-time" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/AuthUnavailable" }
        }
      }
    },
    "/api/v1/bulk": {
      "post": {
        "summary": "Appraise up to 20 domains (1 credit per domain; plan must include bulk)",
        "operationId": "bulkAppraise",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["domains"],
                "properties": {
                  "domains": {
                    "type": "array",
                    "items": { "type": "string" },
                    "minItems": 1,
                    "maxItems": 20
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-domain results. If credits run out mid-batch, remaining domains report quota_exhausted and only processed domains were charged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "domain": { "type": "string" },
                          "ok": { "type": "boolean" },
                          "appraisal": { "$ref": "#/components/schemas/Appraisal" },
                          "error": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": { "$ref": "#/components/responses/AuthUnavailable" }
        }
      }
    },
    "/api/v1/sales": {
      "get": {
        "summary": "Search recorded domain sales (no credit; paid plan required)",
        "operationId": "searchSales",
        "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string" }, "description": "Substring match on domain (verified source also matches category/venue)." },
          { "name": "tld", "in": "query", "schema": { "type": "string" } },
          { "name": "minPrice", "in": "query", "schema": { "type": "integer" } },
          { "name": "maxPrice", "in": "query", "schema": { "type": "integer" } },
          { "name": "yearFrom", "in": "query", "schema": { "type": "integer" } },
          { "name": "yearTo", "in": "query", "schema": { "type": "integer" } },
          { "name": "venue", "in": "query", "schema": { "type": "string" } },
          { "name": "sort", "in": "query", "schema": { "type": "string", "enum": ["price", "date", "domain"], "default": "price" } },
          { "name": "dir", "in": "query", "schema": { "type": "string", "enum": ["asc", "desc"], "default": "desc" } },
          { "name": "page", "in": "query", "schema": { "type": "integer", "minimum": 1, "default": 1 } },
          { "name": "pageSize", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 50 } },
          {
            "name": "source",
            "in": "query",
            "schema": { "type": "string", "enum": ["verified", "ledger"], "default": "verified" },
            "description": "verified = the curated, screened corpus valuations use. ledger = the published research ledger (bulk records with per-row source attribution; NOT used in valuations)."
          }
        ],
        "responses": {
          "200": {
            "description": "One page of sales.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "source": { "type": "string", "enum": ["verified", "ledger"] },
                    "total": { "type": ["integer", "null"], "description": "Exact for the verified source; null for the ledger." },
                    "page": { "type": "integer" },
                    "pageSize": { "type": "integer" },
                    "hasMore": { "type": "boolean" },
                    "rows": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/SaleRecord" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "503": {
            "description": "source_unavailable (ledger not yet published) or api_auth_unavailable.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer ad_live_..."
      },
      "headerKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "invalid_json, invalid_domain, domains_required, or too_many_domains.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "key_required (no key sent) or invalid_key (unknown, revoked, or expired).",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "PaymentRequired": {
        "description": "paid_plan_required (free-plan key), upgrade_required (plan lacks the feature), or quota_exhausted (monthly credits spent).",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "RateLimited": {
        "description": "Per-IP abuse damping tripped; retry with backoff.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "AuthUnavailable": {
        "description": "api_auth_unavailable - key verification is unreachable; the API fails closed.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "detail": { "type": "string" }
        },
        "required": ["error"]
      },
      "Factor": {
        "type": "object",
        "properties": {
          "key": { "type": "string" },
          "label": { "type": "string" },
          "score": { "type": "integer", "minimum": 0, "maximum": 100 }
        }
      },
      "Comp": {
        "type": "object",
        "properties": {
          "domain": { "type": "string" },
          "priceUsd": { "type": "number" },
          "year": { "type": "string" },
          "venue": { "type": ["string", "null"] },
          "similarity": { "type": "integer", "minimum": 0, "maximum": 100 }
        }
      },
      "Appraisal": {
        "type": "object",
        "description": "The locked v1 projection. Keys are contract-locked; new keys only arrive with a version bump.",
        "properties": {
          "domain": { "type": "string" },
          "valueUSD": { "type": "number" },
          "valueRange": {
            "type": "object",
            "properties": {
              "low": { "type": "number" },
              "mid": { "type": "number" },
              "high": { "type": "number" }
            }
          },
          "tier": { "type": "string" },
          "confidence": { "type": "number" },
          "factors": { "type": "array", "items": { "$ref": "#/components/schemas/Factor" } },
          "methodologyVersion": { "type": ["string", "null"] },
          "engineVersion": { "type": "string" },
          "comps": { "type": "array", "items": { "$ref": "#/components/schemas/Comp" }, "maxItems": 5 },
          "appraisalHash": { "type": "string", "description": "SHA-256 over {commitment, result, hashVersion} - the appraisal's stable id (ODVS)." },
          "inputCommitment": { "type": "string", "description": "SHA-256 over {domain, engineId, engineVersion} - identity of the computation (ODVS)." },
          "resultDigest": { "type": "string", "description": "SHA-256 over the canonical numeric outputs (ODVS)." },
          "generatedAt": { "type": "string", "format": "date-time" },
          "dataEdition": { "type": ["string", "null"], "description": "Version of the comparables snapshot in effect, when known." }
        }
      },
      "SaleRecord": {
        "type": "object",
        "properties": {
          "domain": { "type": "string" },
          "price": { "type": "number" },
          "saleDate": { "type": "string", "description": "ISO date, a bare year, or empty when unknown." },
          "venue": { "type": ["string", "null"] },
          "category": { "type": ["string", "null"] },
          "verified": { "type": "boolean" },
          "source": { "type": "string", "description": "\"curated\" for the verified corpus; ledger rows carry their bulk-source id." }
        }
      }
    }
  }
}
