{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/justdomain-ai/json-schema/justdomain-ai-search-response-schema.json",
  "title": "SearchResponse",
  "x-generated": "2026-11-13",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/mcp-openapi.json#/components/schemas/SearchResponse",
  "properties": {
    "domains": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "title": "Domains",
      "description": "The exact domains requested by the caller, echoed back."
    },
    "results": {
      "items": {
        "$ref": "#/$defs/DomainResult"
      },
      "type": "array",
      "title": "Results"
    },
    "alternatives": {
      "items": {
        "$ref": "#/$defs/DomainResult"
      },
      "type": "array",
      "title": "Alternatives",
      "description": "Available domains the caller did not ask about, offered only when every requested domain came back unavailable. Same label the caller typed, on a different ending; nothing is invented and nothing here duplicates a name in `results`. Every entry is available, non-premium and carries a `checkout_url`, so it can be offered to the user directly. Empty is not an error. It means one of three things: recovery is switched off for this deployment, or the search was not a dead end, or the same label is taken on the other endings too, which is the normal outcome for a common dictionary word. Do not tell the user that other endings were checked unless this list is non-empty. Do not re-check these; they were checked live in this same call."
    },
    "component_hint": {
      "type": "string",
      "const": "domain_search_results",
      "title": "Component Hint",
      "default": "domain_search_results"
    },
    "next_action": {
      "type": "string",
      "title": "Next Action",
      "description": "An instruction for the assistant reading this response, or the string 'none' when there is nothing extra to do. It is set in two cases. When no requested domain and no alternative in this response can be registered through Just Domain, it tells you how to search again. When at least one domain carries a `checkout_url`, it tells you to make the name of each such domain you mention in your reply a clickable link to its `checkout_url`. When it is not 'none', carry it out in this same turn before or while replying to the user; it is written to be executable as-is.",
      "default": "none"
    },
    "warnings": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "title": "Warnings"
    },
    "error": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Error",
      "description": "Set when the search could not be completed (e.g. invalid query, provider failure)."
    },
    "error_message": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "title": "Error Message"
    }
  },
  "type": "object",
  "required": [
    "domains",
    "results"
  ],
  "$defs": {
    "DomainResult": {
      "properties": {
        "fqdn": {
          "type": "string",
          "title": "Fqdn"
        },
        "name": {
          "type": "string",
          "title": "Name"
        },
        "tld": {
          "type": "string",
          "title": "Tld"
        },
        "available": {
          "type": "boolean",
          "title": "Available"
        },
        "status": {
          "type": "string",
          "title": "Status",
          "description": "Raw provider status, e.g. 'free', 'active', 'premium'."
        },
        "premium": {
          "type": "boolean",
          "title": "Premium",
          "default": false
        },
        "price": {
          "anyOf": [
            {
              "$ref": "#/$defs/Price"
            },
            {
              "type": "null"
            }
          ],
          "description": "Registration price: the total for ONE full registration term of this ending, not a per-year rate. One year on most endings; two years on .ai, whose registry mandates a two-year term."
        },
        "renewal_price": {
          "anyOf": [
            {
              "$ref": "#/$defs/Price"
            },
            {
              "type": "null"
            }
          ],
          "description": "Renewal price: the total for ONE further registration term, on the same basis as `price`. What a later term would cost at today's rate, not a figure anyone has been charged or quoted for a specific renewal. An owner renews, and turns auto-renew on or off, on their own dashboard at https://justdomain.ai/dashboard, which is the only authoritative source for one domain's renewal state."
        },
        "term_years": {
          "type": "integer",
          "title": "Term Years",
          "description": "Length in years of ONE registration term for this ending, and therefore the period `price` and `renewal_price` each cover. 1 on most endings; 2 on .ai, whose registry mandates a two-year term with no one-year option. Read this before describing any price as annual.",
          "default": 1
        },
        "requires_additional_data": {
          "anyOf": [
            {
              "type": "boolean"
            },
            {
              "type": "null"
            }
          ],
          "title": "Requires Additional Data",
          "description": "Does this ending's registry demand registrant data beyond standard contact details - a nexus declaration, a national ID, a professional credential? TRI-STATE: true / false / null = we do not know. Just Domain cannot collect or submit that data yet, so a true (or unknown) value means the name is reported honestly but carries no `checkout_url`."
        },
        "checkout_url": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Checkout Url",
          "description": "URL on the Just Domain website where the user completes payment. Set for available domains we can actually register; null for unavailable ones, for premium names (the checkout API refuses them), and for endings whose registry requires registrant data we cannot supply yet. The MCP tool handler fills this in after the bare service call so the UI widget's Buy button can open checkout directly in one click."
        },
        "warnings": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Warnings"
        }
      },
      "type": "object",
      "required": [
        "fqdn",
        "name",
        "tld",
        "available",
        "status"
      ],
      "title": "DomainResult"
    },
    "Price": {
      "properties": {
        "amount_minor": {
          "type": "integer",
          "title": "Amount Minor",
          "description": "Amount in the smallest currency unit (e.g. cents)."
        },
        "currency": {
          "type": "string",
          "maxLength": 3,
          "minLength": 3,
          "title": "Currency",
          "description": "ISO-4217 currency code."
        },
        "formatted": {
          "type": "string",
          "title": "Formatted",
          "description": "Human-readable price, e.g. '$12.99'."
        }
      },
      "type": "object",
      "required": [
        "amount_minor",
        "currency",
        "formatted"
      ],
      "title": "Price"
    }
  }
}