{
 "openapi": "3.1.0",
 "info": {
  "title": "Craft House Cloud API for AI agents",
  "version": "1.0.0",
  "description": "Order servers, VPN, databases and one-click apps from an AI agent. Flow: GET /catalog \u2192 POST /orders \u2192 poll GET /services/{id} until state=ready \u2192 GET /services/{id}/credentials. Prices in USD; paid from the account balance (top up with POST /balance/topup, the human pays at pay_url). MCP endpoint: https://api.crafthouse.ai/mcp. Limits: 60 requests/min per key; new accounts may have at most 2 services before the first payment; trials and sign-ups are limited per IP per day."
 },
 "servers": [
  {
   "url": "https://api.crafthouse.ai/v1"
  }
 ],
 "components": {
  "securitySchemes": {
   "apiKey": {
    "type": "http",
    "scheme": "bearer",
    "description": "API key chk_\u2026 (shown once at registration or POST /keys)"
   }
  }
 },
 "security": [
  {
   "apiKey": []
  }
 ],
 "paths": {
  "/register": {
   "post": {
    "summary": "Create an account and the first API key (key and password are shown once)",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "security": [],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "email": {
          "type": "string",
          "format": "email"
         },
         "name": {
          "type": "string"
         }
        },
        "required": [
         "email"
        ]
       }
      }
     }
    }
   }
  },
  "/catalog": {
   "get": {
    "summary": "Products and bundles with plans (trial, monthly, 3m, 6m, 12m, once), USD prices and order settings",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "security": []
   }
  },
  "/orders": {
   "post": {
    "summary": "Order a product or a bundle",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "product": {
          "type": "string",
          "description": "Product slug from /catalog"
         },
         "bundle": {
          "type": "string",
          "description": "Bundle id instead of product"
         },
         "plan": {
          "type": "string",
          "enum": [
           "trial",
           "monthly",
           "3m",
           "6m",
           "12m",
           "once"
          ]
         },
         "settings": {
          "type": "object",
          "description": "Order settings from /catalog (for a bundle: {product_slug: {...}})"
         }
        },
        "required": []
       }
      }
     }
    }
   }
  },
  "/services": {
   "get": {
    "summary": "All services of the account",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    }
   }
  },
  "/services/{id}": {
   "get": {
    "summary": "One service with live state: provisioning, deploying, ready, failed",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "integer"
      }
     }
    ]
   }
  },
  "/services/{id}/credentials": {
   "get": {
    "summary": "Address, login, password, database and access details of an active service",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "integer"
      }
     }
    ]
   }
  },
  "/services/{id}/renew": {
   "post": {
    "summary": "Pay the next invoice of the service from the balance",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "integer"
      }
     }
    ]
   }
  },
  "/services/{id}/cancel": {
   "post": {
    "summary": "Cancel the service",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "type": {
          "type": "string",
          "enum": [
           "immediate",
           "end_of_period"
          ]
         },
         "reason": {
          "type": "string"
         }
        },
        "required": []
       }
      }
     }
    },
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "integer"
      }
     }
    ]
   }
  },
  "/balance": {
   "get": {
    "summary": "Balance and pending invoices",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    }
   }
  },
  "/balance/topup": {
   "post": {
    "summary": "Create a top-up invoice (returns pay_url for the human); bonus +5/+10/+15% from $50/$100/$300",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "amount": {
          "type": "number"
         }
        },
        "required": [
         "amount"
        ]
       }
      }
     }
    }
   }
  },
  "/keys": {
   "post": {
    "summary": "Create another API key, optionally with a webhook (events service.active, invoice.created; header X-Crafthouse-Signature: sha256=HMAC(body, webhook_secret))",
    "responses": {
     "200": {
      "description": "Result"
     },
     "201": {
      "description": "Created"
     },
     "401": {
      "description": "Missing or invalid API key"
     },
     "404": {
      "description": "Not found"
     },
     "409": {
      "description": "Conflict (out of stock, wrong state)"
     },
     "422": {
      "description": "Validation error"
     },
     "429": {
      "description": "Rate limit"
     }
    },
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "properties": {
         "name": {
          "type": "string"
         },
         "webhook_url": {
          "type": "string",
          "format": "uri"
         }
        },
        "required": []
       }
      }
     }
    }
   }
  }
 }
}