{
  "openapi": "3.1.0",
  "info": {
    "title": "Snap IT website API",
    "version": "1.0.0",
    "summary": "The small public API behind snap-it.co.uk",
    "description": "Three endpoints, no API key. POST /api/contact sends a genuine enquiry to the Snap IT helpdesk (it creates a real prospect and ticket, so only submit on behalf of a person who wants to hear back). GET /api/whois is a domain lookup via RDAP. GET /api/whoami echoes the caller's IP and network details and doubles as a liveness check. Human documentation: https://www.snap-it.co.uk/api-docs. Every page on the site is also available as markdown via an Accept: text/markdown header.",
    "contact": {
      "name": "Snap IT",
      "url": "https://www.snap-it.co.uk/contact"
    }
  },
  "servers": [{ "url": "https://www.snap-it.co.uk" }],
  "paths": {
    "/api/contact": {
      "post": {
        "operationId": "sendEnquiry",
        "summary": "Send an enquiry to the Snap IT helpdesk",
        "description": "Creates a prospect and a ticket in our service desk, and a real person replies, usually the same working day. Only submit genuine enquiries on behalf of a person or business who wants a response. Do not use it for marketing, testing or scraping. Leave the `website` field out or empty: it is a spam honeypot and any value silently discards the submission. The form may also be protected by a Cloudflare Turnstile check; if your submission is rejected with a spam error, ask the person to use https://www.snap-it.co.uk/contact or phone 01603 980260.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/Enquiry" }
            },
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/Enquiry" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Enquiry accepted",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Ok" } } }
          },
          "400": {
            "description": "Missing name or email, unreadable body, or failed spam check",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": {
            "description": "The helpdesk could not be reached; try again shortly or phone 01603 980260",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/whois": {
      "get": {
        "operationId": "lookupDomain",
        "summary": "Look up a domain's registration via RDAP",
        "description": "Server-side RDAP lookup (the JSON successor to WHOIS). Tolerates pasted URLs, www prefixes and trailing paths in the domain parameter.",
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "The domain to look up, e.g. example.co.uk",
            "schema": { "type": "string", "examples": ["example.co.uk"] }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup result. `found: false` means the domain is not registered (or its registry publishes no RDAP record).",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DomainRecord" } } }
          },
          "400": {
            "description": "Not a valid domain name",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "502": {
            "description": "The upstream RDAP service failed",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "503": {
            "description": "The upstream RDAP service is rate limiting; retry in a few seconds",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/whoami": {
      "get": {
        "operationId": "whoAmI",
        "summary": "Echo the caller's public IP and network details",
        "description": "Returns the caller's IP plus Cloudflare's geo and network data. A 200 from this endpoint also confirms the API is up, so the API catalog lists it as the status endpoint.",
        "responses": {
          "200": {
            "description": "Caller details",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WhoAmI" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Enquiry": {
        "type": "object",
        "required": ["name", "email"],
        "properties": {
          "name": { "type": "string", "description": "The enquirer's full name" },
          "email": { "type": "string", "format": "email", "description": "Where we reply" },
          "company": { "type": "string", "description": "Business name" },
          "phone": { "type": "string" },
          "interest": { "type": "string", "description": "What the enquiry is about, e.g. IT support, cyber security, Cyber Essentials" },
          "team_size": { "type": "string", "description": "Rough headcount, e.g. 10-25" },
          "subject": { "type": "string", "description": "Optional ticket subject line" },
          "message": { "type": "string", "description": "The enquiry itself; newlines are preserved" },
          "page": { "type": "string", "description": "The page or context the enquiry came from" },
          "website": { "type": "string", "description": "Spam honeypot. Leave empty or omit; any value silently discards the submission." }
        }
      },
      "Ok": {
        "type": "object",
        "properties": { "ok": { "const": true } }
      },
      "Error": {
        "type": "object",
        "properties": {
          "ok": { "const": false },
          "error": { "type": "string", "description": "Human-readable reason" }
        }
      },
      "DomainRecord": {
        "type": "object",
        "required": ["domain", "found"],
        "properties": {
          "domain": { "type": "string" },
          "found": { "type": "boolean" },
          "registrar": { "type": ["string", "null"] },
          "registered": { "type": ["string", "null"], "description": "Registration date, ISO 8601" },
          "expires": { "type": ["string", "null"], "description": "Expiry date, ISO 8601" },
          "updated": { "type": ["string", "null"], "description": "Last changed date, ISO 8601" },
          "status": { "type": "array", "items": { "type": "string" }, "description": "RDAP status values" },
          "locked": { "type": "boolean", "description": "True when a transfer lock is in place" },
          "nameservers": { "type": "array", "items": { "type": "string" } },
          "dnssec": { "type": ["boolean", "null"], "description": "True when the delegation is DNSSEC signed" }
        }
      },
      "WhoAmI": {
        "type": "object",
        "properties": {
          "ip": { "type": ["string", "null"] },
          "country": { "type": ["string", "null"] },
          "region": { "type": ["string", "null"] },
          "city": { "type": ["string", "null"] },
          "postalCode": { "type": ["string", "null"] },
          "timezone": { "type": ["string", "null"] },
          "asn": { "type": ["integer", "null"] },
          "network": { "type": ["string", "null"], "description": "AS organisation name" },
          "colo": { "type": ["string", "null"], "description": "Cloudflare data centre code" },
          "httpProtocol": { "type": ["string", "null"] },
          "userAgent": { "type": ["string", "null"] },
          "time": { "type": "string", "format": "date-time" }
        }
      }
    }
  }
}
