{"openapi":"3.1.0","info":{"title":"Qaaf AI Backend","version":"0.1.0"},"paths":{"/login":{"get":{"summary":"Login Page","operationId":"login_page_login_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Login","operationId":"login_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/register":{"get":{"summary":"Register Page","operationId":"register_page_register_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Register","operationId":"register_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserCreateWithReferral"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/r/{code}":{"get":{"summary":"Referral Link","description":"A partner's link. Remembers the code for a month and shows the site.\n\nThe cookie is what /register and the Google sign-in read when the\naccount is created. Nothing is written to the database on a visit: a\nlink shared in a group is opened by many people who never sign up.","operationId":"referral_link_r__code__get","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/logout":{"get":{"summary":"Logout","operationId":"logout_logout_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/google":{"get":{"summary":"Auth Google","description":"Send the visitor to Google, with a state value to come back with.","operationId":"auth_google_auth_google_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/auth/google/callback":{"get":{"summary":"Auth Google Callback","operationId":"auth_google_callback_auth_google_callback_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/app/connect":{"get":{"summary":"App Connect","description":"Signs a person into the Android app using the browser.\n\nThe app has its own Google sign-in through Play Services, and it is one\ntap when it works. It stops working for reasons nobody holding the phone\ncan see or fix -- an unregistered signing certificate, an out of date\nPlay Services, a device with no Google account at all -- and it fails\nwith a code rather than an explanation.\n\nThis is the way out of that. The browser already signs people in with\nGoogle every day on this site; the app opens that same flow in a Custom\nTab and gets handed a single-use code on the way back. It is also what\nGoogle's own guidance for native apps recommends, and it needs no\ncertificate registered anywhere.\n\nA session already sitting in the browser is deliberately not reused. It\nbelongs to whoever last signed into the website here, which is a guess at\nwho is holding the phone, and a wrong guess signs someone into the app as\nanother person without ever asking. So every sign-in goes to Google's own\naccount screen, and only the account chosen there is handed over.","operationId":"app_connect_app_connect_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/":{"get":{"summary":"Home","operationId":"home__get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/samples":{"get":{"summary":"Samples Page","operationId":"samples_page_samples_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/tools/translator":{"get":{"summary":"Tool Translator","operationId":"tool_translator_tools_translator_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/supported-languages":{"get":{"summary":"Supported Languages Page","operationId":"supported_languages_page_supported_languages_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/translate/{source_slug}-to-{target_slug}-pdf-book-translator":{"get":{"summary":"Seo Translator Page","operationId":"seo_translator_page_translate__source_slug__to__target_slug__pdf_book_translator_get","parameters":[{"name":"source_slug","in":"path","required":true,"schema":{"type":"string","title":"Source Slug"}},{"name":"target_slug","in":"path","required":true,"schema":{"type":"string","title":"Target Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/arabic-typesetting":{"get":{"summary":"Arabic Typesetting","description":"Dedicated page for the strongest keyword found in the whole project.\n\n`arabic typesetting` returned 1k-10k monthly searches at low competition\nand +900% year on year - more volume than anything else tested except\n`inpage to unicode`, and unlike that one it maps onto a service the\nbusiness already sells. `islamic website design` is the runner-up and\ndeserves the same treatment if this page performs.","operationId":"arabic_typesetting_arabic_typesetting_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/arabic-transliteration":{"get":{"summary":"Arabic Transliteration","operationId":"arabic_transliteration_arabic_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/assistant":{"post":{"summary":"Api Assistant","description":"Answer a visitor's question and hand back pages to send them to.\n\nDeliberately does not mint a guest trial or charge credits: this is\nsupport, not a tool, and a credit prompt at the door would stop people\nasking the questions that lead to a sale.","operationId":"api_assistant_api_assistant_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/islamic-social-media-management":{"get":{"summary":"Islamic Social Media Lms","description":"Managed social media and LMS for Islamic institutions.\n\nThe differentiator, and the whole reason this page exists: the competing\nagencies (Munadi, Ummah Design, Media Feathers) sell design and posting.\nNone of them put scholarly review in front of the publish button. That is\nwhat the page leads with.","operationId":"islamic_social_media_lms_islamic_social_media_management_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/privacy-policy":{"get":{"summary":"Privacy Policy","description":"Required by Google before an External OAuth app can be published.","operationId":"privacy_policy_privacy_policy_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/terms":{"get":{"summary":"Terms Of Service","operationId":"terms_of_service_terms_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/transliteration":{"get":{"summary":"Transliteration Hub","description":"Hub for every transliteration tool.\n\nExists for crawlability as much as for readers: without it each language\npage hangs off the sitemap alone with no internal links pointing at it,\nwhich is a reliable way to not get indexed.","operationId":"transliteration_hub_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-urdu-transliteration":{"get":{"summary":"Transliteration Urdu","operationId":"transliteration_urdu_english_to_urdu_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-japanese-transliteration":{"get":{"summary":"Transliteration Japanese","operationId":"transliteration_japanese_english_to_japanese_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/chinese-transliteration":{"get":{"summary":"Transliteration Chinese","operationId":"transliteration_chinese_chinese_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-bangla-transliteration":{"get":{"summary":"Transliteration Bangla","operationId":"transliteration_bangla_english_to_bangla_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-russian-transliteration":{"get":{"summary":"Transliteration Russian","operationId":"transliteration_russian_english_to_russian_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-tamil-transliteration":{"get":{"summary":"Transliteration Tamil","operationId":"transliteration_tamil_english_to_tamil_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-malayalam-transliteration":{"get":{"summary":"Transliteration Malayalam","operationId":"transliteration_malayalam_english_to_malayalam_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-gujarati-transliteration":{"get":{"summary":"Transliteration Gujarati","operationId":"transliteration_gujarati_english_to_gujarati_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-telugu-transliteration":{"get":{"summary":"Transliteration Telugu","operationId":"transliteration_telugu_english_to_telugu_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/english-to-hindi-transliteration":{"get":{"summary":"Transliteration Hindi","operationId":"transliteration_hindi_english_to_hindi_transliteration_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/transliterate":{"post":{"summary":"Api Transliterate","operationId":"api_transliterate_api_transliterate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/transliterate/job/{job_id}":{"get":{"summary":"Api Transliterate Job","description":"Progress and result for a queued transliteration.","operationId":"api_transliterate_job_api_transliterate_job__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"}}}}}}},"/api/transliterate/download/{job_id}":{"get":{"summary":"Api Transliterate Download","description":"Full transliteration as a text file. Only once every section is done.","operationId":"api_transliterate_download_api_transliterate_download__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"}}}}}}},"/api/transliterate/estimate":{"post":{"summary":"Api Transliterate Estimate","description":"Cost before committing, so nobody is surprised by a deduction.","operationId":"api_transliterate_estimate_api_transliterate_estimate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/services":{"get":{"summary":"Services Page","description":"Hub page for the custom software and consultancy side of the business.\n\nJustified regardless of keyword volume: it is the page a referral or an\noutreach reply lands on, and the referral channel is what actually brings\ninstitutional customers. Whether individual service landing pages are\nworth building depends on keyword data we have not gathered yet.","operationId":"services_page_services_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/book-digitization-service":{"get":{"summary":"Digitization Service","description":"Service page for institutional buyers.\n\n`book digitization service` was the only keyword tested that had both\nreal volume and institutional intent, with top-of-page bids around\nPKR 1,486 - a small, high-value market. Deliberately a service page\nrather than a blog post: it is aimed at someone with a budget and an\narchive, not a reader.","operationId":"digitization_service_book_digitization_service_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/tools/handwritten":{"get":{"summary":"Tool Handwritten","operationId":"tool_handwritten_tools_handwritten_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/transcribe/{source_slug}-audio-to-text":{"get":{"summary":"Seo Audio Transcribe Page","operationId":"seo_audio_transcribe_page_transcribe__source_slug__audio_to_text_get","parameters":[{"name":"source_slug","in":"path","required":true,"schema":{"type":"string","title":"Source Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/transcribe/{source_slug}-audio-to-{target_slug}-text":{"get":{"summary":"Seo Audio Translate Page","operationId":"seo_audio_translate_page_transcribe__source_slug__audio_to__target_slug__text_get","parameters":[{"name":"source_slug","in":"path","required":true,"schema":{"type":"string","title":"Source Slug"}},{"name":"target_slug","in":"path","required":true,"schema":{"type":"string","title":"Target Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/audio":{"get":{"summary":"Tool Audio","operationId":"tool_audio_tools_audio_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/upload/":{"post":{"summary":"Upload Book","operationId":"upload_book_upload__post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_book_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"}}}}}}},"/status/{book_id}":{"get":{"summary":"Check Status","operationId":"check_status_status__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/download/{book_id}":{"get":{"summary":"Download Book","operationId":"download_book_download__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/download-source/{book_id}":{"get":{"summary":"Download Source File","operationId":"download_source_file_download_source__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/my-files":{"get":{"summary":"My Files","operationId":"my_files_my_files_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/billing":{"get":{"summary":"Billing Page","operationId":"billing_page_billing_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/samples/audio":{"get":{"summary":"Audio Samples Page","operationId":"audio_samples_page_samples_audio_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/media/{kind}/{name}":{"get":{"summary":"Media File","description":"A campaign image or a review voice note, streamed from the bucket.\n\nThe files live in the bucket because the web server's disk does not\nsurvive a deploy; they are served from here so the bucket stays private\nand every file has a qaafai.com URL for the app to carry around.","operationId":"media_file_media__kind___name__get","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/reviews":{"get":{"summary":"Admin Reviews","description":"The reviews the homepage and the app show, and a form to add one.\n\nThe owner asks customers for reviews and they arrive as voice notes and\nmessages; this is where they go in, without a deploy. Names are shown as\nthe customer agreed -- a first name, an initial, a title -- and never an\norganisation, for the reason recorded in CLAUDE.md.","operationId":"admin_reviews_admin_reviews_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Admin Add Review","operationId":"admin_add_review_admin_reviews_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_add_review_admin_reviews_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/reviews/{review_id}/toggle":{"post":{"summary":"Admin Toggle Review","operationId":"admin_toggle_review_admin_reviews__review_id__toggle_post","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"}}}}}}},"/admin/reviews/{review_id}/delete":{"post":{"summary":"Admin Delete Review","operationId":"admin_delete_review_admin_reviews__review_id__delete_post","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"}}}}}}},"/admin/notifications":{"get":{"summary":"Admin Notifications","description":"Compose a notification and choose who gets it and when.\n\nSent by the worker, not from here: see app/services/campaigns.py. The\npage shows what is scheduled, what went out, and how many devices each\naudience currently reaches, so \"all users\" is a number before it is a\nbutton.","operationId":"admin_notifications_admin_notifications_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}},"post":{"summary":"Admin Create Notification","operationId":"admin_create_notification_admin_notifications_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_admin_create_notification_admin_notifications_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/notifications/{campaign_id}/cancel":{"post":{"summary":"Admin Cancel Notification","operationId":"admin_cancel_notification_admin_notifications__campaign_id__cancel_post","parameters":[{"name":"campaign_id","in":"path","required":true,"schema":{"type":"integer","title":"Campaign Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/earn":{"get":{"summary":"Earn Page","description":"The referral offer, and -- signed in -- the person's own link and numbers.\n\n`?code=` shows the posts and pictures for that code without signing\nin: the app opens the page this way, and a partner can hand the URL\nto whoever runs their social media. A code is made to be public, so\nnothing private is shown for it -- the numbers need the account.","operationId":"earn_page_earn_get","parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string","title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api":{"get":{"summary":"Api Page","description":"The API: what it is, what it costs, how to plug it into a CAT tool.\n\nSigned in, the top of the page is the account's keys and last 30\ndays; signed out, it is the offer and a button to make an account.\nA key is shown once, right after it is made, on this same page.","operationId":"api_page_api_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/api/keys":{"post":{"summary":"Api Key Create","operationId":"api_key_create_api_keys_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_api_key_create_api_keys_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/xliff":{"post":{"summary":"Api Xliff Form","description":"The XLIFF pre-translation, from the page rather than from a key.\n\nA memoQ translator is not a developer and should not have to run\ncurl to try this. Same engine, same price, same ledger; the browser\nsession stands in for the key.","operationId":"api_xliff_form_api_xliff_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_api_xliff_form_api_xliff_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/keys/{key_id}/revoke":{"post":{"summary":"Api Key Revoke","operationId":"api_key_revoke_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":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/earn/card/{code}/{card_id}.svg":{"get":{"summary":"Earn Card","description":"One ready-made post as a picture, with this code's QR and link in it.","operationId":"earn_card_earn_card__code___card_id__svg_get","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}},{"name":"card_id","in":"path","required":true,"schema":{"type":"string","title":"Card Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/earn/poster/{code}":{"get":{"summary":"Earn Poster","description":"A printable A4 poster carrying one partner's code and QR.","operationId":"earn_poster_earn_poster__code__get","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string","title":"Code"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/referrals":{"get":{"summary":"Admin Referrals","description":"Every partner, what their referrals bought, and what is owed.\n\nSorted by what is unpaid, so the top of the page is the month's payout\nlist. Institutions the owner set up sit in the same list as anyone\nwho shared a link; the only difference is a name and a statement.","operationId":"admin_referrals_admin_referrals_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/referrals/{user_id}":{"get":{"summary":"Admin Referral Partner","description":"One partner: their ledger with the buyers named, and the payout button.","operationId":"admin_referral_partner_admin_referrals__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/referrals/{user_id}/partner":{"post":{"summary":"Admin Referral Partner Save","description":"The institution fields: a name for their messages, a contact, notes.","operationId":"admin_referral_partner_save_admin_referrals__user_id__partner_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_admin_referral_partner_save_admin_referrals__user_id__partner_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/referrals/{user_id}/paid":{"post":{"summary":"Admin Referral Mark Paid","description":"The owner has paid this partner; every unpaid row becomes paid, dated now.","operationId":"admin_referral_mark_paid_admin_referrals__user_id__paid_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_admin_referral_mark_paid_admin_referrals__user_id__paid_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/referrals/lookup":{"post":{"summary":"Admin Referral Lookup","description":"Find an account by email and open it as a partner, e.g. to set up an institution.","operationId":"admin_referral_lookup_admin_referrals_lookup_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_admin_referral_lookup_admin_referrals_lookup_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/referrals/{user_id}/statement":{"get":{"summary":"Admin Referral Statement","description":"A month's statement for one partner, laid out to print.\n\nAn institution wants paper. This is a page with nothing on it but the\nstatement, styled for the browser's Print → Save as PDF.","operationId":"admin_referral_statement_admin_referrals__user_id__statement_get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}},{"name":"month","in":"query","required":false,"schema":{"type":"string","default":"","title":"Month"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin":{"get":{"summary":"Admin Panel","operationId":"admin_panel_admin_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/admin/close-ticket":{"post":{"summary":"Close Ticket","operationId":"close_ticket_admin_close_ticket_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketAction"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/update-settings":{"post":{"summary":"Update Settings","operationId":"update_settings_admin_update_settings_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/promote":{"post":{"summary":"Promote User","operationId":"promote_user_admin_promote_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminPromote"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/reset-password":{"post":{"summary":"Admin Reset Pass","operationId":"admin_reset_pass_admin_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PassReset"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/support":{"get":{"summary":"Support Page","operationId":"support_page_support_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/support/submit":{"post":{"summary":"Submit Ticket","operationId":"submit_ticket_support_submit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TicketCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/add-credits":{"post":{"summary":"Add Credits","operationId":"add_credits_admin_add_credits_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/remove-credits":{"post":{"summary":"Remove Credits","operationId":"remove_credits_admin_remove_credits_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/books/{book_id}":{"delete":{"summary":"Delete Book","operationId":"delete_book_books__book_id__delete","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/download-pdf/{book_id}":{"get":{"summary":"Download Book Pdf","operationId":"download_book_pdf_download_pdf__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/download/partial/{book_id}":{"get":{"summary":"Download Partial Book","operationId":"download_partial_book_download_partial__book_id__get","parameters":[{"name":"book_id","in":"path","required":true,"schema":{"type":"integer","title":"Book Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/tools/app-builder":{"get":{"summary":"App Builder Tool","description":"App Builder is not ready for users yet.\n\nThe route still answers 200 with a Coming Soon page rather than\nredirecting or 404ing, because 21 blog articles link here; breaking those\nlinks would waste the authority they carry. Admins still reach the real\nbuilder so work can continue on it.","operationId":"app_builder_tool_tools_app_builder_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/robots.txt":{"get":{"summary":"Robots Txt","description":"robots.txt.\n\nTwo jobs beyond \"allow everything\". First, keep crawlers out of the\nroutes that are private or worthless to index: the admin panel, a\nsigned-in user's files, the download endpoints and the JSON API. None of\nthose are in the sitemap, but a crawler that finds one from a link will\nfetch it, and the download endpoints cost real work to serve.\n\nSecond, name the AI crawlers explicitly. They are already permitted by\nthe wildcard rule and were verified reaching the site, so these blocks\nchange no behaviour today. They are a standing declaration: if a default\nsomewhere ever flips to blocking AI crawlers, an explicit Allow is what\nkeeps this site readable by the answer engines.","operationId":"robots_txt_robots_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/b2062c4056aa4d22b0744215eaa1309f.txt":{"get":{"summary":"Bing Indexnow","operationId":"bing_indexnow_b2062c4056aa4d22b0744215eaa1309f_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/llms.txt":{"get":{"summary":"Get Llms Txt","description":"Short AI-facing summary of the site.\n\nThis is the file an answer engine reads to learn what Qaaf AI is. It is\ngenerated from docs/QAAFAI-SPEC.md, which is the single source of truth\nfor how the business describes itself -- keep the two in step.\n\nDeliberately carries no prices. A figure quoted before anyone has seen\nthe material commits the business to it, and an engine that reads one\nhere will repeat it forever.","operationId":"get_llms_txt_llms_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/auth/handoff":{"get":{"summary":"Auth Handoff","description":"Sign an app user into the website from a single-use ticket.\n\nThe app holds a bearer token; this browser has its own cookie jar and\nknows nothing about it. Without this, \"add credits\" in the app would\ndrop someone on a login form at the exact moment they were willing to\npay. The app mints a ticket, opens this URL, and the person lands on the\nbilling page already signed in.\n\nThe ticket is consumed on first use, so a link left in browser history\ncannot be replayed.","operationId":"auth_handoff_auth_handoff_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/llms-full.txt":{"get":{"summary":"Get Llms Full Txt","description":"The long form: every service, the reasoning behind each, and the\nanswers to the questions people actually ask. llms.txt is the index;\nthis is the document.","operationId":"get_llms_full_txt_llms_full_txt_get","responses":{"200":{"description":"Successful Response","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/web-stories/{slug}":{"get":{"summary":"Web Stories Gone","operationId":"web_stories_gone_web_stories__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/web-stories":{"get":{"summary":"Web Stories Gone","operationId":"web_stories_gone_web_stories_get","parameters":[{"name":"slug","in":"query","required":false,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/blog":{"get":{"summary":"Blog Index","operationId":"blog_index_blog_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/blog/{slug}":{"get":{"summary":"Blog Post","operationId":"blog_post_blog__slug__get","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/image-sitemap.xml":{"get":{"summary":"Image Sitemap","description":"A dedicated image sitemap.\n\nThe site has ~50 original illustrations that no crawler currently knows\nabout, because images are only discovered by parsing the page that\nembeds them. Listing them here puts them in Google Images, which is a\nseparate search surface this site has never appeared in.\n\nEvery image is attached to the page it appears on -- an image sitemap\nentry is a property of a URL, not a standalone record -- so the blog\nimages hang off their post and the marketing images off the page that\nuses them.","operationId":"image_sitemap_image_sitemap_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/sitemap":{"get":{"summary":"Html Sitemap","description":"A human-readable index of the whole site.\n\nTwo jobs: it gives the 404 page somewhere to send a lost visitor, and it\ngives every page at least one plain internal link from a crawlable page,\nwhich the deeper language and blog pages otherwise rely on the XML\nsitemap alone for.","operationId":"html_sitemap_sitemap_get","responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}}}}},"/sitemap.xml":{"get":{"summary":"Generate Sitemap","operationId":"generate_sitemap_sitemap_xml_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/jobs":{"post":{"tags":["public-api"],"summary":"Create Job","description":"Start a transcription, OCR or whole-file translation.\n\nThe website's own upload handler does the work -- splitting, page\nranges, pricing, queueing -- with the API user and the API price\nset on the request. Charged when the job is accepted, at the\nsite's estimate for the file times the API multiplier.","operationId":"create_job_v1_jobs_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_job_v1_jobs_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["public-api"],"summary":"List Jobs","operationId":"list_jobs_v1_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","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"}}}}}}},"/v1/jobs/{job_id}":{"get":{"tags":["public-api"],"summary":"Job Status","operationId":"job_status_v1_jobs__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"}}}}}}},"/v1/jobs/{job_id}/text":{"get":{"tags":["public-api"],"summary":"Job Text","description":"Whatever has finished, as text -- the transcript, the pages read so far.","operationId":"job_text_v1_jobs__job_id__text_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"}}}}}}},"/v1/jobs/{job_id}/download":{"get":{"tags":["public-api"],"summary":"Job Download","description":"The finished file: docx (default) or pdf. Partial while running.","operationId":"job_download_v1_jobs__job_id__download_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"docx","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/translate":{"post":{"tags":["public-api"],"summary":"Translate","description":"Translate up to 100 segments. Charged on source characters.","operationId":"translate_v1_translate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/xliff":{"post":{"tags":["public-api"],"summary":"Translate Xliff","description":"Pre-translate a bilingual file exported from a CAT tool.\n\nThe answer is the same file with the empty segments filled in,\nready to import. This is how memoQ users reach the engine until\nthe plugin exists; it works for any tool that exports XLIFF.","operationId":"translate_xliff_v1_xliff_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_translate_xliff_v1_xliff_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/languages":{"get":{"tags":["public-api"],"summary":"Languages List","description":"The names the site's dropdowns use. Any other name is accepted as typed.","operationId":"languages_list_v1_languages_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/translate":{"post":{"tags":["public-api"],"summary":"Translate Alias","operationId":"translate_alias_api_v1_translate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/usage":{"get":{"tags":["public-api"],"summary":"Usage","operationId":"usage_v1_usage_get","parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/me":{"get":{"tags":["public-api"],"summary":"Me","operationId":"me_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/models":{"get":{"tags":["public-api"],"summary":"Models List","operationId":"models_list_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/chat/completions":{"post":{"tags":["public-api"],"summary":"Chat Completions","operationId":"chat_completions_v1_chat_completions_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/auth/register":{"post":{"tags":["api-v1"],"summary":"Register","operationId":"register_api_v1_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/login":{"post":{"tags":["api-v1"],"summary":"Login","operationId":"login_api_v1_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/google":{"post":{"tags":["api-v1"],"summary":"Google Signin","description":"Sign in with an ID token from the Android app.\n\nThe token is verified against Google's keys rather than merely\ndecoded, because unlike the web flow it arrives from the client.","operationId":"google_signin_api_v1_auth_google_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/apple":{"post":{"tags":["api-v1"],"summary":"Apple Signin","description":"Sign in with an identity token from the iPhone app.\n\nApple requires this of an app that offers Google sign-in. The\ntoken is verified against Apple's keys -- see\napp/services/apple_auth.py. Matching is on Apple's stable subject\nfirst and the verified email second, for the same reason as with\nGoogle: a person who made the account on the desktop with a\npassword must land in it, not beside it.\n\nApple sends the email on the first sign-in only. An account is\nnever created without one, so a first sign-in that somehow carries\nnone is refused rather than creating an account nobody can reach.","operationId":"apple_signin_api_v1_auth_apple_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/exchange":{"post":{"tags":["api-v1"],"summary":"Exchange","description":"Turn a single-use code from the browser into a session.\n\nThe other half of /app/connect. The code is minted only for a person\nalready signed in on the website, is good for one redemption inside\ntwo minutes, and carries no identity of its own -- so a code lifted\nfrom a log or a screenshot after the fact is worth nothing.","operationId":"exchange_api_v1_auth_exchange_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/refresh":{"post":{"tags":["api-v1"],"summary":"Refresh","operationId":"refresh_api_v1_auth_refresh_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/me":{"get":{"tags":["api-v1"],"summary":"Me","operationId":"me_api_v1_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"delete":{"tags":["api-v1"],"summary":"Delete Account","description":"Delete the account, from inside the app.\n\nBoth stores require this of an app that has sign-up: a person must\nbe able to remove their account without emailing anyone. The word\nDELETE in the body is the confirmation; the app asks for it on a\ndialog of its own before sending.\n\nWhat goes and what stays:\n\n- Every job is marked deleted, which is what the website's delete\n  does; the worker cancels anything still queued.\n- Devices (push tokens), sign-in tickets and support tickets are\n  removed outright.\n- The account row is kept but emptied: the email is replaced with an\n  address nobody can use, the password and Google link are cleared,\n  the balance zeroed and the account disabled. Transactions stay\n  against the id, because a sale is a record the business has to\n  keep, but nothing on it names the person any more.\n\nTokens are keyed by email, so replacing the email is also what makes\nevery token this account ever issued stop working, on every device,\nat once.","operationId":"delete_account_api_v1_me_delete","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/auth/handoff":{"post":{"tags":["api-v1"],"summary":"Handoff","description":"A single-use link that opens the website already signed in.\n\nWithout this, \"add credits\" sends someone to a login form at the one\nmoment they were willing to pay.","operationId":"handoff_api_v1_auth_handoff_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","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/credits":{"get":{"tags":["api-v1"],"summary":"Credits","operationId":"credits_api_v1_credits_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/me/stats":{"get":{"tags":["api-v1"],"summary":"My Stats","description":"Lifetime totals for the dashboard strip.\n\nEvery figure here is counted from the database, never estimated. Two\nof them needed care, and the shape of this response reflects that.\n\n`pages_digitized` counts only scanned and handwritten work, because\nthat is the only job type where a real page count survives -- it is\nrecorded per chunk during OCR. `Book.total_pages` is the number of\nsections, not pages, despite the name, so summing it would produce a\nconfident wrong number.\n\n`minutes_transcribed` reads a duration that was previously computed\nfor pricing and thrown away, so it is correct from the moment that\ncolumn was added and blind to anything older. `stats_since` says when\nthat was, and the app should show it rather than implying the total\ncovers all time.","operationId":"my_stats_api_v1_me_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/billing/packages":{"get":{"tags":["api-v1"],"summary":"Billing Packages","description":"What a top-up buys.\n\nThe app shows these and buys them through Google Play; the Play\nproduct id for each is in the list. Serving them rather than\ncompiling them in means a price change is a deploy, not a store\nrelease -- though the price Google charges is the one set in Play\nConsole, and the two have to be kept the same by hand.\n\n`signup_credits` lets the app recognise someone still on their\nstarting balance, who has not yet had a reason to think about a\npackage.","operationId":"billing_packages_api_v1_billing_packages_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/billing/google/verify":{"post":{"tags":["api-v1"],"summary":"Verify Google Purchase","description":"Turn a Google Play purchase into credits, once.\n\nThe app sends the product id and the purchase token Google handed\nit. The server asks Google whether that token is a real, paid\npurchase of that product -- the app's word is not taken for it --\nand only then adds the credits.\n\nOnce is enforced by the database rather than by good behaviour: the\ntoken is written into the transaction's unique id column, so a\nsecond call with the same token, from a retry or from a phone that\ncrashed between paying and hearing back, finds the row and returns\nthe same answer without crediting again. Two calls racing collide on\nthe unique constraint and the loser reads the winner's row.","operationId":"verify_google_purchase_api_v1_billing_google_verify_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/billing/apple/verify":{"post":{"tags":["api-v1"],"summary":"Verify Apple Purchase","description":"Turn an App Store purchase into credits, once.\n\nThe iOS app sends the product id and the signed transaction StoreKit\nhanded it. The signature is Apple's and is checked here against\nApple's root certificate -- see app/services/app_store.py -- so the\napp's word is never what credits the account.\n\nOnce is enforced the same way as for Google: the transaction id is\nwritten into the transaction's unique id column, so a retry finds\nthe row and returns the same answer without crediting again.","operationId":"verify_apple_purchase_api_v1_billing_apple_verify_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/jobs":{"post":{"tags":["api-v1"],"summary":"Create Job","description":"Create a job by handing straight to the website's own handler.\n\nThat handler is ~300 lines of PDF splitting, YouTube fetching, page\ncounting and credit arithmetic. Copying it here would guarantee the\ntwo drift apart, so the authenticated user is put on request.state\nand the same function runs.","operationId":"create_job_api_v1_jobs_post","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_create_job_api_v1_jobs_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["api-v1"],"summary":"List Jobs","operationId":"list_jobs_api_v1_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"type","in":"query","required":false,"schema":{"type":"string","title":"Type"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/jobs/{job_id}":{"get":{"tags":["api-v1"],"summary":"Job Detail","operationId":"job_detail_api_v1_jobs__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":{"tags":["api-v1"],"summary":"Delete Job","operationId":"delete_job_api_v1_jobs__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/jobs/estimate":{"post":{"tags":["api-v1"],"summary":"Estimate Job","description":"What a job will cost, where that can honestly be known in advance.\n\nScanned pages and transliteration are priced per unit, so those are\nexact. Translation and audio are priced from the token count of the\nactual file, which cannot be known before it is uploaded and split.\nReturning a made-up figure for those would be worse than returning\nnone, so `exact: false` says plainly that the real charge is\nconfirmed at submission.","operationId":"estimate_job_api_v1_jobs_estimate_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/rates":{"get":{"tags":["api-v1"],"summary":"Rates","operationId":"rates_api_v1_rates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/languages":{"get":{"tags":["api-v1"],"summary":"List Languages","operationId":"list_languages_api_v1_languages_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/jobs/{job_id}/download":{"get":{"tags":["api-v1"],"summary":"Download Job","operationId":"download_job_api_v1_jobs__job_id__download_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"docx","title":"Format"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/jobs/{job_id}/partial":{"get":{"tags":["api-v1"],"summary":"Download Partial","description":"Finished sections only, for a job still running or abandoned.","operationId":"download_partial_api_v1_jobs__job_id__partial_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"}}}}}}},"/api/v1/jobs/{job_id}/text":{"get":{"tags":["api-v1"],"summary":"Job Text","description":"The finished text, as text.\n\nThe download endpoints return a .docx, which is right for a book\nsomeone is going to edit and wrong for four photographed pages that a\nperson wants to read now and paste into a message. Scanning a page\nand being handed a file to open in another app is a worse answer than\nsimply showing what the page says.\n\nReturns whatever has finished, not only whole jobs: a scan of forty\npages is readable from the first section onwards, and waiting for the\nlast one before showing any of it helps nobody.","operationId":"job_text_api_v1_jobs__job_id__text_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"}}}}}}},"/api/v1/transliterate":{"post":{"tags":["api-v1"],"summary":"Transliterate","description":"Instant for short text, a background job past the chunk limit.\n\nThe website's handler already implements chunking, the credit charge\nand the rate limit, so this sets the user and calls it.","operationId":"transliterate_api_v1_transliterate_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/transliterate/{job_id}":{"get":{"tags":["api-v1"],"summary":"Transliterate Job","operationId":"transliterate_job_api_v1_transliterate__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"}}}}}}},"/api/v1/assistant":{"post":{"tags":["api-v1"],"summary":"Assistant","description":"The same assistant the website runs, for the app.\n\nHands to the website's handler, which owns the prompt, the link\nallowlist and the rate limit. Those rules matter more here than the\ncode sharing does: the assistant must not invent a price or a URL,\nand there should be exactly one place where that is enforced.\n\nLike the web version it charges nothing. This is support, not a tool,\nand a credit prompt in front of a question is how a sale is lost.","operationId":"assistant_api_v1_assistant_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/services":{"get":{"tags":["api-v1"],"summary":"Services","description":"Marketing copy for the services screen.\n\nServed rather than compiled in, so wording can change without an app\nrelease. Carries no prices, by the same rule as everywhere else.","operationId":"services_api_v1_services_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/testimonials":{"get":{"tags":["api-v1"],"summary":"Testimonials List","description":"What people have said, for the app's services screen.\n\nThe same list the homepage renders. Served rather than compiled in,\nso a new review reaches phones without an app release.","operationId":"testimonials_list_api_v1_testimonials_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/devices":{"post":{"tags":["api-v1"],"summary":"Register Device","operationId":"register_device_api_v1_devices_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["api-v1"],"summary":"Unregister Device","operationId":"unregister_device_api_v1_devices_delete","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/me/referrals":{"get":{"tags":["api-v1"],"summary":"My Referrals","description":"The person's own referral link, numbers and ready messages.\n\nNumbers only: how many signed up, how many bought, what is earned\nand owed. Never who -- the people they referred did not agree to\nbe listed.","operationId":"my_referrals_api_v1_me_referrals_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/admin/stats":{"get":{"tags":["api-v1"],"summary":"Admin Stats","operationId":"admin_stats_api_v1_admin_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/v1/admin/users":{"get":{"tags":["api-v1"],"summary":"Admin Users","operationId":"admin_users_api_v1_admin_users_get","parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","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/admin/users/{user_id}":{"get":{"tags":["api-v1"],"summary":"Admin User Detail","operationId":"admin_user_detail_api_v1_admin_users__user_id__get","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/users/{user_id}/credits":{"post":{"tags":["api-v1"],"summary":"Admin Adjust Credits","operationId":"admin_adjust_credits_api_v1_admin_users__user_id__credits_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User 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/admin/users/{user_id}/promote":{"post":{"tags":["api-v1"],"summary":"Admin Promote","operationId":"admin_promote_api_v1_admin_users__user_id__promote_post","parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"integer","title":"User 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/admin/tickets":{"get":{"tags":["api-v1"],"summary":"Admin Tickets","operationId":"admin_tickets_api_v1_admin_tickets_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","default":"open","title":"Status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/tickets/{ticket_id}/close":{"post":{"tags":["api-v1"],"summary":"Admin Close Ticket","operationId":"admin_close_ticket_api_v1_admin_tickets__ticket_id__close_post","parameters":[{"name":"ticket_id","in":"path","required":true,"schema":{"type":"integer","title":"Ticket Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/admin/broadcast":{"get":{"tags":["api-v1"],"summary":"Broadcast Audience","description":"How many devices a broadcast would actually reach.\n\nShown before sending, because \"notify everyone\" means something very\ndifferent at 6 devices than at 600, and the admin should know which\none they are about to do.","operationId":"broadcast_audience_api_v1_admin_broadcast_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"post":{"tags":["api-v1"],"summary":"Send Broadcast","description":"Send one notification to every registered device.\n\nDeliberately blunt: no scheduling, no segments, no templates. This\nexists so an announcement can go out, and every feature added to it\nis another way to send the wrong thing to everyone at once.\n\nIt lands on the news channel, which is low importance and silent, so\nan announcement can never make a phone ring. Anything urgent enough\nto ring is not an announcement.","operationId":"send_broadcast_api_v1_admin_broadcast_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Payload"}}},"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/admin/jobs/failed":{"get":{"tags":["api-v1"],"summary":"Admin Failed Jobs","operationId":"admin_failed_jobs_api_v1_admin_jobs_failed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AdminPromote":{"properties":{"user_id":{"type":"integer","title":"User Id"}},"type":"object","required":["user_id"],"title":"AdminPromote"},"Body_admin_add_review_admin_reviews_post":{"properties":{"name":{"type":"string","title":"Name","default":""},"detail":{"type":"string","title":"Detail","default":""},"quote":{"type":"string","title":"Quote","default":""},"lang":{"type":"string","title":"Lang","default":"en"},"sort_order":{"type":"integer","title":"Sort Order","default":0},"audio":{"type":"string","format":"binary","title":"Audio"}},"type":"object","title":"Body_admin_add_review_admin_reviews_post"},"Body_admin_create_notification_admin_notifications_post":{"properties":{"title":{"type":"string","title":"Title","default":""},"body":{"type":"string","title":"Body","default":""},"audience":{"type":"string","title":"Audience","default":"all"},"user_ids":{"items":{"type":"string"},"type":"array","title":"User Ids","default":[]},"when":{"type":"string","title":"When","default":"now"},"send_at":{"type":"string","title":"Send At","default":""},"tz_offset":{"type":"integer","title":"Tz Offset","default":0},"repeat":{"type":"string","title":"Repeat","default":"none"},"repeat_until":{"type":"string","title":"Repeat Until","default":""},"image":{"type":"string","format":"binary","title":"Image"}},"type":"object","title":"Body_admin_create_notification_admin_notifications_post"},"Body_admin_referral_lookup_admin_referrals_lookup_post":{"properties":{"email":{"type":"string","title":"Email","default":""}},"type":"object","title":"Body_admin_referral_lookup_admin_referrals_lookup_post"},"Body_admin_referral_mark_paid_admin_referrals__user_id__paid_post":{"properties":{"note":{"type":"string","title":"Note","default":""}},"type":"object","title":"Body_admin_referral_mark_paid_admin_referrals__user_id__paid_post"},"Body_admin_referral_partner_save_admin_referrals__user_id__partner_post":{"properties":{"is_partner":{"type":"string","title":"Is Partner","default":""},"partner_name":{"type":"string","title":"Partner Name","default":""},"partner_contact":{"type":"string","title":"Partner Contact","default":""},"partner_notes":{"type":"string","title":"Partner Notes","default":""}},"type":"object","title":"Body_admin_referral_partner_save_admin_referrals__user_id__partner_post"},"Body_api_key_create_api_keys_post":{"properties":{"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"Body_api_key_create_api_keys_post"},"Body_api_xliff_form_api_xliff_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"target":{"type":"string","title":"Target","default":""},"source":{"type":"string","title":"Source","default":""}},"type":"object","title":"Body_api_xliff_form_api_xliff_post"},"Body_create_job_api_v1_jobs_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"yt_url":{"type":"string","title":"Yt Url"},"source_lang":{"type":"string","title":"Source Lang"},"target_lang":{"type":"string","title":"Target Lang"},"project_type":{"type":"string","title":"Project Type","default":"translation"},"content_category":{"type":"string","title":"Content Category","default":"Islamic"},"range_mode":{"type":"string","title":"Range Mode","default":"full"},"page_start":{"type":"string","title":"Page Start"},"page_end":{"type":"string","title":"Page End"},"is_translation_requested":{"type":"string","title":"Is Translation Requested","default":"false"}},"type":"object","required":["source_lang","target_lang"],"title":"Body_create_job_api_v1_jobs_post"},"Body_create_job_v1_jobs_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"type":{"type":"string","title":"Type","default":"translation"},"source":{"type":"string","title":"Source"},"target":{"type":"string","title":"Target"},"pages":{"type":"string","title":"Pages"},"page_start":{"type":"string","title":"Page Start"},"page_end":{"type":"string","title":"Page End"},"category":{"type":"string","title":"Category","default":"Islamic"}},"type":"object","title":"Body_create_job_v1_jobs_post"},"Body_login_login_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"^password$"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","format":"password","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"format":"password","title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_login_post"},"Body_translate_xliff_v1_xliff_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"target":{"type":"string","title":"Target"},"source":{"type":"string","title":"Source"},"category":{"type":"string","title":"Category","default":"Islamic"}},"type":"object","title":"Body_translate_xliff_v1_xliff_post"},"Body_upload_book_upload__post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"yt_url":{"type":"string","title":"Yt Url"},"source_lang":{"type":"string","title":"Source Lang"},"target_lang":{"type":"string","title":"Target Lang"},"project_type":{"type":"string","title":"Project Type","default":"translation"},"content_category":{"type":"string","title":"Content Category","default":"Islamic"},"range_mode":{"type":"string","title":"Range Mode","default":"full"},"page_start":{"type":"string","title":"Page Start"},"page_end":{"type":"string","title":"Page End"},"is_translation_requested":{"type":"string","title":"Is Translation Requested","default":"false"}},"type":"object","required":["source_lang","target_lang"],"title":"Body_upload_book_upload__post"},"CreditUpdate":{"properties":{"user_id":{"type":"integer","title":"User Id"},"amount":{"type":"number","title":"Amount"},"paid":{"type":"boolean","title":"Paid","default":true}},"type":"object","required":["user_id","amount"],"title":"CreditUpdate"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"PassReset":{"properties":{"user_id":{"type":"integer","title":"User Id"},"new_password":{"type":"string","title":"New Password"}},"type":"object","required":["user_id","new_password"],"title":"PassReset"},"SettingsUpdate":{"properties":{"key":{"type":"string","title":"Key"},"value":{"type":"number","title":"Value"}},"type":"object","required":["key","value"],"title":"SettingsUpdate"},"TicketAction":{"properties":{"ticket_id":{"type":"integer","title":"Ticket Id"}},"type":"object","required":["ticket_id"],"title":"TicketAction"},"TicketCreate":{"properties":{"subject":{"type":"string","title":"Subject"},"message":{"type":"string","title":"Message"}},"type":"object","required":["subject","message"],"title":"TicketCreate"},"UserCreateWithReferral":{"properties":{"email":{"type":"string","title":"Email"},"password":{"type":"string","title":"Password"},"phone":{"type":"string","title":"Phone"},"country":{"type":"string","title":"Country"},"referral_code":{"type":"string","title":"Referral Code","default":""}},"type":"object","required":["email","password","phone","country"],"title":"UserCreateWithReferral"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"}}}}