{"openapi":"3.1.0","info":{"title":"DueBuddy API","version":"0.3.0"},"paths":{"/api/v1/api/price":{"get":{"tags":["api-subscription"],"summary":"Api Price","description":"Цена для выбранного ползунком объёма.\n\nДоступно и без входа — это калькулятор на сайте. Валюта зависит от страны клиента.","operationId":"api_price_api_v1_api_price_get","parameters":[{"name":"sheets","in":"query","required":false,"schema":{"type":"integer","maximum":2000000,"minimum":100,"default":100,"title":"Sheets"}},{"name":"country","in":"query","required":false,"schema":{"type":"string","maxLength":2,"description":"Страна клиента — определяет валюту (DE/EUR, US/USD, RU/RUB)","default":"","title":"Country"},"description":"Страна клиента — определяет валюту (DE/EUR, US/USD, RU/RUB)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Price Api V1 Api Price Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/scale":{"get":{"tags":["api-subscription"],"summary":"Api Scale","description":"Шкала: от какого объёма какая цена за лист.","operationId":"api_scale_api_v1_api_scale_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Scale Api V1 Api Scale Get"}}}}}}},"/api/v1/api/dashboard":{"get":{"tags":["api-subscription"],"summary":"Api Dashboard","description":"Что видит клиент: ключ, лимит, израсходовано, осталось, до какой даты.","operationId":"api_dashboard_api_v1_api_dashboard_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Dashboard Api V1 Api Dashboard Get"}}}}}}},"/api/v1/api/keys":{"get":{"tags":["api-subscription"],"summary":"Api Keys List","description":"Список ключей клиента: метка, начало ключа, когда создан, когда последний раз использован.\n\nСами ключи не отдаём — в базе только хеш, показать ключ целиком можно один раз при выдаче.","operationId":"api_keys_list_api_v1_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Keys List Api V1 Api Keys Get"}}}}}},"post":{"tags":["api-subscription"],"summary":"Api Keys Create","description":"Добавить ещё один ключ (например, для второй системы). Лимит общий — он считается по подписке.\n\nПрежние ключи продолжают работать. Если нужно заменить все — есть отдельная кнопка перевыпуска.","operationId":"api_keys_create_api_v1_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Keys Create Api V1 Api Keys Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/keys/{key_id}/revoke":{"post":{"tags":["api-subscription"],"summary":"Api Keys Revoke","description":"Отозвать один ключ. Остальные ключи и подписка не затрагиваются.","operationId":"api_keys_revoke_api_v1_api_keys__key_id__revoke_post","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"integer","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Keys Revoke Api V1 Api Keys  Key Id  Revoke Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/key/rotate":{"post":{"tags":["api-subscription"],"summary":"Api Key Rotate","description":"Перевыпустить ключ (старый сразу перестаёт работать). Новый показывается один раз.","operationId":"api_key_rotate_api_v1_api_key_rotate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Key Rotate Api V1 Api Key Rotate Post"}}}}}}},"/api/v1/api/usage":{"get":{"tags":["api-subscription"],"summary":"Api Usage","description":"Журнал расхода: когда и сколько листов списано (для отчётности клиента).","operationId":"api_usage_api_v1_api_usage_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Usage Api V1 Api Usage Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/countries":{"get":{"tags":["api-subscription"],"summary":"Countries List","description":"Список стран для меню выбора: название на языке интерфейса, язык счетов, форматы, способы оплаты.\n\nЗачем (владелец, 05.10.2026): в интерфейсе нужен выбор страны, и он должен показывать, что\nв этой стране принимается и какие форматы счетов там приняты. Язык интерфейса — ru/de/en,\nязык счетов — местный (по нему работают правила распознавания).","operationId":"countries_list_api_v1_api_countries_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"en","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Countries List Api V1 Api Countries Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/country/{code}":{"get":{"tags":["api-subscription"],"summary":"Country Info","description":"Данные одной страны: как открывать интерфейс, на каком языке приходят счета, что принимается.","operationId":"country_info_api_v1_api_country__code__get","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"en","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Country Info Api V1 Api Country  Code  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/api/balance":{"get":{"tags":["api-subscription"],"summary":"Api Balance","description":"Баланс API: сколько страниц осталось на текущий период.\n\nВладелец: до пополнения обработка не запускается, поэтому клиент должен\nвидеть остаток и понимать, почему запросы не проходят.","operationId":"api_balance_api_v1_api_balance_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Api Balance Api V1 Api Balance Get"}}}}}}},"/api/v1/auth/start":{"post":{"tags":["auth"],"summary":"Auth Start","description":"Всегда 200 {\"ok\": true}: не раскрываем, есть ли такой пользователь.","operationId":"auth_start_api_v1_auth_start_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/verify":{"get":{"tags":["auth"],"summary":"Auth Verify Page","description":"Страница входа по ссылке.\n\nСсылку НЕ гасим при открытии: почтовые сканеры и предпросмотр в мессенджерах\nоткрывают её раньше человека, и он получал «ссылка недействительна» на свежем письме.\nГашение и вход — только после нажатия кнопки (POST).","operationId":"auth_verify_page_api_v1_auth_verify_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":200,"title":"Token"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","maxLength":5,"default":"en","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["auth"],"summary":"Auth Verify","operationId":"auth_verify_api_v1_auth_verify_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOut"}}}}}}},"/api/v1/auth/logout_all":{"post":{"tags":["auth"],"summary":"Auth Logout All","description":"Выход со всех устройств: гасим все активные сессии пользователя.","operationId":"auth_logout_all_api_v1_auth_logout_all_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkOut"}}}}}}},"/api/v1/auth/logout":{"post":{"tags":["auth"],"summary":"Auth Logout","operationId":"auth_logout_api_v1_auth_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkOut"}}}}}}},"/api/v1/me":{"get":{"tags":["auth"],"summary":"Me","operationId":"me_api_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeOut"}}}}}}},"/api/v1/auth/pin/set":{"post":{"tags":["auth"],"summary":"Pin Set","description":"Включить PIN (или сменить). Пустой pin — выключить двухфакторный вход.","operationId":"pin_set_api_v1_auth_pin_set_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/auth/pin/status":{"get":{"tags":["auth"],"summary":"Pin Status","description":"Включён ли PIN у пользователя.","operationId":"pin_status_api_v1_auth_pin_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Pin Status Api V1 Auth Pin Status Get"}}}}}}},"/api/v1/auth/pin/verify":{"post":{"tags":["auth"],"summary":"Pin Verify","description":"Второй шаг входа: проверяем PIN по временному токену ссылки.","operationId":"pin_verify_api_v1_auth_pin_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/plans":{"get":{"tags":["plans"],"summary":"List Plans","operationId":"list_plans_api_v1_plans_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PlanOut"},"type":"array","title":"Response List Plans Api V1 Plans Get"}}}}}}},"/api/v1/plans/current":{"get":{"tags":["plans"],"summary":"Current Plan","operationId":"current_plan_api_v1_plans_current_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurrentPlanOut"}}}}}}},"/api/v1/plans/upgrade-price":{"get":{"tags":["plans"],"summary":"Upgrade Price","operationId":"upgrade_price_api_v1_plans_upgrade_price_get","parameters":[{"name":"to","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":4,"title":"To"}},{"name":"period","in":"query","required":false,"schema":{"anyOf":[{"enum":["m","y"],"type":"string"},{"type":"null"}],"title":"Period"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/plans/select":{"post":{"tags":["plans"],"summary":"Select Plan","operationId":"select_plan_api_v1_plans_select_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SelectOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/inbox/scan":{"post":{"tags":["inbox"],"summary":"Inbox Scan","operationId":"inbox_scan_api_v1_inbox_scan_post","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50,"minimum":1,"default":10,"title":"Limit"}},{"name":"query","in":"query","required":false,"schema":{"type":"string","default":"has:attachment newer_than:14d","title":"Query"}},{"name":"country","in":"query","required":false,"schema":{"type":"string","default":"de","title":"Country"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/inbox":{"get":{"tags":["inbox"],"summary":"Inbox List","operationId":"inbox_list_api_v1_inbox_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leads":{"post":{"tags":["leads"],"summary":"Create Lead","description":"Принять заявку на API распознавания. Отвечаем всегда одинаково (не раскрываем деталей).","operationId":"create_lead_api_v1_leads_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/leads/count":{"get":{"tags":["leads"],"summary":"Leads Count","description":"Сколько заявок уже собрано (для витрины «к нам уже обратились N компаний»).","operationId":"leads_count_api_v1_leads_count_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/guide/lava":{"get":{"tags":["leads"],"summary":"Lava Guide","description":"Чек-лист и готовые тексты для полей Lava (публично, без входа).\n\nВладелец: «мы говорим, как правильно зарегистрироваться, чтобы всё работало» —\nшаг стоит ДО регистрации, потому что проверка в Lava занимает до 7 рабочих дней.","operationId":"lava_guide_api_v1_guide_lava_get","parameters":[{"name":"country","in":"query","required":false,"schema":{"type":"string","default":"","title":"Country"}},{"name":"currency","in":"query","required":false,"schema":{"type":"string","default":"","title":"Currency"}},{"name":"business","in":"query","required":false,"schema":{"type":"string","default":"","title":"Business"}},{"name":"name","in":"query","required":false,"schema":{"type":"string","default":"","title":"Name"}},{"name":"email","in":"query","required":false,"schema":{"type":"string","default":"","title":"Email"}},{"name":"lang","in":"query","required":false,"schema":{"type":"string","default":"","title":"Lang"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Lava Guide Api V1 Guide Lava Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/letters":{"get":{"tags":["letters"],"summary":"List Letters","description":"Все письма клиента (свежие сверху) с названием счёта и должником.","operationId":"list_letters_api_v1_letters_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Letters Api V1 Letters Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/mail/account":{"get":{"tags":["mail-account"],"summary":"Mail Account Status","description":"Подключена ли почта клиента и с какого адреса будут уходить письма.","operationId":"mail_account_status_api_v1_mail_account_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mail Account Status Api V1 Mail Account Get"}}}}}},"delete":{"tags":["mail-account"],"summary":"Mail Account Disconnect","description":"Отключить почту: письма перестанут уходить от имени клиента.","operationId":"mail_account_disconnect_api_v1_mail_account_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mail Account Disconnect Api V1 Mail Account Delete"}}}}}}},"/api/v1/mail/account/connect":{"post":{"tags":["mail-account"],"summary":"Mail Account Connect","description":"Ссылка для подключения Gmail: человек открывает её и разрешает доступ.","operationId":"mail_account_connect_api_v1_mail_account_connect_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mail Account Connect Api V1 Mail Account Connect Post"}}}}}}},"/api/v1/exports/datev":{"post":{"tags":["exports"],"summary":"Export Datev","description":"Один файл DATEV по выбранным разборам (для передачи бухгалтеру).","operationId":"export_datev_api_v1_exports_datev_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatevExportIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse/{job_id}/export/datev":{"get":{"tags":["exports"],"summary":"Export One Datev","description":"Выгрузка одного разобранного счёта в файл DATEV.","operationId":"export_one_datev_api_v1_parse__job_id__export_datev_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"account","in":"query","required":false,"schema":{"type":"string","default":"1200","title":"Account"}},{"name":"contra_account","in":"query","required":false,"schema":{"type":"string","default":"8400","title":"Contra Account"}},{"name":"bu_key","in":"query","required":false,"schema":{"type":"string","default":"","title":"Bu Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/exports/1c":{"post":{"tags":["exports"],"summary":"Export 1C","description":"Отдать таблицу разобранных счетов в формате 1С (CSV, UTF-8 с BOM).","operationId":"export_1c_api_v1_exports_1c_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatevExportIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse/upload":{"post":{"summary":"Parse Upload","operationId":"parse_upload_api_v1_parse_upload_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_parse_upload_api_v1_parse_upload_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse":{"get":{"summary":"Parse List","operationId":"parse_list_api_v1_parse_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":200,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse/{job_id}":{"get":{"summary":"Parse Get","operationId":"parse_get_api_v1_parse__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Parse Delete","operationId":"parse_delete_api_v1_parse__job_id__delete","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse/{job_id}/fields":{"patch":{"summary":"Parse Patch Fields","operationId":"parse_patch_fields_api_v1_parse__job_id__fields_patch","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/parse/{job_id}/reparse":{"post":{"summary":"Parse Reparse","operationId":"parse_reparse_api_v1_parse__job_id__reparse_post","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"country","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Country"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/parse":{"post":{"tags":["public-api"],"summary":"Api Parse","description":"Принять счёт по API: файл → разбор (листы спишутся по факту успеха).","operationId":"api_parse_v1_parse_post","parameters":[{"name":"X-Api-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_api_parse_v1_parse_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Parse V1 Parse Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/parse/{job_id}":{"get":{"tags":["public-api"],"summary":"Api Parse Status","description":"Статус и поля разбора (только свои задания).","operationId":"api_parse_status_v1_parse__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"X-Api-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Parse Status V1 Parse  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/usage":{"get":{"tags":["public-api"],"summary":"Api Usage","description":"Сколько листов израсходовано и сколько осталось (клиент видит в своём кабинете).","operationId":"api_usage_v1_usage_get","parameters":[{"name":"X-Api-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Api-Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Api Usage V1 Usage Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reviews":{"get":{"tags":["reviews"],"summary":"List Reviews","description":"Опубликованные отзывы (для страницы и для Schema.org).","operationId":"list_reviews_api_v1_reviews_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Reviews Api V1 Reviews Get"}}}}}},"post":{"tags":["reviews"],"summary":"Create Review","description":"Принять отзыв. 4–5 звёзд — сразу публикуем, 1–3 — отправляем владельцу.","operationId":"create_review_api_v1_reviews_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Review Api V1 Reviews Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/it":{"get":{"summary":"Lang Page","description":"Постоянный адрес языка: /ru, /de, /en.\n\nЗачем именно так (нашёл Sonnet, 05.10.2026): поисковые роботы и нейросети НЕ ходят по\nпараметрам вида ?lang= — им нужен отдельный адрес на каждый язык. Иначе для бота существует\nтолько английская версия, и немецкие/русские страницы просто не попадают в индекс.","operationId":"lang_page_it_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/de":{"get":{"summary":"Lang Page","description":"Постоянный адрес языка: /ru, /de, /en.\n\nЗачем именно так (нашёл Sonnet, 05.10.2026): поисковые роботы и нейросети НЕ ходят по\nпараметрам вида ?lang= — им нужен отдельный адрес на каждый язык. Иначе для бота существует\nтолько английская версия, и немецкие/русские страницы просто не попадают в индекс.","operationId":"lang_page_de_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ru":{"get":{"summary":"Lang Page","description":"Постоянный адрес языка: /ru, /de, /en.\n\nЗачем именно так (нашёл Sonnet, 05.10.2026): поисковые роботы и нейросети НЕ ходят по\nпараметрам вида ?lang= — им нужен отдельный адрес на каждый язык. Иначе для бота существует\nтолько английская версия, и немецкие/русские страницы просто не попадают в индекс.","operationId":"lang_page_ru_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/en":{"get":{"summary":"Lang Page","description":"Постоянный адрес языка: /ru, /de, /en.\n\nЗачем именно так (нашёл Sonnet, 05.10.2026): поисковые роботы и нейросети НЕ ходят по\nпараметрам вида ?lang= — им нужен отдельный адрес на каждый язык. Иначе для бота существует\nтолько английская версия, и немецкие/русские страницы просто не попадают в индекс.","operationId":"lang_page_en_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/inv/{token}":{"get":{"summary":"Open Pay Link","description":"Короткая ссылка: переводит клиента на настоящую страницу оплаты Lava.","operationId":"open_pay_link_inv__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/checkout":{"post":{"tags":["payments"],"summary":"Checkout","operationId":"checkout_api_v1_payments_checkout_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/webhook":{"post":{"tags":["payments"],"summary":"Webhook","operationId":"webhook_api_v1_payments_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/payments/{subscription_id}/refresh":{"post":{"tags":["payments"],"summary":"Refresh Payment","description":"Спрашивает у Lava состояние счёта и, если он оплачен, включает подписку.\n\nНужно потому, что ссылка на оплату (особенно СБП) живёт ограниченное время,\nа уведомление от Lava может не дойти.","operationId":"refresh_payment_api_v1_payments__subscription_id__refresh_post","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"integer","title":"Subscription Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/{subscription_id}/new-link":{"post":{"tags":["payments"],"summary":"Recreate Link","description":"Выпускает СВЕЖУЮ ссылку на оплату вместо протухшей (та же сумма и тариф).","operationId":"recreate_link_api_v1_payments__subscription_id__new_link_post","parameters":[{"name":"subscription_id","in":"path","required":true,"schema":{"type":"integer","title":"Subscription Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/billing/autorenew":{"get":{"tags":["payments"],"summary":"Autorenew Status","description":"Состояние автоплатежа: включён ли, по какому тарифу, до какой даты.","operationId":"autorenew_status_api_v1_billing_autorenew_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Autorenew Status Api V1 Billing Autorenew Get"}}}}}},"post":{"tags":["payments"],"summary":"Set Autorenew","description":"Включить/выключить автоплатёж из кабинета.\n\nВыключение — это отмена подписки у Lava (иначе она продолжит списывать),\nпоэтому проверяем ответ провайдера и честно сообщаем, если не получилось.","operationId":"set_autorenew_api_v1_billing_autorenew_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Set Autorenew Api V1 Billing Autorenew Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/payments/history":{"get":{"tags":["payments"],"summary":"History","operationId":"history_api_v1_payments_history_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PaymentItem"},"type":"array","title":"Response History Api V1 Payments History Get"}}}}}}},"/api/v1/resolve/{token}":{"get":{"tags":["payments"],"summary":"Resolve Pay Link","description":"Отдаёт целевой адрес оплаты по короткому коду (для редиректа на pay.duebuddy.work).\n\nНужен, чтобы короткая ссылка вела на кассу Lava ОДНИМ переходом: страница\npay.duebuddy.work получает адрес здесь и сразу перенаправляет клиента.","operationId":"resolve_pay_link_api_v1_resolve__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/track/{token}.gif":{"get":{"summary":"Track Open","description":"Read-tracking pixel: mark the letter opened (first open only) and return a 1x1 GIF.","operationId":"track_open_track__token__gif_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews":{"get":{"summary":"List Reviews","description":"Approved reviews, newest first — consumed by the landing-page build step.","operationId":"list_reviews_reviews_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/review-photo/{review_id}":{"get":{"summary":"Review Photo","description":"Serve an approved review's avatar (self-hosted, no external storage).","operationId":"review_photo_review_photo__review_id__get","parameters":[{"name":"review_id","in":"path","required":true,"schema":{"type":"integer","title":"Review Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/callback":{"get":{"summary":"Oauth Callback","description":"Google redirects here after the user consents. Exchanges the code and\nstores the (encrypted) refresh token against the Telegram user carried in state.","operationId":"oauth_callback_oauth_callback_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"Body_api_parse_v1_parse_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"country":{"type":"string","title":"Country","default":"de"}},"type":"object","required":["file"],"title":"Body_api_parse_v1_parse_post"},"Body_parse_upload_api_v1_parse_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"country":{"type":"string","title":"Country","default":"de"},"source":{"type":"string","title":"Source","default":"upload"}},"type":"object","required":["file"],"title":"Body_parse_upload_api_v1_parse_upload_post"},"CheckoutIn":{"properties":{"plan_code":{"type":"string","title":"Plan Code"},"period":{"type":"string","enum":["m","y"],"title":"Period","default":"m"},"payment_method":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Payment Method"}},"type":"object","required":["plan_code"],"title":"CheckoutIn"},"CheckoutOut":{"properties":{"pay_url":{"type":"string","title":"Pay Url"},"amount_rub":{"type":"number","title":"Amount Rub"},"subscription_id":{"type":"integer","title":"Subscription Id"}},"type":"object","required":["pay_url","amount_rub","subscription_id"],"title":"CheckoutOut"},"CurrentPlanOut":{"properties":{"plan_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Code"},"period":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Period"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"},"plan_paid":{"type":"boolean","title":"Plan Paid","default":false},"days_left":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Days Left"}},"type":"object","title":"CurrentPlanOut"},"DatevExportIn":{"properties":{"job_ids":{"items":{"type":"integer"},"type":"array","maxItems":500,"title":"Job Ids"},"consultant_no":{"type":"string","maxLength":20,"title":"Consultant No","default":""},"client_no":{"type":"string","maxLength":20,"title":"Client No","default":""},"account":{"type":"string","maxLength":10,"title":"Account","default":"1200"},"contra_account":{"type":"string","maxLength":10,"title":"Contra Account","default":"8400"},"bu_key":{"type":"string","maxLength":10,"title":"Bu Key","default":""}},"type":"object","title":"DatevExportIn"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"LeadIn":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"company":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Company"},"pages_per_month":{"anyOf":[{"type":"integer","maximum":10000000.0,"minimum":0.0},{"type":"null"}],"title":"Pages Per Month"},"comment":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Comment"},"source":{"type":"string","maxLength":40,"title":"Source","default":"site"},"lang":{"type":"string","maxLength":5,"title":"Lang","default":""}},"type":"object","required":["email"],"title":"LeadIn"},"MeOut":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"type":"string","title":"Name","default":""},"lang":{"type":"string","title":"Lang","default":"ru"},"tier":{"type":"string","title":"Tier","default":"starter"},"plan_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Code"},"plan_paid":{"type":"boolean","title":"Plan Paid","default":false},"free_parses_total":{"type":"integer","title":"Free Parses Total","default":1},"free_parses_used":{"type":"integer","title":"Free Parses Used","default":0},"free_parses_left":{"type":"integer","title":"Free Parses Left","default":1}},"type":"object","required":["id"],"title":"MeOut"},"OkOut":{"properties":{"ok":{"type":"boolean","title":"Ok","default":true}},"type":"object","title":"OkOut"},"PaymentItem":{"properties":{"plan_code":{"type":"string","title":"Plan Code"},"period":{"type":"string","title":"Period"},"amount_rub":{"type":"number","title":"Amount Rub"},"status":{"type":"string","title":"Status"},"paid_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Paid At"},"provider_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider Ref"}},"type":"object","required":["plan_code","period","amount_rub","status"],"title":"PaymentItem"},"PinIn":{"properties":{"pin":{"type":"string","title":"Pin"},"current":{"type":"string","title":"Current","default":""}},"type":"object","required":["pin"],"title":"PinIn"},"PlanOut":{"properties":{"code":{"type":"string","title":"Code"},"name":{"type":"string","title":"Name"},"price_month_rub":{"type":"integer","title":"Price Month Rub"},"price_year_rub":{"type":"integer","title":"Price Year Rub"},"features":{"items":{"type":"string"},"type":"array","title":"Features"}},"type":"object","required":["code","name","price_month_rub","price_year_rub","features"],"title":"PlanOut"},"ReviewIn":{"properties":{"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"stars":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Stars"},"text":{"type":"string","maxLength":1500,"title":"Text","default":""}},"type":"object","required":["name","stars"],"title":"ReviewIn"},"SelectIn":{"properties":{"plan_code":{"type":"string","title":"Plan Code"},"period":{"type":"string","enum":["m","y"],"title":"Period","default":"m"}},"type":"object","required":["plan_code"],"title":"SelectIn"},"SelectOut":{"properties":{"ok":{"type":"boolean","title":"Ok","default":true},"plan_code":{"type":"string","title":"Plan Code"},"period":{"type":"string","title":"Period"},"amount_rub":{"type":"integer","title":"Amount Rub"},"payment_required":{"type":"boolean","title":"Payment Required","default":true}},"type":"object","required":["plan_code","period","amount_rub"],"title":"SelectOut"},"StartIn":{"properties":{"email":{"type":"string","title":"Email"},"lang":{"type":"string","title":"Lang","default":""}},"type":"object","required":["email"],"title":"StartIn"},"UpgradeOut":{"properties":{"from_plan":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From Plan"},"to_plan":{"type":"string","title":"To Plan"},"upgrade":{"type":"boolean","title":"Upgrade"},"amount_rub":{"type":"integer","title":"Amount Rub"},"full_price_rub":{"type":"integer","title":"Full Price Rub"},"reason":{"type":"string","title":"Reason"}},"type":"object","required":["to_plan","upgrade","amount_rub","full_price_rub","reason"],"title":"UpgradeOut"},"UserOut":{"properties":{"id":{"type":"integer","title":"Id"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"type":"string","title":"Name","default":""},"lang":{"type":"string","title":"Lang","default":"ru"},"tier":{"type":"string","title":"Tier","default":"starter"}},"type":"object","required":["id"],"title":"UserOut"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyOut":{"properties":{"pin_required":{"type":"boolean","title":"Pin Required","default":false},"ok":{"type":"boolean","title":"Ok","default":true},"user":{"$ref":"#/components/schemas/UserOut"}},"type":"object","required":["user"],"title":"VerifyOut"}}}}