{
 "openapi": "3.1.0",
 "info": {
  "title": "TOP SKLAD: Rent via your AI",
  "version": "1.0.0",
  "description": "Rent via your AI: how an assistant rents a storage unit at TOP SKLAD for the person it talks to.\n1. Ask for the e-mail first. POST /drafts tells you whether it already has an account (customer_status \"existing\"): then nothing else about the person is needed.\n2. Find a unit with GET /units (city, site, size, floor, budget, term). Never state a price or availability from memory: prices follow occupancy and change.\n3. Price the exact term with POST /quote (unit, months or start_date+end_date, insurance, moving_help, promo_code, customer_type, vat_id). Tell the person the total and the deposit.\n4. For a new customer collect: individual: first_name, last_name, phone (+421... European numbers only), birthday, street, house, city, zip_code, country; company: crn (IČO), name, phone, representative_first_name, representative_last_name, street, house, city, zip_code, country, vat_id if any. With an IČO alone the API fills the name and seat from the register.\n5. POST /drafts with everything; give the person the checkout_url exactly as returned and the notes with it: the unit is NOT reserved until paid, the link and price hold for 7 days.\n6. Send the X-Rent-Session header you received back on every call of the same conversation. Field errors come back under \"fields\" with the site's own wording: ask for that field again.\nConsents, sign-in and payment happen on our page, never in the chat. Answer the person in their language; pass it as lang (sk, en, ru).",
  "contact": {
   "name": "TOP SKLAD",
   "url": "https://top-sklad.com/"
  },
  "x-llms-txt": "https://top-sklad.com/llms.txt",
  "x-mcp-server": "https://mcp.top-sklad.com/mcp"
 },
 "servers": [
  {
   "url": "https://top-sklad.com/api/ai/v1"
  }
 ],
 "paths": {
  "/units": {
   "get": {
    "operationId": "searchUnits",
    "summary": "Units free right now",
    "description": "Every free unit, by site, with sizes, floor, door, the monthly price for each term and the page link. Nothing here is reserved.",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "sk",
        "en",
        "ru"
       ]
      },
      "description": "Language of texts and links; the language the person writes in."
     },
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     },
     {
      "name": "city",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "bratislava, nitra (any language)"
     },
     {
      "name": "site",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Site letters, comma-separated: D,G,H,K,N,P,T"
     },
     {
      "name": "min_area",
      "in": "query",
      "schema": {
       "type": "number"
      },
      "description": "m²"
     },
     {
      "name": "max_area",
      "in": "query",
      "schema": {
       "type": "number"
      },
      "description": "m²"
     },
     {
      "name": "floor",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Floor codes, comma-separated (see GET /sites glossary)"
     },
     {
      "name": "months",
      "in": "query",
      "schema": {
       "type": "integer",
       "enum": [
        1,
        3,
        6,
        9,
        12
       ]
      },
      "description": "Term the monthly_price_eur refers to; default 1"
     },
     {
      "name": "max_monthly_price",
      "in": "query",
      "schema": {
       "type": "number"
      },
      "description": "Budget in EUR per month for that term"
     }
    ],
    "responses": {
     "200": {
      "description": "Sites with free units",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Units"
        }
       }
      }
     },
     "400": {
      "description": "A filter is not acceptable",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many calls",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/quote": {
   "post": {
    "operationId": "getQuote",
    "summary": "Exact total for a unit and a term",
    "description": "Computed by the checkout itself: rent for the term, office discount, promo code, insurance, VAT by the site, refundable deposit. No side effects.",
    "parameters": [
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/QuoteRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "The quote",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/QuoteResponse"
        }
       }
      }
     },
     "400": {
      "description": "Validation: see fields",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Too many calls",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/drafts": {
   "post": {
    "operationId": "createRentalDraft",
    "summary": "Prepare the rental and get the link",
    "description": "Validates the customer with the registration form of the site, prices the rental and returns checkout_url: the confirmation page with everything filled in. customer_status \"existing\" means the e-mail has an account and the page will ask to sign in; no other personal data is kept then. Three different e-mails a day per session.",
    "parameters": [
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/DraftRequest"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Draft created",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DraftResponse"
        }
       }
      }
     },
     "200": {
      "description": "Existing open draft of this conversation updated",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DraftResponse"
        }
       }
      }
     },
     "400": {
      "description": "Validation: see fields (error \"unit_unavailable\" when the unit is gone)",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     },
     "429": {
      "description": "Limit reached: e-mail checks or drafts",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/drafts/{draft_id}": {
   "get": {
    "operationId": "getDraftStatus",
    "summary": "Status of a draft",
    "description": "open, opened (the link was opened), paid, unit_taken, expired. No personal data.",
    "parameters": [
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     },
     {
      "name": "draft_id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Status",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/DraftStatus"
        }
       }
      }
     },
     "404": {
      "description": "No such draft",
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Error"
        }
       }
      }
     }
    }
   }
  },
  "/sites": {
   "get": {
    "operationId": "listSites",
    "summary": "Sites: address, GPS, directions",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "sk",
        "en",
        "ru"
       ]
      },
      "description": "Language of texts and links; the language the person writes in."
     },
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     }
    ],
    "responses": {
     "200": {
      "description": "Sites"
     }
    }
   }
  },
  "/faq": {
   "get": {
    "operationId": "faq",
    "summary": "FAQ with today's prices",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "sk",
        "en",
        "ru"
       ]
      },
      "description": "Language of texts and links; the language the person writes in."
     },
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     }
    ],
    "responses": {
     "200": {
      "description": "FAQ sections"
     }
    }
   }
  },
  "/insurance-options": {
   "get": {
    "operationId": "insuranceOptions",
    "summary": "Insurance tiers and their codes",
    "parameters": [
     {
      "name": "lang",
      "in": "query",
      "schema": {
       "type": "string",
       "enum": [
        "sk",
        "en",
        "ru"
       ]
      },
      "description": "Language of texts and links; the language the person writes in."
     },
     {
      "name": "X-Rent-Session",
      "in": "header",
      "required": false,
      "schema": {
       "type": "string"
      },
      "description": "The conversation session issued in the first response header of the same name; send it back on every later call. Limits are counted per session."
     }
    ],
    "responses": {
     "200": {
      "description": "Options"
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "Error": {
    "type": "object",
    "properties": {
     "success": {
      "type": "boolean",
      "const": false
     },
     "error": {
      "type": "string"
     },
     "message": {
      "type": "string"
     },
     "fields": {
      "type": "object",
      "additionalProperties": {
       "type": "string"
      }
     }
    }
   },
   "Units": {
    "type": "object",
    "properties": {
     "months": {
      "type": "integer"
     },
     "free_units_total": {
      "type": "integer"
     },
     "sites": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "site": {
         "type": "string"
        },
        "name": {
         "type": "string"
        },
        "address": {
         "type": "string"
        },
        "units": {
         "type": "array",
         "items": {
          "$ref": "#/components/schemas/Unit"
         }
        }
       }
      }
     }
    }
   },
   "Unit": {
    "type": "object",
    "properties": {
     "unit": {
      "type": "string",
      "description": "Label, e.g. K14: use it in /quote and /drafts"
     },
     "floor_area_m2": {
      "type": "number"
     },
     "volume_m3": {
      "type": "number"
     },
     "length_m": {
      "type": "number"
     },
     "width_m": {
      "type": "number"
     },
     "height_m": {
      "type": "number"
     },
     "floor": {
      "type": "object"
     },
     "car_access": {
      "type": "object"
     },
     "monthly_price_eur": {
      "type": "number",
      "description": "For the term asked (months)"
     },
     "monthly_prices_eur": {
      "type": "object",
      "description": "Keys 1, 3, 6, 9, 12"
     },
     "page_url": {
      "type": "string",
      "format": "uri"
     }
    }
   },
   "Term": {
    "type": "object",
    "properties": {
     "unit": {
      "type": "string"
     },
     "months": {
      "type": "integer",
      "enum": [
       1,
       3,
       6,
       9,
       12
      ],
      "description": "Omit and give end_date for a period in days (31 days minimum)"
     },
     "start_date": {
      "type": "string",
      "format": "date",
      "description": "Today up to 13 days ahead; default today"
     },
     "end_date": {
      "type": "string",
      "format": "date"
     },
     "insurance": {
      "type": "string",
      "description": "Code from /insurance-options; default \"included\""
     },
     "moving_help": {
      "type": "boolean"
     },
     "moving_help_note": {
      "type": "string"
     },
     "promo_code": {
      "type": "string"
     },
     "lang": {
      "type": "string",
      "enum": [
       "sk",
       "en",
       "ru"
      ]
     }
    },
    "required": [
     "unit"
    ]
   },
   "QuoteRequest": {
    "allOf": [
     {
      "$ref": "#/components/schemas/Term"
     },
     {
      "type": "object",
      "properties": {
       "customer_type": {
        "type": "string",
        "enum": [
         "individual",
         "company"
        ],
        "default": "individual"
       },
       "vat_id": {
        "type": "string",
        "description": "IČ DPH of a company; another EU country's code moves the tax to the buyer"
       }
      }
     }
    ]
   },
   "QuoteResponse": {
    "type": "object",
    "properties": {
     "success": {
      "type": "boolean"
     },
     "quote": {
      "$ref": "#/components/schemas/Quote"
     }
    }
   },
   "Quote": {
    "type": "object",
    "properties": {
     "unit": {
      "type": "string"
     },
     "start_date": {
      "type": "string",
      "format": "date"
     },
     "end_date": {
      "type": "string",
      "format": "date"
     },
     "lines": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "kind": {
         "type": "string"
        },
        "label": {
         "type": "string"
        },
        "amount": {
         "type": "string",
         "pattern": "^-?\\d+\\.\\d{2}$",
         "description": "Amount in EUR with two decimals."
        }
       }
      }
     },
     "vat": {
      "type": "object"
     },
     "total": {
      "type": "string",
      "pattern": "^-?\\d+\\.\\d{2}$",
      "description": "Amount in EUR with two decimals."
     },
     "currency": {
      "type": "string"
     },
     "promo_code": {
      "type": "object",
      "nullable": true
     },
     "unit_available": {
      "type": "boolean"
     },
     "alternatives": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Unit"
      }
     },
     "note": {
      "type": "string"
     }
    }
   },
   "Customer": {
    "type": "object",
    "required": [
     "email"
    ],
    "properties": {
     "type": {
      "type": "string",
      "enum": [
       "individual",
       "company"
      ],
      "default": "individual"
     },
     "email": {
      "type": "string",
      "format": "email"
     },
     "first_name": {
      "type": "string"
     },
     "last_name": {
      "type": "string"
     },
     "phone": {
      "type": "string",
      "description": "E.164, European prefixes +3xx/+4xx only"
     },
     "birthday": {
      "type": "string",
      "format": "date"
     },
     "crn": {
      "type": "string",
      "description": "IČO (company)"
     },
     "name": {
      "type": "string",
      "description": "Company name"
     },
     "vat_id": {
      "type": "string"
     },
     "representative_first_name": {
      "type": "string"
     },
     "representative_last_name": {
      "type": "string"
     },
     "street": {
      "type": "string"
     },
     "house": {
      "type": "string"
     },
     "city": {
      "type": "string"
     },
     "zip_code": {
      "type": "string"
     },
     "country": {
      "type": "string",
      "default": "Slovensko"
     }
    }
   },
   "DraftRequest": {
    "allOf": [
     {
      "$ref": "#/components/schemas/Term"
     },
     {
      "type": "object",
      "required": [
       "customer"
      ],
      "properties": {
       "customer": {
        "$ref": "#/components/schemas/Customer"
       },
       "assistant": {
        "type": "object",
        "properties": {
         "vendor": {
          "type": "string",
          "description": "chatgpt, claude, gemini, perplexity, copilot, grok, mistral, other"
         },
         "model": {
          "type": "string"
         },
         "conversation_language": {
          "type": "string"
         }
        }
       }
      }
     }
    ]
   },
   "DraftResponse": {
    "type": "object",
    "properties": {
     "success": {
      "type": "boolean"
     },
     "draft_id": {
      "type": "string"
     },
     "checkout_url": {
      "type": "string",
      "format": "uri",
      "description": "Give it to the person exactly as it is"
     },
     "expires_at": {
      "type": "string",
      "format": "date-time"
     },
     "customer_status": {
      "type": "string",
      "enum": [
       "new",
       "existing"
      ]
     },
     "quote": {
      "$ref": "#/components/schemas/Quote"
     },
     "notes": {
      "type": "array",
      "items": {
       "type": "string"
      },
      "description": "Tell the person these"
     },
     "company_from_register": {
      "type": "object",
      "description": "What the register knows about the IČO; confirm with the person"
     }
    }
   },
   "DraftStatus": {
    "type": "object",
    "properties": {
     "draft_id": {
      "type": "string"
     },
     "status": {
      "type": "string",
      "enum": [
       "open",
       "opened",
       "paid",
       "unit_taken",
       "expired"
      ]
     },
     "unit": {
      "type": "string"
     },
     "total": {
      "type": "string",
      "pattern": "^-?\\d+\\.\\d{2}$",
      "description": "Amount in EUR with two decimals."
     },
     "checkout_url": {
      "type": "string",
      "nullable": true
     }
    }
   }
  }
 }
}