{
  "openapi": "3.1.0",
  "info": {
    "title": "CryptoVpsHosting Agent API",
    "version": "1.0.0",
    "description": "REST surface for AI agents and autonomous clients to discover, buy, and manage offshore VPS, dedicated servers, and domain names on cryptovpshosting.com. No KYC at any step. Crypto-only payment to an internal balance (bonus from $100, up to +70%). Current auth model: session cookie + CSRF (identical to web flow). A Bearer-token endpoint is planned. The public availability endpoint /domain-check-api.php requires no authentication.",
    "contact": {"url": "https://cryptovpshosting.com/agents"},
    "license": {"name": "Proprietary"},
    "termsOfService": "https://cryptovpshosting.com/terms-of-service"
  },
  "servers": [{"url": "https://cryptovpshosting.com"}],
  "components": {
    "securitySchemes": {
      "SessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "PHPSESSID",
        "description": "Issued by GET /csrf.php. Persist across calls. Pair with the _token CSRF value (body or X-CSRF-Token header) on every POST."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["ok", "error"],
        "properties": {
          "ok": {"type": "boolean", "const": false},
          "error": {"type": "string", "description": "Machine-readable code (e.g. 'auth_required', 'insufficient_balance', 'bad_credentials')"},
          "msg":   {"type": "string", "description": "Human-readable message (optional)"}
        }
      },
      "TopupCreateRequest": {
        "type": "object",
        "required": ["action", "amount", "coin", "_token"],
        "properties": {
          "action":  {"type": "string", "const": "create"},
          "amount":  {
            "type": "number",
            "minimum": 30,
            "maximum": 10000,
            "description": "USD amount to credit (excluding bonus). Hard floor $30, hard ceiling $10,000 — server-enforced. Tampered values are rejected with `{ok:false, error:'amount_too_low'}` or `{ok:false, error:'amount_too_high'}`. Do NOT rely on client-side validation."
          },
          "coin":    {"type": "string", "description": "Coin code from x-coins (BTC, XMR, USDCETH, USDTTRC, …)."},
          "_token":  {"type": "string", "description": "CSRF token (from GET /csrf.php) — body field or X-CSRF-Token header."}
        }
      },
      "DomainResult": {
        "type": "object",
        "properties": {
          "domain":       {"type": "string", "example": "mybrand.com"},
          "tld":          {"type": "string", "example": "com"},
          "available":    {"type": ["boolean", "null"], "description": "true=free, false=taken, null=upstream error"},
          "premium":      {"type": "boolean"},
          "price_usd":    {"type": ["number", "null"]},
          "market_usd":   {"type": ["number", "null"]},
          "discount_pct": {"type": ["integer", "null"]},
          "badge":        {"type": ["string", "null"], "example": "BEST DEAL"},
          "featured":     {"type": "boolean"},
          "tagline":      {"type": ["string", "null"]},
          "error":        {"type": ["string", "null"]}
        }
      }
    }
  },
  "paths": {
    "/domain-check-api.php": {
      "get": {
        "summary": "Live availability + retail/market price across our TLDs",
        "description": "Public, no auth, Redis-cached 1 hour. Pass `q=name.fr` to surface the .fr result first (even if it's a tier-2 TLD). Per-TLD upstream errors are isolated so one slow registry doesn't blank the page. If literally every TLD failed the same way, the response carries `service_error` at the top level.",
        "parameters": [
          {"name": "q",    "in": "query", "required": true,  "schema": {"type": "string", "maxLength": 63}, "description": "SLD or full domain (e.g. `mybrand` or `mybrand.io`). Protocol/www/trailing-slash are stripped automatically.", "example": "mybrand"},
          {"name": "tier", "in": "query", "required": false, "schema": {"type": "string", "enum": ["1", "2", "all"], "default": "1"}, "description": "1 = popular TLDs (12), 2 = niche TLDs (14), all = both (26)."}
        ],
        "responses": {
          "200": {
            "description": "Availability + pricing results",
            "content": {"application/json": {"example": {
              "ok": true, "query": "mybrand", "tier": "1",
              "results": [
                {"domain": "mybrand.com", "tld": "com", "available": true, "premium": false, "price_usd": 9.99, "market_usd": 15.98, "discount_pct": 37, "badge": "BEST DEAL", "featured": true, "tagline": "The classic, universally recognized", "error": null},
                {"domain": "mybrand.io",  "tld": "io",  "available": true, "premium": false, "price_usd": 28.99, "market_usd": 46.98, "discount_pct": 38, "badge": "HOT", "featured": false, "tagline": "Tech / startup default", "error": null}
              ],
              "cache": "miss", "service_error": null, "pricelist_loaded": 26
            }}}
          },
          "400": {"description": "Invalid query", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}
        }
      }
    },
    "/csrf.php": {
      "get": {
        "summary": "Issue a session cookie + CSRF token",
        "description": "Required before any POST. Sets `PHPSESSID` cookie. Persist both the cookie and the returned `csrf` value.",
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"example": {"csrf": "a1b2c3d4...64hex"}}}}
        }
      }
    },
    "/auth-api.php": {
      "post": {
        "summary": "Sign up, sign in, or sign out",
        "security": [{"SessionCookie": []}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"example": "action=signup&email=agent@example.com&password=...&password_confirm=...&_token=<csrf>"}}},
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "redirect": "/account"}}}},
          "400": {"description": "Bad input", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}},
          "403": {"description": "Invalid CSRF token"}
        }
      }
    },
    "/me.php": {
      "get": {
        "summary": "Probe authentication state",
        "security": [{"SessionCookie": []}],
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"example": {"ok": true, "logged_in": true, "email": "agent@example.com", "balance": 130.0, "id": 42}}}}
        }
      }
    },
    "/topup-api.php": {
      "post": {
        "summary": "Create or cancel a crypto top-up invoice",
        "description": "`action=create`: minimum amount $30 USD, maximum $10,000 USD — server-enforced. Below-min returns `{ok:false, error:'amount_too_low', min:30}`; above-max returns `{ok:false, error:'amount_too_high', max:10000}`. Both are HTTP 200 (the `ok` flag carries success). Note: when the kill-switch is on (TOPUP_CREDIT_ENABLED=false), a successful on-chain payment still flips the invoice to `confirmed` for accounting, but the balance is NOT credited and `/account?tab=billing` + `/pay/<ref>` surface the row as 'error' with refund instructions.",
        "security": [{"SessionCookie": []}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {
          "schema": {"$ref": "#/components/schemas/TopupCreateRequest"},
          "examples": {
            "create": {"value": "action=create&amount=100&coin=XMR&_token=<csrf>"},
            "cancel": {"value": "action=cancel&order_ref=NVABCD1234&_token=<csrf>"}
          }
        }}},
        "responses": {
          "200": {"description": "OK or bounds violation (check `ok`)", "content": {"application/json": {"examples": {
            "ok":              {"value": {"ok": true, "order_ref": "NVABCD1234", "payment_id": 12345}},
            "amount_too_low":  {"value": {"ok": false, "error": "amount_too_low",  "min": 30}},
            "amount_too_high": {"value": {"ok": false, "error": "amount_too_high", "max": 10000}}
          }}}},
          "401": {"description": "Not authenticated"},
          "403": {"description": "Invalid CSRF token"}
        }
      }
    },
    "/topup-status.php": {
      "get": {
        "summary": "Poll the status of a top-up invoice",
        "security": [{"SessionCookie": []}],
        "parameters": [{"name": "ref", "in": "query", "required": true, "schema": {"type": "string"}, "description": "The order_ref returned by /topup-api.php"}],
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"example": {"status": "waiting", "deposit_address": "47abc...", "deposit_amount": "0.4521", "expires_at": "2026-05-12 13:14:15"}}}}
        }
      }
    },
    "/deploy-api.php": {
      "post": {
        "summary": "Deploy a VPS or dedicated server (atomic balance debit)",
        "description": "Validates product/plan/region/OS/billing/root_password, debits balance atomically, creates a `servers` row at status=pending. Insufficient-balance response includes the deficit.",
        "security": [{"SessionCookie": []}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"example": "product=vps&plan=s2&region=par&os=debian-13&billing=3&root_password=AgentPass!2026Long&_token=<csrf>"}}},
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"examples": {
            "ok":          {"value": {"ok": true, "server_id": 9876, "monthly_eur": 15.0, "total_eur": 33.75, "redirect": "/account"}},
            "insufficient":{"value": {"ok": false, "error": "insufficient_balance", "have": 5.0, "need": 33.75, "deficit": 28.75, "topup": "/topup"}},
            "bad_password":{"value": {"ok": false, "error": "bad_password", "hint": "12+ chars"}}
          }}}},
          "401": {"description": "Not authenticated"}
        }
      }
    },
    "/domain-order": {
      "get": {
        "summary": "Configure a domain order (HTML preview + form)",
        "description": "GET returns the configuration page; POST (same URL) creates the order row and 302-redirects to `/domain-pay?id=<n>`. Supports query pre-fills: `?domain=...&years=N&privacy=0|1`.",
        "parameters": [
          {"name": "domain",  "in": "query", "required": true,  "schema": {"type": "string"}, "example": "mybrand.com"},
          {"name": "years",   "in": "query", "required": false, "schema": {"type": "integer", "minimum": 1, "maximum": 10}, "example": 1},
          {"name": "privacy", "in": "query", "required": false, "schema": {"type": "integer", "enum": [0, 1]}, "example": 1}
        ],
        "responses": {"200": {"description": "HTML page"}}
      },
      "post": {
        "summary": "Create a domain order row (302 → /domain-pay)",
        "security": [{"SessionCookie": []}],
        "parameters": [{"name": "domain", "in": "query", "required": true, "schema": {"type": "string"}, "example": "mybrand.com"}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"example": "years=1&privacy=1&nameservers=&_submitted=1&_token=<csrf>"}}},
        "responses": {
          "302": {"description": "Redirects to /domain-pay?id=<order_id>"},
          "401": {"description": "Not authenticated"}
        }
      }
    },
    "/domain-pay-api.php": {
      "post": {
        "summary": "Pay a domain order from balance",
        "description": "Atomic debit + status flip to `paid`. With DOMAIN_AUTO_REGISTER=false (current), registration is operator-finalized within 24h. With AUTO_REGISTER=true (roadmap), the registry is called synchronously.",
        "security": [{"SessionCookie": []}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"example": "action=pay_balance&order_id=42&_token=<csrf>"}}},
        "responses": {
          "302": {"description": "Redirects to /domain-pay?id=<n>"},
          "401": {"description": "Not authenticated"},
          "404": {"description": "Order not found"}
        }
      }
    },
    "/account-api.php": {
      "post": {
        "summary": "Account self-service (password change)",
        "security": [{"SessionCookie": []}],
        "requestBody": {"required": true, "content": {"application/x-www-form-urlencoded": {"example": "action=change_password&current_password=...&new_password=...&_token=<csrf>"}}},
        "responses": {
          "200": {"description": "OK", "content": {"application/json": {"example": {"ok": true}}}},
          "401": {"description": "Not authenticated"},
          "403": {"description": "Invalid CSRF token"}
        }
      }
    }
  },
  "x-bonus-tiers": [
    [100, 30], [250, 100], [500, 300], [1000, 700]
  ],
  "x-topup-bounds-usd": {
    "min": 30,
    "max": 10000,
    "enforcement": "server-side; values outside this range return ok:false with error code amount_too_low / amount_too_high. Applies to /topup-api.php and any future bearer-auth REST surface."
  },
  "x-products": {
    "vps":  {"plans": ["s1", "s2", "s3"], "regions": ["par", "rek", "zrh", "otp"]},
    "dedi": {"plans": ["r1", "r2", "r3"], "regions": ["par", "rek", "zrh", "otp"]}
  },
  "x-coins": ["BTC", "XMR", "ETH", "USDTTRC", "USDCETH", "LTC", "SOL", "TRX", "DOGE", "BCH"],
  "x-llms-txt": "https://cryptovpshosting.com/llms.txt",
  "x-agent-discovery": "https://cryptovpshosting.com/.well-known/agent.json",
  "x-policy": {
    "terms": "https://cryptovpshosting.com/terms-of-service",
    "privacy": "https://cryptovpshosting.com/privacy-notice",
    "aup": "https://cryptovpshosting.com/acceptable-use",
    "abuse": "https://cryptovpshosting.com/abuse-policy"
  }
}
