{
  "openapi": "3.1.0",
  "info": {
    "title": "X Mailer API",
    "version": "1.0.0",
    "description": "Start a purchase of X Mailer or the X Proxy, and read the site as Markdown. No key is needed for either.",
    "contact": {
      "email": "support@xmailer.to",
      "url": "https://xmailer.to/contact"
    }
  },
  "externalDocs": {
    "url": "https://xmailer.to/developers"
  },
  "servers": [
    {
      "url": "https://xmailer.to"
    }
  ],
  "tags": [
    {
      "name": "checkout",
      "description": "Start a purchase, paid in crypto through NOWPayments."
    },
    {
      "name": "markdown",
      "description": "The pages of the site as Markdown, for language models and agents."
    }
  ],
  "paths": {
    "/api/checkout": {
      "post": {
        "tags": [
          "checkout"
        ],
        "operationId": "createCheckout",
        "summary": "Start a purchase",
        "description": "Creates an order and a NOWPayments invoice for one plan and option, priced by the server. Open the returned invoiceUrl to pay. Once the payment clears, the installer link and licence (or the proxy details) are emailed to the address given. Limited to ten attempts an hour from one client address, counting failed ones.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                }
              }
            }
          },
          "400": {
            "description": "The body is not JSON, or names an unknown plan or option, or an invalid email or address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts from this client address in the last hour.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The server is not configured to take payments.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "502": {
            "description": "NOWPayments could not create the invoice. Try again shortly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": [
          "markdown"
        ],
        "operationId": "getLlmsTxt",
        "summary": "Index of the site for language models",
        "description": "Every public page and guide, each linked at its Markdown address (llmstxt.org).",
        "responses": {
          "200": {
            "description": "The index.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/index.md": {
      "get": {
        "tags": [
          "markdown"
        ],
        "operationId": "getHomeMarkdown",
        "summary": "The home page as Markdown",
        "responses": {
          "200": {
            "description": "The page.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/{page}.md": {
      "get": {
        "tags": [
          "markdown"
        ],
        "operationId": "getPageMarkdown",
        "summary": "A page as Markdown",
        "description": "Any page, as Markdown with a YAML front matter block of title, description and url. Requesting the page address itself with `Accept: text/markdown` returns the same.",
        "parameters": [
          {
            "name": "page",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
            },
            "example": "pricing"
          }
        ],
        "responses": {
          "200": {
            "description": "The page.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "There is no such page.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/blog/{slug}.md": {
      "get": {
        "tags": [
          "markdown"
        ],
        "operationId": "getPostMarkdown",
        "summary": "A guide as Markdown",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The guide.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "There is no such guide.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "CheckoutRequest": {
        "type": "object",
        "required": [
          "plan",
          "option",
          "email"
        ],
        "properties": {
          "plan": {
            "type": "string",
            "enum": [
              "mailer",
              "bundle",
              "proxy"
            ]
          },
          "option": {
            "type": "string",
            "enum": [
              "lifetime",
              "monthly",
              "rotate-per-email",
              "rotate-10min"
            ]
          },
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254,
            "description": "Where the receipt and the product are sent."
          },
          "whitelistIp": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional, for proxy and bundle plans: one IPv4 or IPv6 address the proxy should accept connections from. Ignored for other plans."
          }
        },
        "oneOf": [
          {
            "title": "X Mailer — One-year licence",
            "description": "$75, covers 365 days.",
            "properties": {
              "plan": {
                "const": "mailer"
              },
              "option": {
                "const": "lifetime"
              }
            }
          },
          {
            "title": "X Mailer + Proxy — The app, plus a first month rotating every 10 minutes",
            "description": "$120, covers 30 days.",
            "properties": {
              "plan": {
                "const": "bundle"
              },
              "option": {
                "const": "monthly"
              }
            }
          },
          {
            "title": "X Mailer + Proxy — The app, plus a first month rotating on every request",
            "description": "$199, covers 30 days.",
            "properties": {
              "plan": {
                "const": "bundle"
              },
              "option": {
                "const": "rotate-per-email"
              }
            }
          },
          {
            "title": "Proxy only — Rotating every 10 minutes",
            "description": "$100, covers 30 days.",
            "properties": {
              "plan": {
                "const": "proxy"
              },
              "option": {
                "const": "rotate-10min"
              }
            }
          },
          {
            "title": "Proxy only — Rotating on every request",
            "description": "$180, covers 30 days.",
            "properties": {
              "plan": {
                "const": "proxy"
              },
              "option": {
                "const": "rotate-per-email"
              }
            }
          }
        ]
      },
      "CheckoutResponse": {
        "type": "object",
        "required": [
          "orderId",
          "invoiceUrl"
        ],
        "properties": {
          "orderId": {
            "type": "string",
            "pattern": "^XM-[0-9A-Z]{16}$"
          },
          "invoiceUrl": {
            "type": "string",
            "format": "uri",
            "description": "The NOWPayments page where the order is paid."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "description": "A message that can be shown to the buyer."
          }
        }
      }
    }
  }
}