{
  "openapi": "3.1.0",
  "info": {
    "title": "Domainee API",
    "version": "1.0.0",
    "summary": "Custom domains, domain registration, and DNS diagnostics for SaaS products.",
    "description": "Domainee lets your product attach your customers' own domains to their accounts:\none call to connect a hostname, automatic SSL issuance and renewal, DNS health\nmonitoring, webhooks, and domain registration across 500+ TLDs.\n\n## Authentication\n\nEvery `/v1` endpoint except `/v1/tools/*` takes a Bearer token in the\n`Authorization` header. Two kinds work interchangeably:\n\n- **API keys** (`sk_live_…`), created at https://domainee.dev/developers\n- **OAuth access tokens** (`dmn_oat_…`), issued by the flow described in\n  the `/.well-known/oauth-authorization-server` document.\n\nBoth are workspace-scoped: a token only ever sees its own workspace's data.\n\n## Rate limits\n\nAuthenticated endpoints allow 60 requests per minute per key and answer `429`\nwith `{\"error\":\"rate_limited\"}` beyond that. The free tools are limited per IP\nat 30/minute and 500/day.\n\n## Idempotency\n\nSend an `Idempotency-Key` header on any POST to make a retry safe: the first\nresponse for a given key is replayed instead of performing the work twice.\n\n## Errors\n\nFailures return the same envelope at every status code:\n`{ \"error\": \"not_found\", \"message\": \"Domain not found\" }`.\n\nFull guides: https://domainee.dev/docs. Machine-readable index: https://domainee.dev/llms.txt.",
    "termsOfService": "https://domainee.dev/terms",
    "contact": {
      "name": "Domainee support",
      "email": "hello@domainee.dev",
      "url": "https://domainee.dev/contact"
    }
  },
  "servers": [
    {
      "url": "https://api.domainee.dev",
      "description": "Production"
    }
  ],
  "externalDocs": {
    "description": "Domainee documentation",
    "url": "https://domainee.dev/docs"
  },
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Domains",
      "description": "Connect and verify your customers' custom domains."
    },
    {
      "name": "Domain purchases",
      "description": "Search, register, renew, and manage domains bought through Domainee."
    },
    {
      "name": "DNS",
      "description": "Verify that DNS records resolve to the expected values."
    },
    {
      "name": "Webhooks",
      "description": "Subscribe to domain lifecycle events."
    },
    {
      "name": "Projects",
      "description": "Generic workspace-scoped objects."
    },
    {
      "name": "Free tools",
      "description": "Keyless diagnostic lookups. No Authorization header required."
    },
    {
      "name": "Service",
      "description": "Health and discovery endpoints."
    }
  ],
  "paths": {
    "/healthz": {
      "get": {
        "operationId": "getHealth",
        "summary": "Liveness probe.",
        "tags": [
          "Service"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "The API is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/v1/domains": {
      "get": {
        "operationId": "listDomains",
        "summary": "List connected domains.",
        "description": "Cursor-paginated and workspace-scoped. Pass `hostname` for an exact-match lookup instead of paging the whole workspace.",
        "tags": [
          "Domains"
        ],
        "parameters": [
          {
            "name": "hostname",
            "in": "query",
            "required": false,
            "description": "Exact hostname to look up. Returns at most one domain and a null `nextCursor`.",
            "schema": {
              "type": "string",
              "example": "app.acme.com"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Only return domains in this verification state.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "verified",
                "failed",
                "expired"
              ]
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The `nextCursor` from a previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Page size.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of domains.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domains": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Domain"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Null on the last page."
                    }
                  },
                  "required": [
                    "domains",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      },
      "post": {
        "operationId": "createDomain",
        "summary": "Connect a custom domain.",
        "description": "Registers the hostname, runs a preflight check, and returns the DNS records\nthe domain owner has to create. The domain stays `pending` until those records\nresolve; SSL is issued automatically once they do.\n\nRequires an active subscription on the workspace even while inside the free\ntier, so a card must be on file.",
        "tags": [
          "Domains"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hostname": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 253,
                    "description": "The customer's hostname. Normalized and validated server-side.",
                    "example": "app.acme.com"
                  },
                  "originUrl": {
                    "type": "string",
                    "format": "uri",
                    "description": "Where verified traffic should go.",
                    "example": "https://acme.vercel.app"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "proxy",
                      "redirect"
                    ],
                    "default": "proxy"
                  },
                  "keepHost": {
                    "type": "boolean"
                  },
                  "redirectWww": {
                    "type": "boolean"
                  },
                  "redirectStatus": {
                    "type": "integer",
                    "enum": [
                      301,
                      302
                    ]
                  }
                },
                "required": [
                  "hostname",
                  "originUrl"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Domain created. Follow `dnsRecords` to finish verification.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/Domain"
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PreflightWarning"
                      },
                      "description": "Non-blocking preflight notes, e.g. an existing CAA record."
                    }
                  },
                  "required": [
                    "domain"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid hostname, reserved hostname, or a blocking preflight failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreflightError"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/BillingRequired"
          },
          "409": {
            "description": "That hostname is already connected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/domains/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DomainId"
        }
      ],
      "get": {
        "operationId": "getDomain",
        "summary": "Retrieve one domain.",
        "tags": [
          "Domains"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/DomainEnvelope"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "updateDomain",
        "summary": "Update a domain's origin or routing options.",
        "description": "Only the fields you send change. The hostname itself is immutable.",
        "tags": [
          "Domains"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "originUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "proxy",
                      "redirect"
                    ]
                  },
                  "keepHost": {
                    "type": "boolean"
                  },
                  "redirectWww": {
                    "type": "boolean"
                  },
                  "redirectStatus": {
                    "type": "integer",
                    "enum": [
                      301,
                      302
                    ]
                  }
                },
                "minProperties": 1
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/DomainEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "delete": {
        "operationId": "deleteDomain",
        "summary": "Disconnect a domain.",
        "description": "Removes the edge configuration and the certificate. Not reversible.",
        "tags": [
          "Domains"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domains/{id}/check": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DomainId"
        }
      ],
      "post": {
        "operationId": "checkDomain",
        "summary": "Re-run DNS and SSL checks now.",
        "description": "Forces the monitor to refresh instead of waiting for its next pass. Use it right after telling a customer to add their records.",
        "tags": [
          "Domains"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/DomainEnvelope"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domains/{id}/instructions": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DomainId"
        }
      ],
      "get": {
        "operationId": "getConnectInstructions",
        "parameters": [
          {
            "name": "redirect_uri",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Where the customer lands after approving a Domain Connect flow at their provider, with state appended to its query string. Cloudflare accepts any URL; other providers may require the domainee.dev redirect domain declared in the templates, so when opening applyUrl in a popup you can omit it and call POST /v1/domains/{id}/check when the customer returns."
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Opaque value round-tripped through the Domain Connect redirect."
          }
        ],
        "summary": "DNS steps for the customer's actual DNS provider.",
        "description": "Fingerprints the DNS provider from the zone's public NS records and returns steps written for it: the right record type for this position and provider, the record name written the way that provider's form wants it (@ vs blank vs the full domain), where the record editor lives in its UI, and the provider-specific gotchas that silently break a connection. Also reports whether the provider supports one-click Domain Connect, in which case domainConnect.applyUrl sends the customer to approve the change at their own provider. Does live NS and Domain Connect lookups, so it is a separate endpoint rather than a field on the domain resource. Never fails: an unrecognised provider returns provider.detected=false with correct generic steps.",
        "tags": [
          "Domains"
        ],
        "responses": {
          "200": {
            "description": "Provider-aware connect instructions.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "instructions": {
                      "type": "object",
                      "properties": {
                        "hostname": {
                          "type": "string"
                        },
                        "provider": {
                          "type": "object",
                          "properties": {
                            "id": {
                              "type": "string",
                              "example": "cloudflare"
                            },
                            "name": {
                              "type": "string",
                              "example": "Cloudflare"
                            },
                            "detected": {
                              "type": "boolean"
                            }
                          }
                        },
                        "apex": {
                          "type": "boolean"
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "a",
                            "cname"
                          ]
                        },
                        "methodReason": {
                          "type": "string"
                        },
                        "records": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "type": {
                                "type": "string",
                                "enum": [
                                  "A",
                                  "CNAME"
                                ]
                              },
                              "name": {
                                "type": "string"
                              },
                              "value": {
                                "type": "string"
                              },
                              "ttl": {
                                "type": "integer"
                              }
                            }
                          }
                        },
                        "steps": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "quirks": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "dashboardUrl": {
                          "type": "string"
                        },
                        "domainConnect": {
                          "type": "object",
                          "description": "One-click setup via Domain Connect when the customer's provider supports it and has adopted Domainee's template. supported=false carries a reason instead; always render steps regardless, since coverage is far from universal.",
                          "properties": {
                            "supported": {
                              "type": "boolean"
                            },
                            "reason": {
                              "type": "string",
                              "enum": [
                                "no_discovery_record",
                                "settings_unavailable",
                                "no_sync_support",
                                "template_not_adopted",
                                "lookup_failed"
                              ]
                            },
                            "providerId": {
                              "type": "string"
                            },
                            "providerName": {
                              "type": "string"
                            },
                            "providerDisplayName": {
                              "type": "string",
                              "description": "The provider's own display name when it publishes one. Prefer it over providerName in UI."
                            },
                            "applyUrl": {
                              "type": "string",
                              "description": "Send the customer here to approve the change at their own DNS provider."
                            },
                            "width": {
                              "type": "integer"
                            },
                            "height": {
                              "type": "integer"
                            },
                            "urlControlPanel": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domains/{id}/connect-session": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DomainId"
        }
      ],
      "post": {
        "operationId": "createConnectSession",
        "summary": "Mint a browser-safe token for the embeddable widget.",
        "description": "Returns a short-lived token scoped to this one domain, safe to hand to a browser. Call it from your server with your API key, then pass the token to Domainee.mount(). The token can only read the domain, read its connect instructions, force a DNS check, and apply records with a customer-supplied DNS token; everything else returns 403, including other domains and minting another session. Tokens are signed rather than stored, so they cannot be revoked before expiry: keep ttlSeconds short. Default 3600, maximum 86400. Never send an sk_live_ key to a browser.",
        "tags": [
          "Domains"
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "ttlSeconds": {
                    "type": "integer",
                    "minimum": 60,
                    "maximum": 86400,
                    "default": 3600
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A scoped, short-lived widget token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connectSession": {
                      "type": "object",
                      "properties": {
                        "token": {
                          "type": "string"
                        },
                        "expiresAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "domainId": {
                          "type": "string"
                        },
                        "hostname": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domains/{id}/dns/apply": {
      "parameters": [
        {
          "$ref": "#/components/parameters/DomainId"
        }
      ],
      "post": {
        "operationId": "applyDnsWithToken",
        "summary": "Point a domain using the customer's own scoped DNS token.",
        "description": "Writes the records at the customer's DNS provider using a scoped API token they supply. The token is used for the request and discarded: never stored, never logged, never returned. Send it in the body, not the query string, so it stays out of access logs. Touches only conflicting A/AAAA/CNAME/ALIAS records at the hostname being pointed, leaving MX, TXT and every other name intact. On Cloudflare, records are created with proxy disabled, since an orange-clouded record prevents certificate issuance. Supported providers: cloudflare, digitalocean.",
        "tags": [
          "Domains"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": [
                      "cloudflare",
                      "digitalocean"
                    ]
                  },
                  "token": {
                    "type": "string",
                    "description": "The customer's scoped DNS API token. Cloudflare needs Zone:Zone:Read and Zone:DNS:Edit; DigitalOcean needs write scope on Domains."
                  }
                },
                "required": [
                  "provider",
                  "token"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Records written and the domain re-probed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "applied": {
                      "type": "object",
                      "properties": {
                        "provider": {
                          "type": "string"
                        },
                        "written": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        },
                        "removed": {
                          "type": "integer",
                          "description": "Conflicting records deleted to make room."
                        }
                      }
                    },
                    "domain": {
                      "$ref": "#/components/schemas/Domain"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "The provider refused the write, or we can't write to it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/domain-purchases/check": {
      "get": {
        "operationId": "checkDomainAvailability",
        "summary": "Check availability and price before buying.",
        "description": "Read-only and free. Nothing is charged and nothing is reserved.",
        "tags": [
          "Domain purchases"
        ],
        "parameters": [
          {
            "name": "hostname",
            "in": "query",
            "required": true,
            "description": "Registrable domain to quote, e.g. `acme.com`.",
            "schema": {
              "type": "string",
              "example": "acme.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Availability and the all-in price.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string"
                    },
                    "available": {
                      "type": "boolean"
                    },
                    "totalCents": {
                      "type": "integer",
                      "description": "What POST /v1/domain-purchases would charge for one year."
                    },
                    "currency": {
                      "type": "string",
                      "enum": [
                        "USD"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/domain-purchases": {
      "get": {
        "operationId": "listDomainPurchases",
        "summary": "List domain purchases.",
        "tags": [
          "Domain purchases"
        ],
        "parameters": [
          {
            "name": "hostname",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Exact-match filter."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Repeat the parameter to filter on several statuses.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string",
                "enum": [
                  "pending",
                  "completed",
                  "failed",
                  "refunded"
                ]
              }
            },
            "explode": true
          },
          {
            "name": "customerReference",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Whatever you stashed at buy time."
          },
          {
            "name": "createdAfter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive ISO date."
          },
          {
            "name": "createdBefore",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Inclusive ISO date."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of purchases.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "purchases": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DomainPurchase"
                      }
                    },
                    "nextCursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  },
                  "required": [
                    "purchases",
                    "nextCursor"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "purchaseDomain",
        "summary": "Register a domain.",
        "description": "Charges the workspace and registers the domain in one call. If the registrar\nrefuses after the charge clears, the charge is refunded automatically and the\npurchase comes back `failed`.\n\nSend `maxTotalCents` to refuse the purchase if the price moved since your quote,\nand `autoConnect` to attach the new domain to an origin without a second call.\nSend an `Idempotency-Key` — this endpoint moves money.",
        "tags": [
          "Domain purchases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "hostname": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 253,
                    "example": "acme.com"
                  },
                  "years": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10,
                    "default": 1
                  },
                  "registrant": {
                    "$ref": "#/components/schemas/Registrant"
                  },
                  "enableWhoisPrivacy": {
                    "type": "boolean",
                    "description": "Rejected with a 400 on TLDs that do not support it."
                  },
                  "autoRenew": {
                    "type": "boolean"
                  },
                  "maxTotalCents": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Abort with `price_changed` if the total would exceed this."
                  },
                  "customerReference": {
                    "type": "string",
                    "maxLength": 256
                  },
                  "autoConnect": {
                    "type": "object",
                    "description": "Connect the domain to an origin as soon as it registers.",
                    "properties": {
                      "originUrl": {
                        "type": "string",
                        "format": "uri"
                      },
                      "keepHost": {
                        "type": "boolean"
                      }
                    },
                    "required": [
                      "originUrl"
                    ]
                  }
                },
                "required": [
                  "hostname",
                  "registrant"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "$ref": "#/components/responses/PurchaseEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/BillingRequired"
          },
          "409": {
            "description": "`unavailable` — the domain was taken; `price_changed` — the total exceeded `maxTotalCents`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The registrar rejected the registration. Any charge was refunded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/domain-purchases/{id}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "get": {
        "operationId": "getDomainPurchase",
        "summary": "Retrieve one purchase.",
        "tags": [
          "Domain purchases"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/PurchaseEnvelope"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "operationId": "setDomainPurchaseAutoRenew",
        "summary": "Turn auto-renew on or off.",
        "description": "Setting `autoRenew` to false is how you cancel: the domain simply lapses at `expiresAt`.",
        "tags": [
          "Domain purchases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "autoRenew": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "autoRenew"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/PurchaseEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/details": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "get": {
        "operationId": "getDomainPurchaseDetails",
        "summary": "Retrieve a purchase with live registrar state.",
        "description": "Hits the registrar, so it is slower than `getDomainPurchase`. Use it when you need the authoritative expiry, lock, or nameserver state.",
        "tags": [
          "Domain purchases"
        ],
        "responses": {
          "200": {
            "description": "The stored purchase plus what the registrar reports right now.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "purchase": {
                      "$ref": "#/components/schemas/DomainPurchase"
                    },
                    "live": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/dns": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "get": {
        "operationId": "listDomainPurchaseDnsRecords",
        "summary": "List the registrar DNS records for a purchased domain.",
        "tags": [
          "Domain purchases"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/RegistrarDnsEnvelope"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "put": {
        "operationId": "replaceDomainPurchaseDnsRecords",
        "summary": "Replace the registrar DNS records.",
        "description": "Declarative: the set you send becomes the complete record set. Omitting a record deletes it.",
        "tags": [
          "Domain purchases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "records": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/RegistrarDnsRecord"
                    }
                  }
                },
                "required": [
                  "records"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/RegistrarDnsEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/nameservers": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "put": {
        "operationId": "setDomainPurchaseNameservers",
        "summary": "Point a purchased domain at custom nameservers.",
        "description": "Delegating away from the registrar's nameservers makes the DNS-record endpoints inoperative for that domain.",
        "tags": [
          "Domain purchases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nameservers": {
                    "type": "array",
                    "maxItems": 13,
                    "items": {
                      "type": "string",
                      "minLength": 1,
                      "maxLength": 253
                    },
                    "example": [
                      "ns1.cloudflare.com",
                      "ns2.cloudflare.com"
                    ]
                  }
                },
                "required": [
                  "nameservers"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The nameservers now on file.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string"
                    },
                    "nameservers": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/renew": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "post": {
        "operationId": "renewDomainPurchase",
        "summary": "Extend a registration.",
        "description": "Charges the workspace and pushes `expiresAt` out by `years`.",
        "tags": [
          "Domain purchases"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "years": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10
                  }
                },
                "required": [
                  "years"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/PurchaseEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/BillingRequired"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The purchase is not in a renewable state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "The registrar refused the renewal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/connect": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "post": {
        "operationId": "connectDomainPurchase",
        "summary": "Connect a purchased domain to an origin.",
        "description": "Provisions the domain on Domainee's edge and writes the DNS records at the registrar in one call. No manual DNS step, because Domainee controls both sides. The DNS write is a merge: it replaces only the routing records at the apex and www, and leaves MX, TXT, SPF, DKIM, DMARC, CAA and subdomain records in place.",
        "tags": [
          "Domain purchases"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "originUrl": {
                    "type": "string",
                    "format": "uri"
                  },
                  "keepHost": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "originUrl"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/PurchaseEnvelope"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "The purchase is not in a connectable state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/domain-purchases/{id}/auth-code": {
      "parameters": [
        {
          "$ref": "#/components/parameters/PurchaseId"
        }
      ],
      "get": {
        "operationId": "getDomainPurchaseAuthCode",
        "summary": "Get the EPP transfer code.",
        "description": "The code a customer needs to move the domain to another registrar.",
        "tags": [
          "Domain purchases"
        ],
        "responses": {
          "200": {
            "description": "The transfer authorization code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "hostname": {
                      "type": "string"
                    },
                    "authCode": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/dns/check-records-exist": {
      "post": {
        "operationId": "checkDnsRecordsExist",
        "summary": "Check that at least one record matches the expected value.",
        "description": "Resolves each name live and reports whether the expected value is among the answers. Use this for records that legitimately have siblings, such as TXT or MX.",
        "tags": [
          "DNS"
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/DnsCheck"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/DnsCheckResult"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/dns/check-records-match-exactly": {
      "post": {
        "operationId": "checkDnsRecordsMatchExactly",
        "summary": "Check that every record for a name equals the expected value.",
        "description": "Stricter than `checkDnsRecordsExist`: a stale extra A record fails the check. Use this for records that must be unique, such as a CNAME.",
        "tags": [
          "DNS"
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/DnsCheck"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/DnsCheckResult"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/webhook-endpoints": {
      "get": {
        "operationId": "listWebhookEndpoints",
        "summary": "List webhook endpoints.",
        "description": "Signing secrets are omitted here; they are shown once, at creation.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "The workspace's endpoints.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/WebhookEndpoint"
                      }
                    }
                  },
                  "required": [
                    "endpoints"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createWebhookEndpoint",
        "summary": "Create a webhook endpoint.",
        "description": "The response contains the signing secret. It is returned exactly once, so store it now.",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Where Domainee POSTs the event.",
                    "example": "https://acme.com/hooks/domainee"
                  },
                  "events": {
                    "type": "array",
                    "description": "Events to receive. An empty array subscribes to none.",
                    "items": {
                      "type": "string",
                      "enum": [
                        "domain.created",
                        "domain.verified",
                        "domain.failed",
                        "domain.expired",
                        "domain.deleted",
                        "domain.monitor_updated"
                      ]
                    },
                    "default": []
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Endpoint created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint": {
                      "$ref": "#/components/schemas/WebhookEndpoint"
                    },
                    "secret": {
                      "type": "string",
                      "description": "HMAC signing secret. Shown only in this response."
                    }
                  },
                  "required": [
                    "endpoint",
                    "secret"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/webhook-endpoints/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Webhook endpoint identifier.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "operationId": "deleteWebhookEndpoint",
        "summary": "Delete a webhook endpoint.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "$ref": "#/components/responses/Deleted"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/projects": {
      "get": {
        "operationId": "listProjects",
        "summary": "List projects.",
        "tags": [
          "Projects"
        ],
        "responses": {
          "200": {
            "description": "The workspace's projects, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "projects": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Project"
                      }
                    }
                  },
                  "required": [
                    "projects"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "operationId": "createProject",
        "summary": "Create a project.",
        "tags": [
          "Projects"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 2000
                  }
                },
                "required": [
                  "title"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Project created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/projects/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "description": "Project identifier.",
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "operationId": "getProject",
        "summary": "Retrieve one project.",
        "tags": [
          "Projects"
        ],
        "responses": {
          "200": {
            "description": "The project.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "project": {
                      "$ref": "#/components/schemas/Project"
                    }
                  },
                  "required": [
                    "project"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/tools/ssl-check": {
      "get": {
        "operationId": "toolSslCheck",
        "summary": "Returns TLS certificate details for any public hostname: subject, issuer, validity, alt names, cipher, full chain.",
        "description": "Returns TLS certificate details for any public hostname: subject, issuer, validity, alt names, cipher, full chain.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/ssl-check?host=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "required": true,
            "description": "Hostname to check. Optionally with `:port` (default 443).",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "host": "domainee.dev",
                    "port": 443,
                    "protocol": "TLSv1.3",
                    "cipher": {
                      "name": "TLS_AES_256_GCM_SHA384",
                      "version": "TLSv1.3"
                    },
                    "authorized": true,
                    "expired": false,
                    "daysUntilExpiry": 71,
                    "subject": {
                      "CN": "domainee.dev"
                    },
                    "issuer": {
                      "C": "US",
                      "O": "Let's Encrypt",
                      "CN": "E7"
                    },
                    "validFrom": "2026-03-15T08:32:14.000Z",
                    "validTo": "2026-06-13T08:32:13.000Z",
                    "altNames": [
                      "domainee.dev",
                      "*.domainee.dev"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/dns-record-lookup": {
      "get": {
        "operationId": "toolDnsRecordLookup",
        "summary": "Look up DNS records for any hostname. Returns all common record types (A, AAAA, CNAME, MX, TXT, NS, SOA) by default, or only the type you specify.",
        "description": "Look up DNS records for any hostname. Returns all common record types (A, AAAA, CNAME, MX, TXT, NS, SOA) by default, or only the type you specify.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/dns-record-lookup?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain or hostname to query.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Restrict to one record type. Defaults to all common types.",
            "schema": {
              "type": "string",
              "enum": [
                "A",
                "AAAA",
                "CNAME",
                "MX",
                "TXT",
                "NS",
                "SOA"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "records": [
                      {
                        "type": "A",
                        "values": [
                          "35.165.194.233",
                          "52.39.55.154"
                        ]
                      },
                      {
                        "type": "MX",
                        "values": [
                          "10 mail.example.com."
                        ]
                      },
                      {
                        "type": "NS",
                        "values": [
                          "abdullah.ns.cloudflare.com.",
                          "audrey.ns.cloudflare.com."
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/whois-lookup": {
      "get": {
        "operationId": "toolWhoisLookup",
        "summary": "Modern RDAP-backed WHOIS lookup. Returns registrar, status, key dates (created/updated/expires), nameservers, and registrant info where public.",
        "description": "Modern RDAP-backed WHOIS lookup. Returns registrar, status, key dates (created/updated/expires), nameservers, and registrant info where public.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/whois-lookup?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to look up.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "registrar": "Namecheap, Inc.",
                    "status": [
                      "clientTransferProhibited"
                    ],
                    "created": "2025-09-12T08:21:33.000Z",
                    "updated": "2026-03-04T11:08:12.000Z",
                    "expires": "2027-09-12T08:21:33.000Z",
                    "nameServers": [
                      "abdullah.ns.cloudflare.com",
                      "audrey.ns.cloudflare.com"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/cname-lookup": {
      "get": {
        "operationId": "toolCnameLookup",
        "summary": "Resolve a hostname's CNAME chain. Flags apex-domain misuse (apex domains can't legally have CNAME records per RFC 1034) and returns the full chain to the final A record.",
        "description": "Resolve a hostname's CNAME chain. Flags apex-domain misuse (apex domains can't legally have CNAME records per RFC 1034) and returns the full chain to the final A record.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/cname-lookup?host=www.domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "required": true,
            "description": "Hostname to resolve. Use a subdomain like `www.example.com`.",
            "schema": {
              "type": "string",
              "example": "www.domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "host": "www.domainee.dev",
                    "isApex": false,
                    "cnames": [
                      "domainee.dev."
                    ],
                    "finalIps": [
                      "35.165.194.233"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/dns-provider-lookup": {
      "get": {
        "operationId": "toolDnsProviderLookup",
        "summary": "Fingerprint the DNS provider serving a domain from its public NS records. Returns the record name written the way that provider's form expects it (@ vs blank vs the full domain), whether it can point a zone apex, where its record editor lives, and the provider-specific settings that silently break custom domain setups.",
        "description": "Fingerprint the DNS provider serving a domain from its public NS records. Returns the record name written the way that provider's form expects it (@ vs blank vs the full domain), whether it can point a zone apex, where its record editor lives, and the provider-specific settings that silently break custom domain setups.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/dns-provider-lookup?domain=example.com\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain or hostname. Subdomains are walked up to the zone that holds the NS records.",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "host": "example.com",
                    "apex": true,
                    "zone": "example.com",
                    "nameservers": [
                      "abdullah.ns.cloudflare.com",
                      "audrey.ns.cloudflare.com"
                    ],
                    "detected": true,
                    "provider": {
                      "id": "cloudflare",
                      "name": "Cloudflare",
                      "recordName": "@",
                      "apexSupport": "alias",
                      "recordEditorPath": "Select your domain > DNS > Records > Add record"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/domain-connect-checker": {
      "get": {
        "operationId": "toolDomainConnectChecker",
        "summary": "Check whether a domain's DNS provider implements the Domain Connect protocol, read live from the _domainconnect TXT record and the provider's settings endpoint. Reports the provider and whether it offers the synchronous flow (a signed redirect with no token exchanged, the one that works in practice) or only the asynchronous OAuth flow. One-click setup also needs the provider to have synced and enabled the service's template.",
        "description": "Check whether a domain's DNS provider implements the Domain Connect protocol, read live from the _domainconnect TXT record and the provider's settings endpoint. Reports the provider and whether it offers the synchronous flow (a signed redirect with no token exchanged, the one that works in practice) or only the asynchronous OAuth flow. One-click setup also needs the provider to have synced and enabled the service's template.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/domain-connect-checker?domain=example.com\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to check. The zone apex is used for discovery.",
            "schema": {
              "type": "string",
              "example": "example.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "example.com",
                    "supported": true,
                    "discoveryHost": "api.domainconnect.example-dns.com",
                    "dnsProvider": "Example DNS",
                    "providerId": "example-dns.com",
                    "flows": {
                      "synchronous": true,
                      "asynchronous": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/http-header-checker": {
      "get": {
        "operationId": "toolHttpHeaderChecker",
        "summary": "Fetch a URL and return its response headers + a security grade based on HSTS, CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy presence.",
        "description": "Fetch a URL and return its response headers + a security grade based on HSTS, CSP, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, and Permissions-Policy presence.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/http-header-checker?url=https://domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Full URL to fetch (must include scheme).",
            "schema": {
              "type": "string",
              "example": "https://domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "url": "https://domainee.dev",
                    "status": 200,
                    "statusText": "OK",
                    "headers": {
                      "server": "Caddy",
                      "content-type": "text/html"
                    },
                    "securityHeaders": [
                      {
                        "name": "strict-transport-security",
                        "present": true
                      },
                      {
                        "name": "content-security-policy",
                        "present": false
                      }
                    ],
                    "grade": "B"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/dns-propagation-checker": {
      "get": {
        "operationId": "toolDnsPropagationChecker",
        "summary": "Query the same hostname against ~10 public resolvers across the world (Cloudflare, Google, Quad9, OpenDNS, etc.) and report which ones see the same answer. Useful right after a DNS change.",
        "description": "Query the same hostname against ~10 public resolvers across the world (Cloudflare, Google, Quad9, OpenDNS, etc.) and report which ones see the same answer. Useful right after a DNS change.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/dns-propagation-checker?host=domainee.dev&type=A\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "host",
            "in": "query",
            "required": true,
            "description": "Hostname to query across resolvers.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Record type to check. Defaults to A.",
            "schema": {
              "type": "string",
              "enum": [
                "A",
                "AAAA",
                "CNAME",
                "MX",
                "TXT",
                "NS"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "type": "A",
                    "consistent": true,
                    "results": [
                      {
                        "resolver": "Cloudflare (1.1.1.1)",
                        "values": [
                          "35.165.194.233"
                        ]
                      },
                      {
                        "resolver": "Google (8.8.8.8)",
                        "values": [
                          "35.165.194.233"
                        ]
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/redirect-checker": {
      "get": {
        "operationId": "toolRedirectChecker",
        "summary": "Follow a URL's redirect chain and return every hop with status code, response time, and the final destination URL. Stops at 20 hops to prevent loops.",
        "description": "Follow a URL's redirect chain and return every hop with status code, response time, and the final destination URL. Stops at 20 hops to prevent loops.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/redirect-checker?url=https://domainee.com\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "Starting URL.",
            "schema": {
              "type": "string",
              "example": "https://domainee.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "hops": [
                      {
                        "url": "https://domainee.com/",
                        "status": 301,
                        "statusText": "Moved Permanently",
                        "responseTimeMs": 42
                      },
                      {
                        "url": "https://domainee.dev/",
                        "status": 200,
                        "statusText": "OK",
                        "responseTimeMs": 65
                      }
                    ],
                    "finalUrl": "https://domainee.dev/"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/spf-record-checker": {
      "get": {
        "operationId": "toolSpfRecordChecker",
        "summary": "Look up the SPF record for a domain, validate syntax, and count void/total DNS lookups against the RFC 7208 limit of 10. Flags common issues.",
        "description": "Look up the SPF record for a domain, validate syntax, and count void/total DNS lookups against the RFC 7208 limit of 10. Flags common issues.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/spf-record-checker?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to check the SPF record for.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "record": "v=spf1 include:_spf.google.com ~all",
                    "mechanisms": [
                      {
                        "kind": "include",
                        "value": "_spf.google.com"
                      },
                      {
                        "kind": "all",
                        "qualifier": "~"
                      }
                    ],
                    "lookupCount": 4,
                    "withinLimit": true,
                    "issues": []
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/domain-age-checker": {
      "get": {
        "operationId": "toolDomainAgeChecker",
        "summary": "RDAP-backed lookup that returns a domain's registration date, age in days + years, last-updated date, and expiration date.",
        "description": "RDAP-backed lookup that returns a domain's registration date, age in days + years, last-updated date, and expiration date.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/domain-age-checker?domain=google.com\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to check.",
            "schema": {
              "type": "string",
              "example": "google.com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "google.com",
                    "created": "1997-09-15T04:00:00.000Z",
                    "updated": "2025-09-09T15:39:04.000Z",
                    "expires": "2028-09-14T04:00:00.000Z",
                    "ageDays": 10481,
                    "ageYears": 28.7
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/subdomain-finder": {
      "get": {
        "operationId": "toolSubdomainFinder",
        "summary": "Enumerate subdomains for a target domain by querying Certificate Transparency logs (crt.sh) and DNS resolution. Returns deduplicated, sorted list.",
        "description": "Enumerate subdomains for a target domain by querying Certificate Transparency logs (crt.sh) and DNS resolution. Returns deduplicated, sorted list.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/subdomain-finder?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Apex domain to enumerate subdomains for.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "subdomains": [
                      "api.domainee.dev",
                      "edge.domainee.dev",
                      "mcp.domainee.dev",
                      "www.domainee.dev"
                    ],
                    "count": 4,
                    "source": "certificate-transparency"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/reverse-ip-lookup": {
      "get": {
        "operationId": "toolReverseIpLookup",
        "summary": "Resolve PTR (reverse DNS) records for an IP address, and list other domains observed on the same address. `hostnames` is the PTR answer, which is one or more names the IP's operator published; it is never a list of the sites hosted there, because DNS cannot produce one. `sharedHosts` is that separate list, from an observed-hostname corpus, and is null when no co-hosting source is configured. Private and reserved IPs are rejected.",
        "description": "Resolve PTR (reverse DNS) records for an IP address, and list other domains observed on the same address. `hostnames` is the PTR answer, which is one or more names the IP's operator published; it is never a list of the sites hosted there, because DNS cannot produce one. `sharedHosts` is that separate list, from an observed-hostname corpus, and is null when no co-hosting source is configured. Private and reserved IPs are rejected.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/reverse-ip-lookup?ip=8.8.8.8\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "ip",
            "in": "query",
            "required": true,
            "description": "IPv4 or IPv6 address.",
            "schema": {
              "type": "string",
              "example": "8.8.8.8"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "ip": "8.8.8.8",
                    "hostnames": [
                      "dns.google"
                    ],
                    "sharedHosts": null,
                    "sharedHostsStatus": "unavailable",
                    "sharedHostsNote": "No co-hosting data source is configured, so this result is the PTR record only."
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/dmarc-record-checker": {
      "get": {
        "operationId": "toolDmarcRecordChecker",
        "summary": "Look up the DMARC record at _dmarc.<domain>, parse the policy (`p`), subdomain policy (`sp`), alignment, reporting addresses (`rua`/`ruf`), and percentage. Flags issues like missing policy or too-permissive settings.",
        "description": "Look up the DMARC record at _dmarc.<domain>, parse the policy (`p`), subdomain policy (`sp`), alignment, reporting addresses (`rua`/`ruf`), and percentage. Flags issues like missing policy or too-permissive settings.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/dmarc-record-checker?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to check DMARC for.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "record": "v=DMARC1; p=none;",
                    "tags": {
                      "v": "DMARC1",
                      "p": "none"
                    },
                    "issues": [
                      {
                        "level": "warning",
                        "message": "Policy is `none` — no enforcement."
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/txt-record-lookup": {
      "get": {
        "operationId": "toolTxtRecordLookup",
        "summary": "Fetch all TXT records on a domain and classify them: SPF, DKIM, DMARC, BIMI, verification tokens (Google, Microsoft, Atlassian, etc.), or general.",
        "description": "Fetch all TXT records on a domain and classify them: SPF, DKIM, DMARC, BIMI, verification tokens (Google, Microsoft, Atlassian, etc.), or general.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/txt-record-lookup?domain=domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain to fetch TXT records for.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "count": 3,
                    "records": [
                      {
                        "value": "v=spf1 include:_spf.google.com ~all",
                        "classification": "SPF"
                      },
                      {
                        "value": "google-site-verification=...",
                        "classification": "verification"
                      },
                      {
                        "value": "MS=ms123456",
                        "classification": "verification"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/website-status-checker": {
      "get": {
        "operationId": "toolWebsiteStatusChecker",
        "summary": "Issue a HEAD/GET to a URL and report whether it's up, the HTTP status, response time in ms, final URL after redirects, and basic SSL info.",
        "description": "Issue a HEAD/GET to a URL and report whether it's up, the HTTP status, response time in ms, final URL after redirects, and basic SSL info.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/website-status-checker?url=https://domainee.dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "description": "URL to check (include scheme).",
            "schema": {
              "type": "string",
              "example": "https://domainee.dev"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "url": "https://domainee.dev",
                    "up": true,
                    "status": 200,
                    "statusText": "OK",
                    "responseTimeMs": 84,
                    "finalUrl": "https://domainee.dev/"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/dkim-record-checker": {
      "get": {
        "operationId": "toolDkimRecordChecker",
        "summary": "Look up the DKIM record at <selector>._domainkey.<domain>, parse the public key, key type (rsa/ed25519), and any issues. Validates against common provider conventions (Google `google`, Resend, Mailgun `mxvault`, etc.).",
        "description": "Look up the DKIM record at <selector>._domainkey.<domain>, parse the public key, key type (rsa/ed25519), and any issues. Validates against common provider conventions (Google `google`, Resend, Mailgun `mxvault`, etc.).\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/dkim-record-checker?domain=domainee.dev&selector=google\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "domain",
            "in": "query",
            "required": true,
            "description": "Domain whose DKIM you want to check.",
            "schema": {
              "type": "string",
              "example": "domainee.dev"
            }
          },
          {
            "name": "selector",
            "in": "query",
            "required": true,
            "description": "DKIM selector to look up. Common values: `google`, `k1`, `mxvault`, `selector1`, `s1`. Must be `[a-z0-9_-]+`.",
            "schema": {
              "type": "string",
              "example": "google"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "domain": "domainee.dev",
                    "selector": "google",
                    "record": "v=DKIM1;k=rsa;p=MIIBI...AB",
                    "keyType": "rsa",
                    "keyBits": 2048,
                    "issues": []
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    },
    "/v1/tools/domain-availability-checker": {
      "get": {
        "operationId": "toolDomainAvailabilityChecker",
        "summary": "Check availability of a name across one or more TLDs. Uses DNS + RDAP fallback. Returns per-TLD availability with caveats (registrar lock, premium, etc.) where known.",
        "description": "Check availability of a name across one or more TLDs. Uses DNS + RDAP fallback. Returns per-TLD availability with caveats (registrar lock, premium, etc.) where known.\n\nFree and keyless: no Authorization header, CORS enabled for browser callers.\nRate limited per IP at 30 requests/minute and 500/day; the\n`x-ratelimit-remaining-minute` and `x-ratelimit-remaining-day` response\nheaders report what is left.\n\nExample: `curl -s \"https://api.domainee.dev/v1/tools/domain-availability-checker?name=mybrand&tlds=com&tlds=io&tlds=dev\" | jq`",
        "tags": [
          "Free tools"
        ],
        "security": [],
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": true,
            "description": "The bare name (without TLD), e.g. `mybrand`.",
            "schema": {
              "type": "string",
              "example": "mybrand"
            }
          },
          {
            "name": "tlds",
            "in": "query",
            "required": false,
            "description": "Optional repeatable parameter: `?tlds=com&tlds=io&tlds=dev`. Defaults to a standard SaaS set when omitted.",
            "schema": {
              "type": "string",
              "example": "com"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Lookup completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ToolResult"
                },
                "example": {
                  "ok": true,
                  "data": {
                    "name": "mybrand",
                    "results": [
                      {
                        "tld": "com",
                        "available": false
                      },
                      {
                        "tld": "io",
                        "available": true
                      },
                      {
                        "tld": "dev",
                        "available": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ToolError"
          },
          "429": {
            "$ref": "#/components/responses/ToolError"
          },
          "502": {
            "$ref": "#/components/responses/ToolError"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key (`sk_live_…`) from https://domainee.dev/developers or an OAuth access token (`dmn_oat_…`). Both are workspace-scoped."
      }
    },
    "parameters": {
      "DomainId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Domain identifier returned by `createDomain`.",
        "schema": {
          "type": "string"
        }
      },
      "PurchaseId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Purchase identifier returned by `purchaseDomain`.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Any unique string. Retrying with the same key replays the first response instead of repeating the work.",
        "schema": {
          "type": "string"
        }
      }
    },
    "requestBodies": {
      "DnsCheck": {
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "records": {
                  "type": "array",
                  "minItems": 1,
                  "maxItems": 50,
                  "items": {
                    "type": "object",
                    "properties": {
                      "address": {
                        "type": "string",
                        "description": "The name to resolve.",
                        "example": "app.acme.com"
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "a",
                          "aaaa",
                          "cname",
                          "mx",
                          "txt",
                          "ns",
                          "caa"
                        ]
                      },
                      "match_against": {
                        "type": "string",
                        "description": "The value you expect. Compared case-insensitively, trailing dot ignored.",
                        "example": "edge.domainee.dev"
                      }
                    },
                    "required": [
                      "address",
                      "type",
                      "match_against"
                    ]
                  }
                }
              },
              "required": [
                "records"
              ]
            }
          }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, malformed, revoked, or expired Bearer token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "The request body or query failed validation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such object in this workspace.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BillingRequired": {
        "description": "The workspace has no active subscription or the charge failed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "RateLimited": {
        "description": "More than 60 requests in a minute for this key.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Deleted": {
        "description": "Deleted.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "deleted": {
                  "type": "boolean"
                }
              },
              "required": [
                "deleted"
              ]
            }
          }
        }
      },
      "DomainEnvelope": {
        "description": "The domain.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "domain": {
                  "$ref": "#/components/schemas/Domain"
                }
              },
              "required": [
                "domain"
              ]
            }
          }
        }
      },
      "PurchaseEnvelope": {
        "description": "The purchase.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "purchase": {
                  "$ref": "#/components/schemas/DomainPurchase"
                }
              },
              "required": [
                "purchase"
              ]
            }
          }
        }
      },
      "RegistrarDnsEnvelope": {
        "description": "The records currently held at the registrar.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "hostname": {
                  "type": "string"
                },
                "records": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/RegistrarDnsRecord"
                  }
                }
              },
              "required": [
                "hostname",
                "records"
              ]
            }
          }
        }
      },
      "DnsCheckResult": {
        "description": "One result per submitted record, in the order they were sent.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "records": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "address": {
                        "type": "string"
                      },
                      "type": {
                        "type": "string"
                      },
                      "match_against": {
                        "type": "string"
                      },
                      "match": {
                        "type": "boolean",
                        "description": "Whether the check passed."
                      },
                      "actual_values": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "What actually resolved. Empty when the lookup failed."
                      }
                    },
                    "required": [
                      "address",
                      "type",
                      "match_against",
                      "match",
                      "actual_values"
                    ]
                  }
                }
              },
              "required": [
                "records"
              ]
            }
          }
        }
      },
      "ToolError": {
        "description": "The lookup could not be completed.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ToolError"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "The error envelope used by every authenticated endpoint.",
        "properties": {
          "error": {
            "type": "string",
            "description": "Stable machine-readable code.",
            "example": "not_found"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation."
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "PreflightError": {
        "type": "object",
        "description": "A rejected domain creation. `warnings` lists the specific DNS or CAA problems found.",
        "properties": {
          "error": {
            "type": "string",
            "example": "preflight_failed"
          },
          "message": {
            "type": "string"
          },
          "warnings": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PreflightWarning"
            }
          }
        },
        "required": [
          "error",
          "message"
        ]
      },
      "PreflightWarning": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "caa_blocks_lets_encrypt",
              "dns_unresolvable",
              "origin_unreachable",
              "origin_ssrf_blocked"
            ]
          },
          "message": {
            "type": "string"
          },
          "caaRecords": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present on `caa_blocks_lets_encrypt`."
          },
          "details": {
            "type": "string",
            "description": "May be present on `origin_unreachable`."
          },
          "resolvedIps": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Present on `origin_ssrf_blocked`."
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "ToolResult": {
        "type": "object",
        "description": "The envelope every free tool returns. `data` is tool-specific.",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              true
            ]
          },
          "data": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": [
          "ok",
          "data"
        ]
      },
      "ToolError": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "enum": [
              false
            ]
          },
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "example": "unknown_tool"
              },
              "message": {
                "type": "string"
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        },
        "required": [
          "ok",
          "error"
        ]
      },
      "DnsRecordInstruction": {
        "type": "object",
        "description": "A record the domain owner must create for verification to pass.",
        "properties": {
          "name": {
            "type": "string",
            "example": "app.acme.com"
          },
          "value": {
            "type": "string",
            "example": "edge.domainee.dev"
          },
          "type": {
            "type": "string",
            "example": "CNAME"
          },
          "purpose": {
            "type": "string",
            "example": "Traffic Routing"
          }
        },
        "required": [
          "name",
          "value",
          "type"
        ]
      },
      "DnsRecordSet": {
        "type": "object",
        "description": "One way of pointing the hostname at the edge. Every record in `records` must be created for the set to work.",
        "properties": {
          "method": {
            "type": "string",
            "enum": [
              "cname",
              "a"
            ],
            "description": "`cname` works wherever the provider allows a CNAME at this position. `a` is for apex/root domains on providers with no ALIAS or ANAME support."
          },
          "label": {
            "type": "string",
            "example": "A records"
          },
          "recommended": {
            "type": "boolean"
          },
          "note": {
            "type": "string"
          },
          "records": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DnsRecordInstruction"
            }
          }
        },
        "required": [
          "method",
          "label",
          "recommended",
          "records"
        ]
      },
      "Domain": {
        "type": "object",
        "description": "A customer hostname connected to one of your origins.",
        "properties": {
          "id": {
            "type": "string",
            "description": "Domainee identifier.",
            "example": "dom_9f2c"
          },
          "workspaceId": {
            "type": "string",
            "description": "Workspace the domain belongs to."
          },
          "hostname": {
            "type": "string",
            "example": "app.acme.com"
          },
          "originUrl": {
            "type": "string",
            "format": "uri",
            "description": "Where verified traffic is sent.",
            "example": "https://acme.vercel.app"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Opaque key/value bag echoed back on reads and webhooks."
          },
          "mode": {
            "type": "string",
            "enum": [
              "proxy",
              "redirect"
            ],
            "description": "`proxy` serves the origin under the custom hostname; `redirect` sends a 301/302."
          },
          "keepHost": {
            "type": "boolean",
            "description": "Forward the original Host header to the origin instead of rewriting it."
          },
          "redirectWww": {
            "type": "boolean",
            "description": "Also answer for the www. variant."
          },
          "redirectStatus": {
            "type": "integer",
            "enum": [
              301,
              302
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "verified",
              "failed",
              "expired"
            ],
            "description": "Verification state. Traffic only flows once `verified`."
          },
          "dnsRecords": {
            "type": "array",
            "description": "The records the domain owner must create for verification to pass. Always the single CNAME. Unchanged and safe to keep rendering as-is; read `dnsRecordOptions` if you want to offer the apex A-record path.",
            "items": {
              "$ref": "#/components/schemas/DnsRecordInstruction"
            }
          },
          "dnsRecordOptions": {
            "type": "array",
            "description": "Every supported way to point this hostname at the edge, recommended first — take `[0]` to get the right one. For a subdomain that is the `cname` set. For an apex it is the `a` set: a root domain cannot hold a CNAME, and the ALIAS/ANAME/flattening substitutes all pin the name to a single region with no failover, whereas the anycast A records keep every region.",
            "items": {
              "$ref": "#/components/schemas/DnsRecordSet"
            }
          },
          "verificationToken": {
            "type": "string"
          },
          "verifiedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "lastCheckedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "isResolving": {
            "type": "boolean",
            "description": "The hostname resolves in public DNS."
          },
          "pointsToEdge": {
            "type": "boolean",
            "description": "It resolves to Domainee's edge."
          },
          "dnsPointedAt": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the hostname currently resolves to."
          },
          "sslActiveFrom": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sslActiveUntil": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "monitorStatus": {
            "type": "string",
            "enum": [
              "unknown",
              "dns_not_resolving",
              "dns_incorrect",
              "pending_ssl",
              "active_ssl",
              "target_not_loading",
              "ssl_failed",
              "ssl_expired"
            ],
            "description": "Live health, refreshed by the DNS monitor and by POST /v1/domains/{id}/check."
          },
          "monitorMessage": {
            "type": [
              "string",
              "null"
            ]
          },
          "lastMonitoredAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "hostname",
          "originUrl",
          "status",
          "createdAt"
        ]
      },
      "DomainPurchase": {
        "type": "object",
        "description": "A domain registered through Domainee on the customer's behalf.",
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "hostname": {
            "type": "string",
            "example": "acme.com"
          },
          "years": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10
          },
          "wholesaleCents": {
            "type": "integer",
            "description": "Registrar cost at purchase time."
          },
          "feeCents": {
            "type": "integer",
            "description": "Domainee's per-purchase fee."
          },
          "totalCents": {
            "type": "integer",
            "description": "What the workspace was charged."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ]
          },
          "registrar": {
            "type": "string",
            "enum": [
              "namecheap"
            ]
          },
          "registrarDomainId": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "completed",
              "failed",
              "refunded"
            ],
            "description": "`pending` means the charge cleared but the registration is not confirmed yet; a failed registration is refunded automatically."
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          },
          "registrant": {
            "type": "object",
            "description": "Minimal owner snapshot. The registrar remains the source of truth.",
            "properties": {
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              },
              "email": {
                "type": "string",
                "format": "email"
              },
              "country": {
                "type": "string",
                "description": "ISO 3166-1 alpha-2."
              }
            }
          },
          "whoisPrivacyEnabled": {
            "type": "boolean"
          },
          "autoRenew": {
            "type": "boolean"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "connectedDomainId": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set when the purchase was auto-connected to a /v1/domains entry."
          },
          "customerReference": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque caller-supplied reference, echoed on reads and webhooks."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "hostname",
          "years",
          "status",
          "createdAt"
        ]
      },
      "Registrant": {
        "type": "object",
        "description": "ICANN-required owner contact. Sent to the registrar verbatim.",
        "properties": {
          "firstName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "lastName": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string",
            "pattern": "^\\+\\d{1,3}\\.\\d{4,15}$",
            "description": "E.164 with a dot after the country code.",
            "example": "+1.5551234567"
          },
          "address1": {
            "type": "string",
            "minLength": 1,
            "maxLength": 128
          },
          "address2": {
            "type": "string",
            "maxLength": 128
          },
          "city": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "stateOrProvince": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "postalCode": {
            "type": "string",
            "minLength": 1,
            "maxLength": 20
          },
          "country": {
            "type": "string",
            "minLength": 2,
            "maxLength": 2,
            "description": "ISO 3166-1 alpha-2."
          },
          "organization": {
            "type": "string",
            "maxLength": 128
          }
        },
        "required": [
          "firstName",
          "lastName",
          "email",
          "phone",
          "address1",
          "city",
          "stateOrProvince",
          "postalCode",
          "country"
        ]
      },
      "RegistrarDnsRecord": {
        "type": "object",
        "description": "A DNS record held at the registrar for a purchased domain.",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "A",
              "AAAA",
              "CNAME",
              "MX",
              "TXT",
              "NS",
              "SRV",
              "URL",
              "URL301",
              "FRAME"
            ]
          },
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Subdomain label; `@` for the apex.",
            "example": "@"
          },
          "value": {
            "type": "string",
            "maxLength": 2048
          },
          "ttl": {
            "type": "integer",
            "minimum": 60,
            "maximum": 86400
          },
          "priority": {
            "type": "integer",
            "minimum": 0,
            "maximum": 65535,
            "description": "MX/SRV only."
          }
        },
        "required": [
          "type",
          "name",
          "value"
        ]
      },
      "WebhookEndpoint": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "domain.created",
                "domain.verified",
                "domain.failed",
                "domain.expired",
                "domain.deleted",
                "domain.monitor_updated"
              ]
            }
          },
          "enabled": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "url",
          "events"
        ]
      },
      "Project": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "createdBy": {
            "type": "string",
            "description": "`apikey:<id>` when created through the API."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "active",
              "archived"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "workspaceId",
          "title",
          "status"
        ]
      }
    }
  }
}