{
  "openapi": "3.1.0",
  "info": {
    "title": "CLI>_ Agent API",
    "version": "0.1.3",
    "description": "Public read, quote, draft-cart, pending-order, authenticated credit-payment, post-payment service install, and credential handoff API for AI agents. Agents can create pending_payment card orders from customer email and billing data. After a successful paid order, order status returns agent_auth.token. Use it as Authorization: Bearer <token> for future customer-agent orders, including payment_method=credit when account credit covers the order total. For card orders send the customer to payment.pay_url, poll the returned signed status_url, POST required service configuration to signed install_action.url, then fetch ready credentials from signed credentials_action.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. Public orders use payment_method=card.",
    "After a successful paid order, read order.agent_auth.token from the signed status_url response and use it as Authorization: Bearer <token> for future orders for the same customer.",
    "Authenticated customer agents may set payment_method=credit when the customer's existing account credit covers the order total. Email-only public agents without agent_auth cannot spend account credit.",
    "Send the customer to payment.pay_url, then poll the returned signed status_url until paymentStatus is Success.",
    "If a paid service returns requires_install_configuration, POST config to the signed install_action.url.",
    "During processing, read provisioning_estimate from the service payload. Provisioning usually takes 3-20 minutes; poll every 60 seconds and do not retry aggressively.",
    "When credentials_available is true, GET signed credentials_action.url. Treat status_url, install_action.url, credentials_action.url, and credential responses as bearer-like secrets."
  ],
  "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": "+420777111222",
                    "billing_street": "Cloud Street 1",
                    "billing_city": "Prague",
                    "billing_postal_code": "11000",
                    "billing_country": "CZ",
                    "items": [{"product_id": "kubernetes-hosting-universal", "quantity": 1}]
                  }
                },
                "company": {
                  "summary": "Company order",
                  "value": {
                    "customer_email": "buyer@example.com",
                    "billing_name": "Buyer Name",
                    "billing_street": "Personal Street 1",
                    "billing_city": "Prague",
                    "billing_postal_code": "11000",
                    "billing_country": "CZ",
                    "is_company": true,
                    "company_name": "Example Cloud Ltd.",
                    "company_ico": "12345678",
                    "company_dic": "CZ12345678",
                    "company_ic_dph": "CZ12345678",
                    "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": "Order created. Card orders are pending_payment and contain payment.pay_url plus signed status_url; send the customer to Stripe Checkout, then poll status_url. After payment succeeds, status responses include agent_auth.token for future customer-agent orders. Authenticated credit orders are marked paid immediately when credit covers the total and return no pay_url. Treat status_url and agent_auth.token as bearer-like secrets. 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 and service status 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, provisioning_estimate timing, install_action for services requiring post-payment configuration, and credentials_action for ready credential handoff."},
          "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}/services/{item}/install": {
      "post": {
        "operationId": "configure_service",
        "summary": "Submit post-payment service configuration and start installation",
        "parameters": [
          {"name": "order_number", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "item", "in": "path", "required": true, "schema": {"type": "integer"}}
        ],
        "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServiceInstallRequest"}}}},
        "responses": {
          "200": {"description": "Install started. Response includes refreshed order status. Processing usually takes 3-20 minutes; agents should follow provisioning_estimate.poll_after_seconds."},
          "401": {"description": "Signed install_action.url or order-owner login required."},
          "409": {"description": "Payment is not confirmed yet."},
          "422": {"description": "Validation errors, unsupported service install action, or custom domain DNS not ready."}
        }
      }
    },
    "/api/order/{order_number}/services/{item}/credentials": {
      "get": {
        "operationId": "get_service_credentials",
        "summary": "Fetch ready handoff credentials using signed credentials_action.url",
        "parameters": [
          {"name": "order_number", "in": "path", "required": true, "schema": {"type": "string"}},
          {"name": "item", "in": "path", "required": true, "schema": {"type": "integer"}}
        ],
        "responses": {
          "200": {"description": "Sensitive service handoff credentials and instructions."},
          "401": {"description": "Signed credentials_action.url or order-owner login required."},
          "404": {"description": "Credentials are not available for this service or handoff secret is not ready."},
          "409": {"description": "Service is not in a credential-ready state yet."}
        }
      }
    },
    "/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 CZ. 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."},
          "payment_method": {"type": "string", "enum": ["card", "credit"], "default": "card", "description": "Use card for public orders. credit is allowed only with a logged-in customer session or Authorization: Bearer <agent_auth.token> from a previous paid order, when account credit covers the order total."},
          "note": {"type": "string"}
        }
      },
      "ServiceInstallRequest": {
        "type": "object",
        "required": ["config"],
        "properties": {
          "config": {"type": "object", "additionalProperties": true, "description": "Use the per-service service_configuration_schema returned in order status."}
        }
      }
    }
  }
}
