{"openapi":"3.1.0","info":{"title":"Email Reputation Checker","version":"0.1.0","description":"Checks a domain's email authentication setup via DNS-over-HTTPS.\n\n**Scoring** – weighted average of six checks, each 0–100:\n\n| Check | Weight |\n|---|---|\n| SPF | 25% |\n| DKIM | 25% |\n| DMARC | 25% |\n| MX | 15% |\n| DNSSEC | 5% |\n| BIMI | 5% |\n\n**Grades** – A+ ≥ 90, A ≥ 80, B ≥ 70, C ≥ 60, D ≥ 50, F < 50.\n\nFor AI agents, a UTCP manual is served at [`/utcp`](/utcp)."},"tags":[{"name":"Checks","description":"Email authentication / reputation"},{"name":"Meta"}],"paths":{"/api/check":{"get":{"tags":["Checks"],"summary":"Check a domain","operationId":"checkDomain","parameters":[{"name":"domain","required":true,"schema":{"type":"string"},"example":"livetiosen.no","description":"Domain to check. URLs and email addresses are normalised.","in":"query"},{"name":"selectors","in":"query","required":false,"schema":{"type":"string"},"example":"mailjet,sendgrid","description":"Comma-separated custom DKIM selectors, checked in addition to the common ones."}],"responses":{"200":{"description":"Domain report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainReport"}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Checks"],"summary":"Check a domain (JSON body)","operationId":"checkDomainPost","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string","example":"livetiosen.no"},"selectors":{"type":"array","items":{"type":"string"},"example":["mailjet"]}}}}}},"responses":{"200":{"description":"Domain report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainReport"}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/check/{domain}":{"get":{"tags":["Checks"],"summary":"Check a domain (path parameter)","operationId":"checkDomainPath","parameters":[{"name":"domain","required":true,"schema":{"type":"string"},"example":"livetiosen.no","description":"Domain to check. URLs and email addresses are normalised.","in":"path"},{"name":"selectors","in":"query","required":false,"schema":{"type":"string"},"example":"mailjet,sendgrid","description":"Comma-separated custom DKIM selectors, checked in addition to the common ones."}],"responses":{"200":{"description":"Domain report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainReport"}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/utcp":{"get":{"tags":["Meta"],"summary":"UTCP manual for AI agents","operationId":"utcpManual","responses":{"200":{"description":"UTCP manual","content":{"application/json":{}}}}}},"/health":{"get":{"tags":["Meta"],"summary":"Health check","operationId":"health","responses":{"200":{"description":"OK"}}}}},"components":{"schemas":{"CheckResult":{"type":"object","required":["id","name","status","score","weight","message","records"],"properties":{"id":{"type":"string","enum":["spf","dkim","dmarc","mx","dnssec","bimi"],"example":"spf"},"name":{"type":"string","example":"SPF Record"},"status":{"type":"string","enum":["pass","warning","fail"],"example":"fail"},"score":{"type":"integer","minimum":0,"maximum":100,"example":0},"weight":{"type":"number","description":"Relative weight in the overall score","example":25},"message":{"type":"string","example":"No SPF record found. Add a TXT record starting with 'v=spf1' to authorize email senders."},"records":{"type":"array","items":{"type":"string"},"description":"Raw DNS records found"},"details":{"type":"object","additionalProperties":true},"fix":{"$ref":"#/components/schemas/Fix"}}},"DomainReport":{"type":"object","required":["domain","score","grade","passed","total","summary","checks","checkedAt"],"properties":{"domain":{"type":"string","example":"livetiosen.no"},"score":{"type":"integer","minimum":0,"maximum":100,"example":28},"grade":{"type":"string","enum":["A+","A","B","C","D","F"],"example":"F"},"passed":{"type":"integer","example":1},"total":{"type":"integer","example":6},"summary":{"type":"string","example":"livetiosen.no scored 28/100 (grade F), 1/6 checks passed."},"checks":{"type":"array","items":{"$ref":"#/components/schemas/CheckResult"}},"checkedAt":{"type":"string","format":"date-time"}}},"Error":{"type":"object","properties":{"error":{"type":"string"}}},"Fix":{"type":"object","properties":{"text":{"type":"string"},"example":{"type":"string"},"links":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"url":{"type":"string","format":"uri"}}}}}},"Finding":{"type":"object","properties":{"id":{"type":"string","example":"dnssec"},"status":{"type":"string","enum":["pass","warning","fail"]},"title":{"type":"string"},"message":{"type":"string"},"fix":{"$ref":"#/components/schemas/Fix"}}},"DnsOverview":{"type":"object","properties":{"name":{"type":"string"},"zone":{"type":"string"},"isApex":{"type":"boolean"},"source":{"type":"string","description":"Authoritative server IP the records were read from"},"nameservers":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ipv4":{"type":"array","items":{"type":"string"}},"ipv6":{"type":"array","items":{"type":"string"}},"inParent":{"type":"boolean"},"inZone":{"type":"boolean"},"responds":{"type":"boolean"},"authoritative":{"type":"boolean"},"serial":{"type":["integer","null"]},"rttMs":{"type":["integer","null"]}}}},"soa":{"type":["object","null"]},"records":{"type":"object","description":"Keyed by record type","additionalProperties":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"ttl":{"type":"integer"},"value":{"type":"string"}}}}},"dnssec":{"type":"object","properties":{"signed":{"type":"boolean"},"validated":{"type":"boolean"},"ds":{"type":"array","items":{"type":"string"}},"dnskeys":{"type":"integer"}}},"findings":{"type":"array","items":{"$ref":"#/components/schemas/Finding"}},"summary":{"type":"object","properties":{"pass":{"type":"integer"},"warning":{"type":"integer"},"fail":{"type":"integer"}}}}},"PropagationReport":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"zone":{"type":"string"},"expectedSource":{"type":"string","enum":["authoritative","user"]},"expected":{"type":"array","items":{"type":"string"}},"authoritativeConsistent":{"type":"boolean"},"authoritative":{"type":"array","items":{"type":"object"}},"resolvers":{"type":"array","items":{"type":"object","properties":{"ip":{"type":"string"},"provider":{"type":"string"},"country":{"type":"string"},"region":{"type":"string"},"anycast":{"type":"boolean"},"city":{"type":"string","description":"Approximate location (unicast resolvers only)"},"lat":{"type":"number"},"lon":{"type":"number"},"status":{"type":"string","enum":["match","mismatch","missing","error"]},"values":{"type":"array","items":{"type":"string"}},"ttl":{"type":["integer","null"]},"rttMs":{"type":["integer","null"]},"error":{"type":"string"}}}},"summary":{"type":"object","properties":{"matched":{"type":"integer"},"responded":{"type":"integer"},"total":{"type":"integer"},"percent":{"type":"integer"},"maxTtlRemaining":{"type":["integer","null"]}}}}}}}}