{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/justdomain-ai/json-schema/justdomain-ai-transfer-precheck-response-schema.json",
  "title": "TransferPrecheckResponse",
  "description": "The public precheck payload. The frontend checker is built against it.\n\n**Additive only.** Every key below `source` was added after the page\nshipped, and nothing above it may be removed or renamed: the checker\nreads the payload as a typed object, and a renamed key is a blank on a\npublic page. `tests/test_transfer_precheck_parity.py` pins the original\nkey set.\n\nThe last four fields are the ones the MCP tool `check_domain_transfer`\nhas always carried. They come from the same builder\n(`shared/services/transfer_handoff`), so an agent with no MCP client gets\nthe same `ready`, the same handoff link, the same next step and - the\none that matters - the same authorization-code refusal, byte for byte.\nThe one key that still differs is the projected date: `new_expiry` here,\n`expected_new_expiry` on the tool.",
  "x-generated": "2026-11-13",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/mcp-openapi.json#/components/schemas/TransferPrecheckResponse",
  "properties": {
    "domain": {
      "type": "string",
      "title": "Domain"
    },
    "tld": {
      "type": "string",
      "title": "Tld"
    },
    "supported": {
      "type": "boolean",
      "title": "Supported"
    },
    "checked_at": {
      "type": "string",
      "title": "Checked At"
    },
    "blockers": {
      "items": {
        "$ref": "#/$defs/TransferBlockerOut"
      },
      "type": "array",
      "title": "Blockers",
      "default": []
    },
    "registrar": {
      "$ref": "#/$defs/TransferRegistrarOut"
    },
    "nameservers": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "title": "Nameservers",
      "default": []
    },
    "dns_continuity": {
      "$ref": "#/$defs/DnsContinuityOut"
    },
    "price": {
      "anyOf": [
        {
          "$ref": "#/$defs/TransferPriceOut"
        },
        {
          "type": "null"
        }
      ]
    },
    "source": {
      "$ref": "#/$defs/TransferPrecheckSourceOut"
    },
    "ready": {
      "type": "boolean",
      "title": "Ready",
      "description": "TRUE only when `blockers` is empty. A convenience over that list that can never disagree with it: anything we could not establish becomes a blocker, so a registry timeout reads as not ready."
    },
    "transfer_url": {
      "type": "string",
      "title": "Transfer Url",
      "description": "The page on justdomain.ai a PERSON opens in a browser to take this further."
    },
    "next_step": {
      "type": "string",
      "title": "Next Step",
      "description": "One sentence about what happens next, already matched to this domain's state. Written to be relayed to a person as-is."
    },
    "auth_code_policy": {
      "type": "string",
      "title": "Auth Code Policy",
      "description": "Constant. The rule about authorization (EPP) codes, restated in every payload so it travels with the answer."
    }
  },
  "type": "object",
  "required": [
    "domain",
    "tld",
    "supported",
    "checked_at",
    "registrar",
    "dns_continuity",
    "source",
    "ready",
    "transfer_url",
    "next_step",
    "auth_code_policy"
  ],
  "$defs": {
    "DnsContinuityOut": {
      "properties": {
        "case": {
          "type": "string",
          "title": "Case"
        },
        "provider": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Provider"
        },
        "detail": {
          "type": "string",
          "title": "Detail"
        },
        "records": {
          "items": {
            "$ref": "#/$defs/DnsRecordOut"
          },
          "type": "array",
          "title": "Records",
          "default": []
        },
        "records_probed": {
          "type": "boolean",
          "title": "Records Probed",
          "default": false
        },
        "records_unreadable": {
          "type": "integer",
          "title": "Records Unreadable",
          "default": 0
        },
        "records_notes": {
          "items": {
            "type": "string"
          },
          "type": "array",
          "title": "Records Notes",
          "default": []
        }
      },
      "type": "object",
      "required": [
        "case",
        "detail"
      ],
      "title": "DnsContinuityOut",
      "description": "Does DNS keep working after the transfer?\n\n\"independent\" - the nameservers belong to a DNS provider, not to the\nlosing registrar, so a transfer does not touch them. \"losing_registrar\" -\nthe dangerous case: the old registrar eventually stops serving the zone.\n\"unknown\" - we do not recognise the nameservers, said plainly.\n\n`records` is the public-DNS probe the wizard renders for its \"does this\nlook complete?\" review. It is only populated when the caller asks for it\n(`include_records`), because the probe is ~57 lookups against public\nresolvers and the checker page does not need them to answer its own\nquestion. **`records_probed` is how a client tells \"we did not look\" from\n\"there is nothing there\"** - an empty `records` with `records_probed:\nfalse` means the first, and treating it as the second is how somebody\nstages an empty zone."
    },
    "DnsRecordOut": {
      "properties": {
        "type": {
          "type": "string",
          "title": "Type",
          "description": "A, AAAA, CNAME, MX, TXT, NS, SRV, CAA."
        },
        "name": {
          "type": "string",
          "title": "Name",
          "description": "The absolute host, e.g. 'example.com' or '_dmarc.example.com'."
        },
        "value": {
          "type": "string",
          "title": "Value"
        },
        "ttl": {
          "type": "integer",
          "title": "Ttl",
          "default": 3600
        },
        "prio": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "title": "Prio"
        }
      },
      "type": "object",
      "required": [
        "type",
        "name",
        "value"
      ],
      "title": "DnsRecordOut",
      "description": "One DNS record, in the five fields the rest of the product uses.\n\nIdentical in shape to what the DNS-management screen sends, so a record\nread off somebody else's nameservers and a record typed into our own\nform are the same object and never need translating between the two."
    },
    "TransferBlockerOut": {
      "properties": {
        "code": {
          "type": "string",
          "title": "Code"
        },
        "detail": {
          "type": "string",
          "title": "Detail"
        },
        "eligible_at": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Eligible At"
        }
      },
      "type": "object",
      "required": [
        "code",
        "detail"
      ],
      "title": "TransferBlockerOut"
    },
    "TransferPrecheckSourceOut": {
      "properties": {
        "rdap": {
          "type": "boolean",
          "title": "Rdap"
        },
        "registrar_pricing": {
          "type": "boolean",
          "title": "Registrar Pricing"
        }
      },
      "type": "object",
      "required": [
        "rdap",
        "registrar_pricing"
      ],
      "title": "TransferPrecheckSourceOut",
      "description": "Which sources actually answered on this request.\n\n`registrar_pricing: false` means the price is missing because we could\nnot read it, not because the domain is free to transfer."
    },
    "TransferPriceOut": {
      "properties": {
        "amount": {
          "type": "string",
          "title": "Amount"
        },
        "currency": {
          "type": "string",
          "title": "Currency"
        },
        "term_years": {
          "type": "integer",
          "title": "Term Years"
        },
        "term_note": {
          "type": "string",
          "title": "Term Note"
        },
        "new_expiry": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "New Expiry"
        },
        "is_premium": {
          "type": "boolean",
          "title": "Is Premium"
        }
      },
      "type": "object",
      "required": [
        "amount",
        "currency",
        "term_years",
        "term_note",
        "is_premium"
      ],
      "title": "TransferPriceOut"
    },
    "TransferRegistrarOut": {
      "properties": {
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Name"
        },
        "iana_id": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "title": "Iana Id"
        }
      },
      "type": "object",
      "title": "TransferRegistrarOut",
      "description": "Who sponsors the domain today, as the REGISTRY reports it."
    }
  }
}