{
	"openapi": "3.1.0",
	"info": {
		"title": "certdesk API",
		"version": "1.1.0",
		"description": "TLS/SSL certificate diagnostics: served-certificate expiry (measured from a Korean network, CT logs as fallback), chain, revocation, security grade, TLS error explanations and free expiry monitoring by email (double opt-in). No API key. Limit: 30 requests per minute per IP; results cached per domain for 10 minutes (security: 30 minutes). Free and best-effort. Docs: https://certdesk.dev/en/api/ · MCP server: https://certdesk.dev/mcp",
		"contact": {
			"email": "hello@certdesk.dev",
			"url": "https://certdesk.dev/en/api/"
		}
	},
	"servers": [
		{
			"url": "https://certdesk.dev/api/v1"
		}
	],
	"paths": {
		"/certificate": {
			"get": {
				"operationId": "checkCertificate",
				"summary": "Check one domain's TLS certificate in depth",
				"description": "Expiry and days left for the certificate the server actually serves (source=served) or, if the server could not be measured, the latest certificate in CT logs (source=ct); newerInCt=true means a later-expiring certificate exists in CT logs but is not served. Also live TLS verification (global PoP and Korea), chain, revocation and CA incident history.",
				"parameters": [
					{
						"$ref": "#/components/parameters/domain"
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "Diagnosis",
						"content": {
							"application/json": {
								"schema": {
									"$ref": "#/components/schemas/CertificateCheck"
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		},
		"/expiry": {
			"get": {
				"operationId": "checkExpiry",
				"summary": "Expiry summary for up to 5 domains",
				"description": "For CI jobs and inventories: served certificate expiry, domain registration expiry (RDAP) and alert lines (alerts are in Korean).",
				"parameters": [
					{
						"name": "domains",
						"in": "query",
						"required": true,
						"description": "1–5 domain names, comma-separated",
						"schema": {
							"type": "string",
							"examples": [
								"example.com,example.org"
							]
						}
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "Per-domain results",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"results": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/ExpiryResult"
											}
										},
										"checkedAt": {
											"type": "string",
											"format": "date-time"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		},
		"/security": {
			"get": {
				"operationId": "checkSecurity",
				"summary": "Web server security grade",
				"description": "TLS protocol versions (legacy 1.0/1.1 detection), security headers, HTTP→HTTPS redirect and key/signature strength. No port scanning.",
				"parameters": [
					{
						"$ref": "#/components/parameters/domain"
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "Grade and checks",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"domain": {
											"type": "string"
										},
										"grade": {
											"type": "string",
											"enum": [
												"A",
												"A-",
												"B",
												"C",
												"D"
											]
										},
										"checks": {
											"type": "array",
											"items": {
												"type": "object",
												"properties": {
													"id": {
														"type": "string"
													},
													"level": {
														"type": "string",
														"enum": [
															"pass",
															"warn",
															"fail"
														]
													},
													"detail": {
														"type": "string",
														"description": "Korean text"
													}
												}
											}
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		},
		"/explain": {
			"get": {
				"operationId": "explainTlsError",
				"summary": "Explain a TLS/SSL error message",
				"description": "Matches error text from browsers, curl/OpenSSL, Java, Python, Node.js, Go and .NET against a curated knowledge base and returns likely causes, fixes (English and Korean) and guide links.",
				"parameters": [
					{
						"name": "error",
						"in": "query",
						"required": true,
						"description": "Full error text",
						"schema": {
							"type": "string",
							"examples": [
								"PKIX path building failed"
							]
						}
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "Matches (empty when nothing matched)",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"matches": {
											"type": "array",
											"items": {
												"type": "object",
												"properties": {
													"id": {
														"type": "string"
													},
													"matched": {
														"type": "string"
													},
													"en": {
														"$ref": "#/components/schemas/Explanation"
													},
													"ko": {
														"$ref": "#/components/schemas/Explanation"
													},
													"links": {
														"type": "array",
														"items": {
															"type": "string",
															"format": "uri"
														}
													}
												}
											}
										},
										"next": {
											"type": "string"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					}
				}
			}
		},
		"/watch": {
			"post": {
				"operationId": "watchExpiry",
				"summary": "Request free daily expiry monitoring by email",
				"description": "Double opt-in: sends a confirmation email; monitoring starts only after the recipient clicks the link. Up to 5 domains per address. Use only an address the user owns.",
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "object",
								"required": [
									"email",
									"domains"
								],
								"properties": {
									"email": {
										"type": "string",
										"format": "email"
									},
									"domains": {
										"type": "array",
										"items": {
											"type": "string"
										},
										"minItems": 1,
										"maxItems": 5
									}
								}
							}
						}
					}
				},
				"responses": {
					"202": {
						"description": "Confirmation email sent",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"ok": {
											"type": "boolean"
										},
										"message": {
											"type": "string"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		},
		"/dns-info": {
			"get": {
				"operationId": "dnsInfo",
				"summary": "DNS and hosting facts for a domain",
				"description": "Nameservers with DNS provider (only when the nameserver is under the provider's own domain), A/AAAA with IP owner (ASN via Team Cymru), CNAME, MX, CAA (effective record set, RFC 8659 tree climbing), SPF/DMARC, DNSSEC (DS at the zone apex), registrar and domain expiry (RDAP).",
				"parameters": [
					{
						"$ref": "#/components/parameters/domain"
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "DNS facts",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"domain": {
											"type": "string"
										},
										"zone": {
											"type": "string"
										},
										"nameservers": {
											"type": "array",
											"items": {
												"type": "object",
												"properties": {
													"host": {
														"type": "string"
													},
													"provider": {
														"type": [
															"string",
															"null"
														]
													}
												}
											}
										},
										"dnsProvider": {
											"type": [
												"string",
												"null"
											]
										},
										"a": {
											"type": "array",
											"items": {
												"type": "object",
												"properties": {
													"ip": {
														"type": "string"
													},
													"asn": {
														"type": "integer"
													},
													"asName": {
														"type": [
															"string",
															"null"
														]
													},
													"prefix": {
														"type": "string"
													},
													"country": {
														"type": "string"
													}
												}
											}
										},
										"aaaa": {
											"type": "array",
											"items": {
												"type": "string"
											}
										},
										"cname": {
											"type": "array",
											"items": {
												"type": "string"
											}
										},
										"mx": {
											"type": "array",
											"items": {
												"type": "string"
											}
										},
										"spf": {
											"type": [
												"string",
												"null"
											]
										},
										"dmarc": {
											"type": [
												"object",
												"null"
											]
										},
										"caa": {
											"type": [
												"object",
												"null"
											],
											"properties": {
												"foundAt": {
													"type": "string"
												},
												"issue": {
													"type": "array",
													"items": {
														"type": "string"
													}
												},
												"issuewild": {
													"type": "array",
													"items": {
														"type": "string"
													}
												},
												"records": {
													"type": "array",
													"items": {
														"type": "string"
													}
												}
											}
										},
										"dnssec": {
											"type": "boolean"
										},
										"registrar": {
											"type": [
												"string",
												"null"
											]
										},
										"domainExpiry": {
											"type": [
												"string",
												"null"
											]
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		},
		"/dns": {
			"get": {
				"operationId": "dnsPropagation",
				"summary": "Compare one DNS record across resolvers",
				"description": "Measured from a Korean network: the zone's authoritative nameservers, Korean ISP resolvers (KT, SK Broadband, LG U+) and public resolvers (Cloudflare, Google, Quad9, OpenDNS). If the Korean probe is unavailable, falls back to Cloudflare and Google DoH from the edge (vantage=edge-doh). Cached 30 seconds.",
				"parameters": [
					{
						"name": "name",
						"in": "query",
						"required": true,
						"schema": {
							"type": "string",
							"examples": [
								"_acme-challenge.example.com"
							]
						}
					},
					{
						"name": "type",
						"in": "query",
						"required": true,
						"schema": {
							"type": "string",
							"enum": [
								"A",
								"AAAA",
								"CNAME",
								"TXT",
								"MX",
								"NS",
								"CAA",
								"SOA"
							]
						}
					},
					{
						"$ref": "#/components/parameters/client"
					}
				],
				"responses": {
					"200": {
						"description": "Per-resolver answers",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"name": {
											"type": "string"
										},
										"type": {
											"type": "string"
										},
										"zone": {
											"type": [
												"string",
												"null"
											]
										},
										"vantage": {
											"type": "string",
											"enum": [
												"kr-probe",
												"edge-doh"
											]
										},
										"authoritative": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/ResolverAnswer"
											}
										},
										"resolvers": {
											"type": "array",
											"items": {
												"$ref": "#/components/schemas/ResolverAnswer"
											}
										},
										"checkedAt": {
											"type": "string"
										}
									}
								}
							}
						}
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"429": {
						"$ref": "#/components/responses/RateLimited"
					}
				}
			}
		}
	},
	"components": {
		"parameters": {
			"domain": {
				"name": "domain",
				"in": "query",
				"required": true,
				"schema": {
					"type": "string",
					"examples": [
						"example.com"
					]
				}
			},
			"client": {
				"name": "client",
				"in": "query",
				"required": false,
				"description": "Optional name of your app or tool, used only for aggregate usage counts",
				"schema": {
					"type": "string"
				}
			}
		},
		"responses": {
			"Error": {
				"description": "Invalid input",
				"content": {
					"application/json": {
						"schema": {
							"type": "object",
							"properties": {
								"error": {
									"type": "string"
								}
							}
						}
					}
				}
			},
			"RateLimited": {
				"description": "More than 30 requests per minute from this IP",
				"headers": {
					"retry-after": {
						"schema": {
							"type": "integer"
						}
					}
				}
			}
		},
		"schemas": {
			"CertSummary": {
				"type": [
					"object",
					"null"
				],
				"properties": {
					"notAfter": {
						"type": "string",
						"description": "Expiry (date or date-time)"
					},
					"daysLeft": {
						"type": "integer"
					},
					"issuer": {
						"type": [
							"string",
							"null"
						]
					},
					"source": {
						"type": "string",
						"enum": [
							"served",
							"ct"
						]
					},
					"newerInCt": {
						"type": "boolean"
					},
					"ctLatest": {
						"type": [
							"object",
							"null"
						],
						"properties": {
							"notAfter": {
								"type": "string"
							},
							"issuer": {
								"type": [
									"string",
									"null"
								]
							}
						}
					}
				}
			},
			"CertificateCheck": {
				"type": "object",
				"properties": {
					"domain": {
						"type": "string"
					},
					"tls": {
						"type": "object",
						"description": "Live TLS verification from a Cloudflare PoP"
					},
					"tlsKr": {
						"type": [
							"object",
							"null"
						],
						"description": "Live TLS check from a Korean network"
					},
					"cert": {
						"$ref": "#/components/schemas/CertSummary"
					},
					"chain": {
						"type": "array",
						"items": {
							"type": "object"
						}
					},
					"revoked": {
						"type": [
							"boolean",
							"null"
						]
					},
					"incidents": {
						"type": "array",
						"items": {
							"type": "object"
						}
					},
					"checkedAt": {
						"type": "string",
						"format": "date-time"
					}
				}
			},
			"ExpiryResult": {
				"type": "object",
				"properties": {
					"domain": {
						"type": "string"
					},
					"certificate": {
						"type": [
							"object",
							"null"
						],
						"properties": {
							"notAfter": {
								"type": "string"
							},
							"daysLeft": {
								"type": "integer"
							},
							"issuer": {
								"type": [
									"string",
									"null"
								]
							},
							"source": {
								"type": "string",
								"enum": [
									"served",
									"ct"
								]
							}
						}
					},
					"servedTlsOk": {
						"type": [
							"boolean",
							"null"
						]
					},
					"domainExpiry": {
						"type": [
							"string",
							"null"
						]
					},
					"domainDaysLeft": {
						"type": [
							"integer",
							"null"
						]
					},
					"alerts": {
						"type": "array",
						"items": {
							"type": "string"
						}
					}
				}
			},
			"Explanation": {
				"type": "object",
				"properties": {
					"title": {
						"type": "string"
					},
					"causes": {
						"type": "array",
						"items": {
							"type": "string"
						}
					},
					"fixes": {
						"type": "array",
						"items": {
							"type": "string"
						}
					}
				}
			},
			"ResolverAnswer": {
				"type": "object",
				"properties": {
					"resolver": {
						"type": "string"
					},
					"ip": {
						"type": "string"
					},
					"rcode": {
						"type": "string",
						"description": "NOERROR, NXDOMAIN, SERVFAIL, REFUSED…"
					},
					"answers": {
						"type": "array",
						"items": {
							"type": "object",
							"properties": {
								"type": {
									"type": "string"
								},
								"ttl": {
									"type": "integer"
								},
								"data": {
									"type": "string"
								}
							}
						}
					},
					"ms": {
						"type": "integer"
					},
					"error": {
						"type": "string"
					}
				}
			}
		}
	}
}
