{
  "openapi": "3.0.3",
  "info": {
    "title": "Mailcheck API",
    "description": "REST API for checking SPF, DKIM, DMARC, MTA-STS, TLS-RPT, and BIMI email deliverability configuration. Returns a 0–100 deliverability score with detailed findings.",
    "version": "1.0.0",
    "contact": {
      "name": "Mailcheck Contributors",
      "url": "https://korpo.pro/git/mailcheck/mailcheck"
    },
    "license": {
      "name": "MIT",
      "url": "https://korpo.pro/git/mailcheck/mailcheck/src/branch/main/LICENSE"
    }
  },
  "servers": [
    {
      "url": "https://korpo.pro/api/v1",
      "description": "Production server"
    }
  ],
  "tags": [
    {
      "name": "mailcheck",
      "description": "Email deliverability checking endpoints"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "tags": ["mailcheck"],
        "summary": "Health check",
        "description": "Returns the health status of the Mailcheck API service.",
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                },
                "example": {
                  "status": "ok",
                  "timestamp": 1714032000,
                  "service": "mailcheck-api",
                  "version": "1.0.0"
                }
              }
            }
          }
        }
      }
    },
    "/check/{domain}": {
      "get": {
        "operationId": "checkDomain",
        "tags": ["mailcheck"],
        "summary": "Check domain deliverability",
        "description": "Run SPF, DKIM, DMARC, MTA-STS, TLS-RPT, and BIMI checks for the given domain and return a JSON deliverability report with a 0–100 score.",
        "parameters": [
          {
            "name": "domain",
            "in": "path",
            "required": true,
            "description": "Domain name to check, e.g. example.com",
            "schema": {
              "type": "string",
              "pattern": "^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*\\.[a-zA-Z]{2,}$"
            },
            "example": "example.com"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful domain check result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainReport"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — maximum 50 requests per hour per IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                },
                "example": {
                  "detail": "Rate limit exceeded. Maximum 50 requests per hour per IP."
                }
              }
            }
          }
        }
      }
    },
    "/subscribe": {
      "post": {
        "operationId": "subscribe",
        "tags": ["mailcheck"],
        "summary": "Subscribe for updates",
        "description": "Subscribe an email address for deliverability insights and updates.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubscribeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Subscription processed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubscribeResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded — maximum 50 requests per hour per IP",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RateLimitError"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "HealthResponse": {
        "type": "object",
        "required": ["status", "timestamp", "service", "version"],
        "properties": {
          "status": {
            "type": "string",
            "description": "Health status of the service",
            "enum": ["ok"]
          },
          "timestamp": {
            "type": "integer",
            "description": "Unix timestamp of the health check",
            "format": "int64"
          },
          "service": {
            "type": "string",
            "description": "Name of the service",
            "enum": ["mailcheck-api"]
          },
          "version": {
            "type": "string",
            "description": "API version",
            "pattern": "^\\d+\\.\\d+\\.\\d+$"
          }
        }
      },
      "Issue": {
        "type": "object",
        "required": ["record_type", "severity", "message"],
        "properties": {
          "record_type": {
            "type": "string",
            "description": "The DNS record type this issue relates to",
            "enum": ["SPF", "DKIM", "DMARC", "MTA-STS", "TLS-RPT", "BIMI"]
          },
          "severity": {
            "type": "string",
            "description": "Issue severity level",
            "enum": ["critical", "warning", "info"]
          },
          "message": {
            "type": "string",
            "description": "Human-readable description of the issue"
          },
          "detail": {
            "type": "string",
            "description": "Optional additional detail about the issue",
            "nullable": true
          }
        }
      },
      "SPFResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether an SPF record was found"
          },
          "record": {
            "type": "string",
            "description": "The raw SPF record string",
            "nullable": true
          },
          "all_mechanism": {
            "type": "string",
            "description": "The SPF all mechanism qualifier (+all, ~all, -all, ?all)",
            "nullable": true,
            "enum": ["+all", "~all", "-all", "?all"]
          },
          "includes": {
            "type": "array",
            "description": "List of domains included via the include mechanism",
            "items": {
              "type": "string"
            }
          },
          "redirects": {
            "type": "string",
            "description": "The redirect target domain",
            "nullable": true
          },
          "has_ptr": {
            "type": "boolean",
            "description": "Whether the record uses the deprecated ptr mechanism"
          },
          "dns_lookups": {
            "type": "integer",
            "description": "Number of DNS lookups triggered by the SPF record",
            "format": "int32"
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the SPF configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "DKIMResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether any DKIM record was found"
          },
          "selectors_found": {
            "type": "array",
            "description": "List of DKIM selectors that had valid records",
            "items": {
              "type": "string"
            }
          },
          "selectors_checked": {
            "type": "array",
            "description": "List of DKIM selectors that were probed",
            "items": {
              "type": "string"
            }
          },
          "records": {
            "type": "object",
            "description": "Map of selector name to its DKIM record value",
            "additionalProperties": {
              "type": "string",
              "nullable": true
            }
          },
          "key_sizes": {
            "type": "object",
            "description": "Map of selector name to its key size in bits",
            "additionalProperties": {
              "type": "integer",
              "format": "int32"
            }
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the DKIM configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "DMARCResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether a DMARC record was found"
          },
          "record": {
            "type": "string",
            "description": "The raw DMARC record string",
            "nullable": true
          },
          "policy": {
            "type": "string",
            "description": "The DMARC policy (none, quarantine, or reject)",
            "nullable": true,
            "enum": ["none", "quarantine", "reject"]
          },
          "subdomain_policy": {
            "type": "string",
            "description": "The DMARC subdomain policy (sp tag)",
            "nullable": true
          },
          "percentage": {
            "type": "integer",
            "description": "The DMARC percentage (pct tag)",
            "nullable": true,
            "format": "int32"
          },
          "rua": {
            "type": "array",
            "description": "Aggregate reporting URIs (rua tag)",
            "items": {
              "type": "string"
            }
          },
          "ruf": {
            "type": "array",
            "description": "Forensic reporting URIs (ruf tag)",
            "items": {
              "type": "string"
            }
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the DMARC configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "MTASTSResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether an MTA-STS TXT record was found"
          },
          "txt_record": {
            "type": "string",
            "description": "The raw MTA-STS TXT record",
            "nullable": true
          },
          "version": {
            "type": "string",
            "description": "MTA-STS version (e.g. STSv1)",
            "nullable": true
          },
          "id_value": {
            "type": "string",
            "description": "Policy ID from the TXT record",
            "nullable": true
          },
          "policy_fetched": {
            "type": "boolean",
            "description": "Whether the MTA-STS policy file was successfully fetched"
          },
          "mode": {
            "type": "string",
            "description": "MTA-STS mode (enforce, testing, or none)",
            "nullable": true,
            "enum": ["enforce", "testing", "none"]
          },
          "max_age": {
            "type": "integer",
            "description": "Policy max-age in seconds",
            "nullable": true,
            "format": "int32"
          },
          "mx_patterns": {
            "type": "array",
            "description": "MX patterns from the MTA-STS policy",
            "items": {
              "type": "string"
            }
          },
          "policy_text": {
            "type": "string",
            "description": "Raw content of the MTA-STS policy file",
            "nullable": true
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the MTA-STS configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "TLSRPTResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether a TLS-RPT record was found"
          },
          "record": {
            "type": "string",
            "description": "The raw TLS-RPT record string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "description": "TLS-RPT version (e.g. TLSRPTv1)",
            "nullable": true
          },
          "rua": {
            "type": "array",
            "description": "Reporting URIs for TLS failure reports",
            "items": {
              "type": "string"
            }
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the TLS-RPT configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "BIMIResult": {
        "type": "object",
        "required": ["found"],
        "properties": {
          "found": {
            "type": "boolean",
            "description": "Whether a BIMI record was found"
          },
          "record": {
            "type": "string",
            "description": "The raw BIMI record string",
            "nullable": true
          },
          "version": {
            "type": "string",
            "description": "BIMI version tag",
            "nullable": true
          },
          "location": {
            "type": "string",
            "description": "Logo location URL (l= tag, SVG/PNG)",
            "nullable": true
          },
          "authority": {
            "type": "string",
            "description": "Authority certificate URL (a= tag)",
            "nullable": true
          },
          "issues": {
            "type": "array",
            "description": "Issues found with the BIMI configuration",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "DomainReport": {
        "type": "object",
        "required": ["domain", "score", "spf", "dkim", "dmarc", "mtasts", "tlsrpt", "bimi", "issues"],
        "properties": {
          "domain": {
            "type": "string",
            "description": "The domain that was checked"
          },
          "score": {
            "type": "integer",
            "description": "Deliverability score from 0 to 100",
            "minimum": 0,
            "maximum": 100,
            "format": "int32"
          },
          "spf": {
            "$ref": "#/components/schemas/SPFResult"
          },
          "dkim": {
            "$ref": "#/components/schemas/DKIMResult"
          },
          "dmarc": {
            "$ref": "#/components/schemas/DMARCResult"
          },
          "mtasts": {
            "$ref": "#/components/schemas/MTASTSResult"
          },
          "tlsrpt": {
            "$ref": "#/components/schemas/TLSRPTResult"
          },
          "bimi": {
            "$ref": "#/components/schemas/BIMIResult"
          },
          "issues": {
            "type": "array",
            "description": "Top-level issues from all checks combined",
            "items": {
              "$ref": "#/components/schemas/Issue"
            }
          }
        }
      },
      "SubscribeRequest": {
        "type": "object",
        "required": ["email"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "description": "Email address to subscribe"
          }
        }
      },
      "SubscribeResponse": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": {
            "type": "string",
            "enum": ["ok", "error"]
          },
          "message": {
            "type": "string",
            "description": "Subscription result message"
          }
        }
      },
      "RateLimitError": {
        "type": "object",
        "required": ["detail"],
        "properties": {
          "detail": {
            "type": "string",
            "description": "Rate limit error message"
          }
        }
      }
    }
  }
}