{
  "openapi": "3.1.0",
  "info": {
    "title": "Polyzon API",
    "version": "1.0.0",
    "description": "Поиск 3D-моделей по каталогу Polyzon и карточки моделей. Доступ по личному токену из polyzon.org/account."
  },
  "servers": [
    {
      "url": "https://api.polyzon.org"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "Личный токен pzk_… из раздела «API» в polyzon.org/account."
      }
    }
  },
  "paths": {
    "/v1/search": {
      "get": {
        "operationId": "search",
        "summary": "Поиск моделей",
        "description": "Поиск по каталогу Polyzon: модели со всех площадок, с фильтрами и страницами. Глубина выдачи — не больше 2400 моделей (page × size).",
        "x-daily-quota": true,
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Поисковый запрос на русском или английском, до 200 символов.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "дракон"
          },
          {
            "name": "page",
            "in": "query",
            "description": "Номер страницы, с 1.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 1
            }
          },
          {
            "name": "size",
            "in": "query",
            "description": "Моделей на странице. page × size — не больше 2400.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Порядок: relevant — по релевантности, popular — по популярности на своей площадке, newest — новые, likes, makes, downloads.",
            "schema": {
              "type": "string",
              "enum": [
                "relevant",
                "popular",
                "newest",
                "likes",
                "makes",
                "downloads"
              ],
              "default": "relevant"
            }
          },
          {
            "name": "free",
            "in": "query",
            "description": "Только бесплатные модели.",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            }
          },
          {
            "name": "sources",
            "in": "query",
            "description": "Площадки через запятую: thingiverse, cults3d, printables, makerworld, 3dtoday, crealitycloud, myminifactory, thangs, youmagine, grabcad, sketchfab, threeding, nexprint, nasa, nih3d, smithsonian, pinshape, cgtrader, gambody, jewelmodel, makeronline, 3dexport.",
            "schema": {
              "type": "string"
            },
            "example": "thingiverse,printables"
          },
          {
            "name": "formats",
            "in": "query",
            "description": "Форматы файлов через запятую: stl, 3mf, obj, step, scad, gcode и другие.",
            "schema": {
              "type": "string"
            },
            "example": "stl,3mf"
          },
          {
            "name": "license",
            "in": "query",
            "description": "Лицензии через запятую: cc0, cc-by, cc-by-sa, cc-by-nd, cc-by-nc, cc-by-nc-sa, cc-by-nc-nd, gpl, lgpl, mit, bsd, private-use, commercial, custom, unknown.",
            "schema": {
              "type": "string"
            },
            "example": "cc0,cc-by"
          },
          {
            "name": "lang",
            "in": "query",
            "description": "Язык названий и тегов: ru или en. Если оригинал на другом языке, отдаётся машинный перевод.",
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en"
              ],
              "default": "ru"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Страница выдачи. `hasMore` — есть ли следующая страница в пределах 2400; `partial` — часть каталога не ответила, выдача неполная. В `stats.collects` — сохранения в коллекции, а если площадка их не считает — скачивания.",
            "content": {
              "application/json": {
                "example": {
                  "query": "дракон",
                  "correctedQuery": null,
                  "didYouMean": null,
                  "total": 1873,
                  "totalRelation": "eq",
                  "page": 1,
                  "size": 20,
                  "hasMore": true,
                  "partial": false,
                  "items": [
                    {
                      "source": "thingiverse",
                      "id": "tv-1234567",
                      "title": "Дракон с подвижными сочленениями (пример)",
                      "url": "https://www.thingiverse.com/thing:1234567",
                      "thumbnail": "https://cdn.thingiverse.com/assets/dragon.jpg",
                      "creator": "example_maker",
                      "license": "cc-by-nc",
                      "price": {
                        "type": "free",
                        "value": 0,
                        "currency": null,
                        "display": "Бесплатно"
                      },
                      "formats": [
                        "stl"
                      ],
                      "tags": [
                        "дракон",
                        "игрушка"
                      ],
                      "stats": {
                        "likes": 51234,
                        "comments": 870,
                        "makes": 3120,
                        "collects": 61000
                      },
                      "publishedAt": "2021-01-17T10:21:00Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Неверный параметр (`bad_request`, в поле `param` — какой) или слишком глубокая страница (`page_too_deep`)."
          },
          "401": {
            "description": "Нет токена (`unauthorized`) или он неверен либо отозван (`invalid_token`)."
          },
          "403": {
            "description": "Владелец токена не принял действующие условия Polyzon (`account_action_required`) — войдите в аккаунт."
          },
          "429": {
            "description": "Превышен минутный лимит (`rate_limited`) или исчерпана суточная квота (`quota_exceeded`). Ждите `Retry-After` секунд."
          },
          "503": {
            "description": "Каталог или проверка токена временно недоступны (`unavailable`). Повторите позже."
          }
        }
      }
    },
    "/v1/models/{source}/{id}": {
      "get": {
        "operationId": "getModel",
        "summary": "Карточка модели",
        "description": "Модель по площадке и её id — те же, что в элементах поиска и в адресе страницы polyzon.org/model/{source}/{id}. Картинки — адреса на CDN самой площадки.",
        "x-daily-quota": true,
        "parameters": [
          {
            "name": "source",
            "in": "path",
            "required": true,
            "description": "Площадка, откуда модель.",
            "schema": {
              "type": "string",
              "enum": [
                "thingiverse",
                "cults3d",
                "printables",
                "makerworld",
                "3dtoday",
                "crealitycloud",
                "myminifactory",
                "thangs",
                "youmagine",
                "grabcad",
                "sketchfab",
                "threeding",
                "nexprint",
                "nasa",
                "nih3d",
                "smithsonian",
                "pinshape",
                "cgtrader",
                "gambody",
                "jewelmodel",
                "makeronline",
                "3dexport"
              ]
            },
            "example": "thingiverse"
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Идентификатор модели на площадке с префиксом Polyzon, например tv-1234567.",
            "schema": {
              "type": "string",
              "maxLength": 255
            },
            "example": "tv-1234567"
          },
          {
            "name": "lang",
            "in": "query",
            "description": "Язык названия, описания и тегов: ru или en.",
            "schema": {
              "type": "string",
              "enum": [
                "ru",
                "en"
              ],
              "default": "ru"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Модель. `copies` — та же модель на других площадках.",
            "content": {
              "application/json": {
                "example": {
                  "source": "thingiverse",
                  "id": "tv-1234567",
                  "title": "Дракон с подвижными сочленениями (пример)",
                  "url": "https://www.thingiverse.com/thing:1234567",
                  "thumbnail": "https://cdn.thingiverse.com/assets/dragon.jpg",
                  "creator": "example_maker",
                  "license": {
                    "id": "cc-by-nc",
                    "raw": "Creative Commons - Attribution - Non-Commercial"
                  },
                  "price": {
                    "type": "free",
                    "value": 0,
                    "currency": null,
                    "display": "Бесплатно"
                  },
                  "formats": [
                    "stl"
                  ],
                  "tags": [
                    "дракон",
                    "игрушка"
                  ],
                  "stats": {
                    "likes": 51234,
                    "comments": 870,
                    "makes": 3120,
                    "collects": 61000,
                    "downloads": 410000,
                    "views": 990000
                  },
                  "publishedAt": "2021-01-17T10:21:00Z",
                  "description": "Дракон печатается целиком, без поддержек…",
                  "images": [
                    "https://cdn.thingiverse.com/assets/dragon.jpg"
                  ],
                  "creatorUrl": "https://www.thingiverse.com/example_maker",
                  "category": "Toys & Games",
                  "updatedAt": "2021-02-02T08:00:00Z",
                  "copies": [
                    {
                      "source": "printables",
                      "id": "pr-123456"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Нет токена (`unauthorized`) или он неверен либо отозван (`invalid_token`)."
          },
          "403": {
            "description": "Владелец токена не принял действующие условия Polyzon (`account_action_required`) — войдите в аккаунт."
          },
          "404": {
            "description": "Такой модели нет (`not_found`)."
          },
          "410": {
            "description": "Модель удалена по требованию правообладателя (`gone`). Удалите её и у себя."
          },
          "429": {
            "description": "Превышен минутный лимит (`rate_limited`) или исчерпана суточная квота (`quota_exceeded`). Ждите `Retry-After` секунд."
          },
          "503": {
            "description": "Каталог или проверка токена временно недоступны (`unavailable`). Повторите позже."
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Аккаунт и токен",
        "description": "Кому принадлежит токен, которым сделан запрос. Суточную квоту не тратит.",
        "x-daily-quota": false,
        "parameters": [],
        "responses": {
          "200": {
            "description": "Аккаунт и токен.",
            "content": {
              "application/json": {
                "example": {
                  "account": {
                    "id": "0f8c2a4e-…",
                    "displayName": "Алексей",
                    "createdAt": "2026-03-14T10:00:00.000Z"
                  },
                  "token": {
                    "id": "7d0e2f8a-…",
                    "name": "Телеграм-бот",
                    "prefix": "pzk_Q7xR2mVb",
                    "createdAt": "2026-10-09T08:15:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Нет токена (`unauthorized`) или он неверен либо отозван (`invalid_token`)."
          },
          "403": {
            "description": "Владелец токена не принял действующие условия Polyzon (`account_action_required`) — войдите в аккаунт."
          },
          "429": {
            "description": "Превышен минутный лимит (`rate_limited`) или исчерпана суточная квота (`quota_exceeded`). Ждите `Retry-After` секунд."
          },
          "503": {
            "description": "Каталог или проверка токена временно недоступны (`unavailable`). Повторите позже."
          }
        }
      }
    },
    "/v1/limits": {
      "get": {
        "operationId": "getLimits",
        "summary": "Остаток лимитов",
        "description": "Минутное окно и сутки UTC: лимит, израсходовано, осталось и момент сброса (секунды Unix). Суточную квоту не тратит.",
        "x-daily-quota": false,
        "parameters": [],
        "responses": {
          "200": {
            "description": "Окна квот аккаунта.",
            "content": {
              "application/json": {
                "example": {
                  "perMinute": {
                    "limit": 20,
                    "used": 1,
                    "remaining": 19,
                    "resetAt": 1791579180
                  },
                  "daily": {
                    "limit": 200,
                    "used": 37,
                    "remaining": 163,
                    "resetAt": 1791590400
                  }
                }
              }
            }
          },
          "401": {
            "description": "Нет токена (`unauthorized`) или он неверен либо отозван (`invalid_token`)."
          },
          "403": {
            "description": "Владелец токена не принял действующие условия Polyzon (`account_action_required`) — войдите в аккаунт."
          },
          "429": {
            "description": "Превышен минутный лимит (`rate_limited`) или исчерпана суточная квота (`quota_exceeded`). Ждите `Retry-After` секунд."
          },
          "503": {
            "description": "Каталог или проверка токена временно недоступны (`unavailable`). Повторите позже."
          }
        }
      }
    }
  }
}