{
  "openapi": "3.1.0",
  "info": {
    "title": "CLI>_ Agent API",
    "version": "0.1.0",
    "description": "Public read, quote, draft-cart, and pending-order API for AI agents. Agents can create pending_payment orders from customer email and billing data, send the customer to payment.pay_url, then poll the returned signed status_url. Payment confirmation is asynchronous and Stripe-webhook-confirmed."
  },
  "x-agent-workflow": [
    "GET /api/products or GET /api/products/{product_id}",
    "POST /api/checkout/quote with items",
    "Ask the customer for missing billing fields before order creation; do not guess billing data.",
    "POST /api/order with customer_email, billing fields, items, and Idempotency-Key",
    "Send the customer to payment.pay_url, then poll the returned signed status_url until paymentStatus is Success and services are ready. Treat status_url as a bearer-like secret and do not publish it."
  ],
  "paths": {
    "/api/products": {
      "get": {
        "operationId": "search_products",
        "summary": "Search active products",
        "parameters": [
          {"name": "query", "in": "query", "schema": {"type": "string"}},
          {"name": "category", "in": "query", "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {"description": "Product list with stable IDs, prices, availability, schemas, and action policy."},
          "429": {"description": "Rate limit exceeded."}
        }
      }
    },
    "/api/products/{product_id}": {
      "get": {
        "operationId": "get_product",
        "summary": "Get one active product by stable slug",
        "parameters": [
          {"name": "product_id", "in": "path", "required": true, "schema": {"type": "string"}}
        ],
        "responses": {
          "200": {"description": "Product detail with configuration schema and allowed actions."},
          "404": {"description": "Product not found or inactive."},
          "429": {"description": "Rate limit exceeded."}
        }
      }
    },
    "/api/cart": {
      "post": {
        "operationId": "create_cart",
        "summary": "Create a non-persistent draft cart",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ItemsRequest"}}}},
        "responses": {
          "201": {"description": "Draft cart created with quote."},
          "422": {"description": "Validation errors with exact field paths."},
          "429": {"description": "Rate limit exceeded."}
        }
      }
    },
    "/api/checkout/quote": {
      "post": {
        "operationId": "create_checkout_quote",
        "summary": "Calculate deterministic quote without order or payment",
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ItemsRequest"}}}},
        "responses": {
          "200": {"description": "Quote with totals, currency, expiration, commit policy, configuration_normalized, and configuration_warnings when submitted configuration values were defaulted."},
          "422": {"description": "Validation errors with exact field paths."},
          "429": {"description": "Rate limit exceeded."}
        }
      }
    },
    "/api/order": {
      "post": {
        "operationId": "create_order",
        "summary": "Create a pending payment order from customer email and billing data",
        "parameters": [{"name": "Idempotency-Key", "in": "header", "required": true, "schema": {"type": "string"}}],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {"$ref": "#/components/schemas/AgentOrderRequest"},
              "examples": {
                "person": {
                  "summary": "Private person order",
                  "value": {
                    "customer_email": "customer@example.com",
                    "billing_name": "Customer Name",
                    "billing_phone": "+421900111222",
                    "billing_street": "Cloud Street 1",
                    "billing_city": "Bratislava",
                    "billing_postal_code": "81101",
                    "billing_country": "SK",
                    "items": [{"product_id": "managed-vps", "quantity": 1}]
                  }
                },
                "company": {
                  "summary": "Company order",
                  "value": {
                    "customer_email": "buyer@example.com",
                    "billing_name": "Buyer Name",
                    "billing_street": "Personal Street 1",
                    "billing_city": "Bratislava",
                    "billing_postal_code": "81101",
                    "billing_country": "SK",
                    "is_company": true,
                    "company_name": "Example Cloud Ltd.",
                    "company_ico": "12345678",
                    "company_dic": "SK12345678",
                    "company_ic_dph": "SK12345678",
                    "company_street": "Company Street 10",
                    "company_city": "Vienna",
                    "company_postal_code": "1010",
                    "company_country": "AT",
                    "items": [{"product_id": "kubernetes-hosting-universal", "quantity": 1}]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {"description": "Pending payment order created. Response contains payment.pay_url and signed status_url; send the customer to Stripe Checkout, then poll status_url until paymentStatus changes and services become ready. Treat status_url as a bearer-like secret. If submitted configuration values were normalized, configuration_normalized and configuration_warnings are included."},
          "200": {"description": "Idempotent replay of an existing order."},
          "428": {"description": "Idempotency-Key header required."},
          "422": {"description": "Validation errors with exact field paths, missing customer email/billing data, or incomplete logged-in account settings."}
        }
      }
    },
    "/api/order/{order_number}/status": {
      "get": {
        "operationId": "get_order_status",
        "summary": "Poll payment status, service status, and ready credentials using signed status_url",
        "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string"}}],
        "responses": {
          "200": {"description": "Order status with paymentStatus, serviceStatus, poll_after_seconds, and credentials when ready after asynchronous payment confirmation."},
          "401": {"description": "Signed status_url or order-owner login required."},
          "403": {"description": "Order does not belong to the logged-in customer."}
        }
      }
    },
    "/api/order/{order_number}": {
      "get": {
        "operationId": "get_order",
        "summary": "Order lookup placeholder requiring signed status_url or scoped auth",
        "parameters": [{"name": "order_number", "in": "path", "required": true, "schema": {"type": "string"}}],
        "responses": {
          "401": {"description": "Use signed status_url returned by order creation."},
          "429": {"description": "Rate limit exceeded."}
        }
      }
    },
    "/api/mcp/tools": {"get": {"operationId": "list_mcp_tools", "responses": {"200": {"description": "HTTP MCP-style tool catalog."}}}},
    "/api/mcp/resources": {"get": {"operationId": "list_mcp_resources", "responses": {"200": {"description": "HTTP MCP-style resource catalog."}}}},
    "/api/mcp/call": {"post": {"operationId": "call_mcp_tool", "description": "Calls only tools listed in /api/mcp/tools mcp_call.callable_tools. Direct API-only tools such as create_order must be called through their endpoint.", "responses": {"200": {"description": "Tool result for read/draft actions."}, "422": {"description": "JSON validation error, including direct API-only tool names."}}}}
  },
  "components": {
    "schemas": {
      "ItemsRequest": {
        "type": "object",
        "required": ["items"],
        "properties": {
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "type": "object",
              "required": ["product_id"],
              "properties": {
                "product_id": {"type": "string", "description": "Stable product slug."},
                "quantity": {"type": "integer", "minimum": 1, "maximum": 99, "default": 1},
                "configuration": {"type": "object", "additionalProperties": true}
              }
            }
          }
        }
      },
      "AgentOrderRequest": {
        "type": "object",
        "required": ["items", "customer_email", "billing_name", "billing_street", "billing_city", "billing_postal_code", "billing_country"],
        "properties": {
          "items": {"$ref": "#/components/schemas/ItemsRequest/properties/items"},
          "customer_email": {"type": "string", "format": "email", "description": "Customer email that will own the order after payment confirmation."},
          "billing_name": {"type": "string"},
          "billing_phone": {"type": "string"},
          "billing_street": {"type": "string"},
          "billing_city": {"type": "string"},
          "billing_postal_code": {"type": "string"},
          "billing_country": {"type": "string", "description": "ISO-3166 alpha-2 country code preferred, for example SK. Country names are accepted for now."},
          "is_company": {"type": "boolean"},
          "company_name": {"type": "string"},
          "company_ico": {"type": "string"},
          "company_dic": {"type": "string"},
          "company_ic_dph": {"type": "string"},
          "company_street": {"type": "string"},
          "company_city": {"type": "string"},
          "company_postal_code": {"type": "string"},
          "company_country": {"type": "string", "description": "ISO-3166 alpha-2 country code preferred, for example AT."},
          "note": {"type": "string"}
        }
      }
    }
  }
}
