{"openapi":"3.1.0","info":{"title":"Book Generator API","description":"Backend API for the AI-powered coloring book generator.","version":"1.0.0"},"paths":{"/.well-known/oauth-protected-resource/mcp/":{"get":{"summary":"Oauth Protected Resource Metadata","operationId":"oauth_protected_resource_metadata__well_known_oauth_protected_resource_mcp__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource/mcp":{"get":{"summary":"Oauth Protected Resource Metadata","operationId":"oauth_protected_resource_metadata__well_known_oauth_protected_resource_mcp_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"summary":"Oauth Protected Resource Metadata","operationId":"oauth_protected_resource_metadata__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"summary":"Oauth Authorization Server Metadata","operationId":"oauth_authorization_server_metadata__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/register":{"post":{"summary":"Oauth Register","operationId":"oauth_register_oauth_register_post","responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/authorize":{"get":{"summary":"Oauth Authorize","operationId":"oauth_authorize_oauth_authorize_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/consent":{"get":{"summary":"Oauth Consent Details","operationId":"oauth_consent_details_oauth_consent_get","parameters":[{"name":"request","in":"query","required":true,"schema":{"type":"string","title":"Request"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/approve":{"post":{"summary":"Oauth Approve","operationId":"oauth_approve_oauth_approve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthConsentDecision"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/oauth/token":{"post":{"summary":"Oauth Token","operationId":"oauth_token_oauth_token_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/revoke":{"post":{"summary":"Oauth Revoke","operationId":"oauth_revoke_oauth_revoke_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","description":"Lightweight health check used by load balancers and uptime monitors.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/auth/register":{"post":{"summary":"Register","operationId":"register_api_auth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserRegister"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/login":{"post":{"summary":"Login","operationId":"login_api_auth_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserLogin"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/google":{"post":{"summary":"Google Auth","operationId":"google_auth_api_auth_google_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GoogleAuthRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/refresh":{"post":{"summary":"Refresh Token","operationId":"refresh_token_api_auth_refresh_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefreshRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/me":{"get":{"summary":"Get Current User Info","operationId":"get_current_user_info_api_auth_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/me/email-preferences":{"get":{"summary":"Get Email Preferences","description":"Return the authenticated user's optional marketing consent state.","operationId":"get_email_preferences_api_me_email_preferences_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPreferencesResponse"}}}}},"security":[{"HTTPBearer":[]}]},"put":{"summary":"Update Email Preferences","description":"Update marketing consent and language; service notices remain unaffected.","operationId":"update_email_preferences_api_me_email_preferences_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPreferencesUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPreferencesResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/email/unsubscribe":{"get":{"summary":"Unsubscribe Email","description":"Process a signed one-click marketing unsubscribe link.","operationId":"unsubscribe_email_api_email_unsubscribe_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","minLength":20,"maxLength":4096,"title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/email/webhook":{"post":{"summary":"Resend Email Webhook","description":"Receive signed Resend delivery events and update the email ledger.","operationId":"resend_email_webhook_api_email_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/me/analytics-consent":{"put":{"summary":"Update Analytics Consent","description":"Record the user's cookie-banner decision on their account.\n\nThe Dodo webhook reports a purchase to GA only when this says \"accepted\", so a\nGA client id sent by the browser never counts as consent on its own.","operationId":"update_analytics_consent_api_me_analytics_consent_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsConsentUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsConsentResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/auth/password":{"put":{"summary":"Change Current User Password","operationId":"change_current_user_password_api_auth_password_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangePasswordResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/auth/forgot-password":{"post":{"summary":"Forgot Password","operationId":"forgot_password_api_auth_forgot_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/reset-password":{"post":{"summary":"Reset Password","operationId":"reset_password_api_auth_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/me/default-styles":{"put":{"summary":"Update Current User Default Styles","operationId":"update_current_user_default_styles_api_auth_me_default_styles_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateDefaultStylesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/me/brand":{"get":{"summary":"Get Brand","description":"The caller's brand / series signature (used on covers + the copyright page).\n\nStored inside the per-user cover preset; surfaced standalone so it can be read\nand edited from settings or an inline prompt, independent of the cover flow.","operationId":"get_brand_api_me_brand_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponse"}}}}},"security":[{"HTTPBearer":[]}]},"put":{"summary":"Update Brand","description":"Set the caller's brand without clobbering the rest of their cover preset.\n\nReads the existing preset and re-upserts it with only ``brand_signature``\nchanged (the cover style fields are preserved).","operationId":"update_brand_api_me_brand_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/jobs":{"get":{"summary":"List User Jobs","operationId":"list_user_jobs_api_jobs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":20,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/generate":{"post":{"summary":"Start Generation","description":"Start a new book generation job. Free users get one watermarked book of up to\n3 pages (FREE_MAX_PAGES_PER_BOOK in credits_service).","operationId":"start_generation_api_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartJobResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/generate/quote":{"post":{"summary":"Quote Generation","description":"Price a book before creating it. Never blocks the creation: if the balance or\nthe plan lookup fails, answer with the price the request alone implies and let\nPOST /api/generate (which re-checks credits and plan limits before spending\nanything) be the authority.","operationId":"quote_generation_api_generate_quote_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationQuoteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerationQuoteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/generate/{job_id}/status":{"get":{"summary":"Job Status","operationId":"job_status_api_generate__job_id__status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/edit":{"post":{"summary":"Edit Page Image","description":"Start an AI edit in the background and return immediately.\n\nThe edit makes two Gemini calls (~20s); running it synchronously made the edge\nproxy abort the request at ~16s (HTTP 499) even though the backend finished and\nthe user was charged. The frontend polls ``/op-status`` for the preview.","operationId":"edit_page_image_api_jobs__job_id__images__image_index__edit_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EditImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncOpStartResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/regenerate":{"post":{"summary":"Regenerate Page Image","description":"Start a background regeneration and return immediately. Poll ``/op-status``.","operationId":"regenerate_page_image_api_jobs__job_id__images__image_index__regenerate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AsyncOpStartResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/op-status":{"get":{"summary":"Page Op Status","description":"Poll the result of a background page edit/regenerate for this slot.","operationId":"page_op_status_api_jobs__job_id__images__image_index__op_status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageOpStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/save":{"post":{"summary":"Save Edited Image","operationId":"save_edited_image_api_jobs__job_id__images__image_index__save_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveEditedImageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/frame":{"post":{"summary":"Set Page Frame","description":"Add or remove a deterministic black KDP-safe frame on a page.\n\nThis is a classic image-processing step (pure Pillow, no AI, no credits); it\nruns in well under a second, so it returns synchronously with the updated\nimage URL and framed state.","operationId":"set_page_frame_api_jobs__job_id__images__image_index__frame_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPageFrameRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageFrameResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/frontmatter":{"post":{"summary":"Add Frontmatter Page","description":"Add a front-matter page (copyright/tips/test) to an existing book at the\nfront. Renders in the background (gpt-image); poll the new page's ``/op-status``\nand refresh the job. Insufficient credits → global 402 handler.","operationId":"add_frontmatter_page_api_jobs__job_id__frontmatter_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddFrontmatterRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}/retry":{"post":{"summary":"Retry Failed Image","operationId":"retry_failed_image_api_jobs__job_id__images__image_index__retry_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/images/{image_index}":{"delete":{"summary":"Delete Page","description":"Delete a single front-matter page (copyright/tips/test) from a book and\ncollapse the slot gap. Only the owner can delete it; coloring pages cannot be\ndeleted (they are part of the book's plan). Returns the updated job.","operationId":"delete_page_api_jobs__job_id__images__image_index__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"image_index","in":"path","required":true,"schema":{"type":"integer","title":"Image Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/download":{"get":{"summary":"Download Images Zip","operationId":"download_images_zip_api_jobs__job_id__download_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","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/jobs/{job_id}/download/pdf":{"get":{"summary":"Download Images Pdf","operationId":"download_images_pdf_api_jobs__job_id__download_pdf_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","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/jobs/{job_id}":{"delete":{"summary":"Delete Job","description":"Delete a book and all its artifacts. Only the owner can delete it.","operationId":"delete_job_api_jobs__job_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","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/milestones":{"get":{"summary":"Get Milestones","description":"The signed-in user's album: every sticker with its status and progress,\nplus this year's seasonal windows.","operationId":"get_milestones_api_milestones_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MilestonesResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/jobs/{job_id}/feedback-prompt":{"get":{"summary":"Get Feedback Prompt","description":"Whether to show the rating popup for this book. A missing or foreign job\nanswers ``eligible=false`` (not 404), so the popup simply stays hidden.","operationId":"get_feedback_prompt_api_jobs__job_id__feedback_prompt_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedbackPromptResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/feedback":{"post":{"summary":"Submit Book Feedback","description":"Save the rating (or a \"not now\" when ``dismissed=true``) for a finished\nbook. 404 when the book is missing or not the user's; 409 while it is not\nfinished. A \"not now\" never overwrites an existing rating.","operationId":"submit_book_feedback_api_jobs__job_id__feedback_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookFeedbackRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BookFeedbackResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/feedback/trustpilot-click":{"post":{"summary":"Record Trustpilot Click","description":"Note that the user opened the Trustpilot link from the popup. Always 204\n(a no-op when there is no feedback row for this book).","operationId":"record_trustpilot_click_api_jobs__job_id__feedback_trustpilot_click_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/share":{"put":{"summary":"Share Book","description":"Opt a completed book into the public gallery (optional Amazon link + the\npage slots to feature). Owner-only; auto-publishes (no review). Charges no\ncredits. Returns the refreshed job status with the new sharing fields.","operationId":"share_book_api_jobs__job_id__share_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareBookRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Unshare Book","description":"Remove a book from the public gallery. Owner-only. Keeps the saved Amazon\nlink so re-sharing is one click. Returns the refreshed job status.","operationId":"unshare_book_api_jobs__job_id__share_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobStatusPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/books/shared":{"get":{"summary":"List Shared Books","description":"PUBLIC, unauthenticated gallery feed of opt-in shared books (cover + sample\npage URLs + Amazon CTA). Rate-limited; no owner identity beyond brand signature.","operationId":"list_shared_books_api_books_shared_get","parameters":[{"name":"lang","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Lang"}},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Skip"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":24,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SharedBooksResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/public/stats":{"get":{"summary":"Public Stats","description":"PUBLIC, unauthenticated landing counters (users, countries, books).\n\nAggregates only, no personal data. Cached in-process for 60s (see\n``services.stats_service``), so \"real time\" means \"at most a minute old\".","operationId":"public_stats_api_public_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicStatsResponse"}}}}}}},"/api/plan/chat":{"post":{"summary":"Plan Chat","description":"Drive the guided planning conversation. Stateless: the FE replays the full\ntranscript each turn. Text only — no credits are charged here.","operationId":"plan_chat_api_plan_chat_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlanChatRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlannerTurn"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/plan/title-suggestions":{"post":{"summary":"Plan Title Suggestions","description":"Suggest cover titles before the book and its automatic cover exist.","operationId":"plan_title_suggestions_api_plan_title_suggestions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TitleSuggestionsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverTitleSuggestionsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/plan/style-previews":{"post":{"summary":"Plan Style Previews","description":"Render the one shared scene in each invented style so the user can pick a look.\n\nFree users get one lifetime rendered preview (their first pick); past that\nthey fall back to choosing from the text descriptions, and asking for more\nrendered styles raises the subscriber gate. Subscribers preview every\nrequested style at one ``style_suggest`` credit each.","operationId":"plan_style_previews_api_plan_style_previews_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StylePreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StylePreviewResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles/list":{"get":{"summary":"List Styles","operationId":"list_styles_api_styles_list_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleListResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles/suggest":{"post":{"summary":"Suggest Styles","operationId":"suggest_styles_api_styles_suggest_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleSuggestRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleSuggestResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles/improve":{"post":{"summary":"Improve Single Style","operationId":"improve_single_style_api_styles_improve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImproveStyleRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImprovedStyleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles/improve-batch":{"post":{"summary":"Improve Styles Batch","operationId":"improve_styles_batch_api_styles_improve_batch_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImproveBatchRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImproveBatchResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles":{"get":{"summary":"Get User Styles","operationId":"get_user_styles_api_styles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserStylesListResponse"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"summary":"Create Style","operationId":"create_style_api_styles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateStyleRequest"}}},"required":true},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/styles/{style_id}":{"put":{"summary":"Update Style","operationId":"update_style_api_styles__style_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"style_id","in":"path","required":true,"schema":{"type":"string","title":"Style Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateStyleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StyleResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Style","operationId":"delete_style_api_styles__style_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"style_id","in":"path","required":true,"schema":{"type":"string","title":"Style Id"}}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/me":{"get":{"summary":"Billing Me","operationId":"billing_me_api_billing_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingBalanceResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/billing/transactions":{"get":{"summary":"Billing Transactions","operationId":"billing_transactions_api_billing_transactions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditTransactionListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/billing/checkout/subscription":{"post":{"summary":"Billing Checkout Subscription","operationId":"billing_checkout_subscription_api_billing_checkout_subscription_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/billing/checkout/topup":{"post":{"summary":"Billing Checkout Topup","operationId":"billing_checkout_topup_api_billing_checkout_topup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupCheckoutRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/billing/portal":{"post":{"summary":"Billing Portal","operationId":"billing_portal_api_billing_portal_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSessionResponse"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/billing/webhook":{"post":{"summary":"Billing Webhook","description":"Dodo Payments webhook endpoint (Standard Webhooks signature-verified).","operationId":"billing_webhook_api_billing_webhook_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/cover-preset":{"get":{"summary":"Get Cover Preset","description":"Return the caller's reusable cover preset (Phase 5b series branding).\n\nAll fields are null when the user has not saved a preset yet. The TEMPLATE\nis intentionally NOT part of the preset — it is chosen per book by\ndistribution type.","operationId":"get_cover_preset_api_cover_preset_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverPresetResponse"}}}}},"security":[{"HTTPBearer":[]}]},"put":{"summary":"Update Cover Preset","description":"Create or update the caller's reusable cover preset.","operationId":"update_cover_preset_api_cover_preset_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverPresetUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverPresetResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/api/jobs/{job_id}/covers/latest":{"get":{"summary":"Get Latest Cover","description":"Return the most recent cover for a book, or null if none exists yet.\n\nLets the library's book view preload an existing cover so the user can\nreview, regenerate or edit it instead of always starting from scratch.","operationId":"get_latest_cover_api_jobs__job_id__covers_latest_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoverStatusResponse"},{"type":"null"}],"title":"Response Get Latest Cover Api Jobs  Job Id  Covers Latest Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/kdp-metadata":{"post":{"summary":"Generate Kdp Metadata Route","description":"Generate Amazon KDP listing metadata for a book, in the book's language.\n\nFree of credits but subscribers-only. Persists the result on the job and\nreturns it inline.","operationId":"generate_kdp_metadata_route_api_jobs__job_id__kdp_metadata_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdpMetadataGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdpMetadataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Get Kdp Metadata Route","description":"Return the saved KDP metadata for a book, or null if none generated yet.\n\nRead access is NOT gated — a user who generated metadata while subscribed can\nalways read/copy it later, even if their subscription lapses.","operationId":"get_kdp_metadata_route_api_jobs__job_id__kdp_metadata_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/KdpMetadataResponse"},{"type":"null"}],"title":"Response Get Kdp Metadata Route Api Jobs  Job Id  Kdp Metadata Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Kdp Metadata Route","description":"Persist user edits to a book's KDP metadata (subscribers-only).","operationId":"update_kdp_metadata_route_api_jobs__job_id__kdp_metadata_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdpMetadataUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KdpMetadataResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/suggest-titles":{"post":{"summary":"Suggest Cover Titles","operationId":"suggest_cover_titles_api_jobs__job_id__covers_suggest_titles_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverTitleSuggestionsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverTitleSuggestionsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/suggest-copy":{"post":{"summary":"Suggest Cover Copy","description":"Suggest cover sales copy (subtitle, audience, page badge) for a book.\n\nDoes not spend credits; falls back to sensible defaults when Gemini is\nunavailable.","operationId":"suggest_cover_copy_api_jobs__job_id__covers_suggest_copy_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverCopySuggestionsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers":{"post":{"summary":"Start Cover","operationId":"start_cover_api_jobs__job_id__covers_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStartResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/status":{"get":{"summary":"Get Cover Status","operationId":"get_cover_status_api_jobs__job_id__covers__cover_id__status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/edit":{"post":{"summary":"Edit Cover Endpoint","operationId":"edit_cover_endpoint_api_jobs__job_id__covers__cover_id__edit_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverEditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStartResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/select-variant":{"post":{"summary":"Select Cover Variant Endpoint","description":"Pick a generated front-cover variant and recompose the downloadable cover.\n\nDeterministic and FREE: recomposes cover.png/cover.pdf from an\nalready-generated front variant. No model call, no credits.","operationId":"select_cover_variant_endpoint_api_jobs__job_id__covers__cover_id__select_variant_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverSelectVariantRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/variants":{"post":{"summary":"Generate Cover Variants Endpoint","description":"Generate 1-4 new cover alternatives (default 3) at three credits each.","operationId":"generate_cover_variants_endpoint_api_jobs__job_id__covers__cover_id__variants_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CoverVariantsRequest"},{"type":"null"}],"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/layout":{"put":{"summary":"Update Cover Layout Endpoint","description":"Edit the cover's TEXT/LAYOUT (title, copy, color, font, position, which\ninterior pages show on the back) and recompose.\n\nDeterministic and FREE: no model call, no credits. Re-renders the text overlay\non the already-generated, text-free front art. Only works for v2 covers\n(render_version>=2); legacy AI-baked-text covers must be regenerated first.","operationId":"update_cover_layout_endpoint_api_jobs__job_id__covers__cover_id__layout_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverLayoutUpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/variants/{index}/regenerate":{"post":{"summary":"Regenerate Cover Variant Endpoint","description":"Regenerate ONE variant slot's artwork (fresh palette + fresh take).\n\nBilling: retrying a FAILED slot is FREE (completes the set the user already\npaid for); regenerating a COMPLETED slot costs ``cover_variant_regenerate``\n(2), spent upfront here and refunded by the background task on failure. Runs\nin the background; the slot shows as 'processing' then 'completed'/'failed'\nvia the variant_states in the cover status the client polls.","operationId":"regenerate_cover_variant_endpoint_api_jobs__job_id__covers__cover_id__variants__index__regenerate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}},{"name":"index","in":"path","required":true,"schema":{"type":"integer","title":"Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/download/png":{"get":{"summary":"Download Cover Png","operationId":"download_cover_png_api_jobs__job_id__covers__cover_id__download_png_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/covers/{cover_id}/download/pdf":{"get":{"summary":"Download Cover Pdf","operationId":"download_cover_pdf_api_jobs__job_id__covers__cover_id__download_pdf_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"cover_id","in":"path","required":true,"schema":{"type":"string","title":"Cover Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus":{"post":{"summary":"Start Aplus","description":"Start generating the three A+ marketing modules (hero / specs / lifestyle).\n\nCosts ``aplus_generation`` credits (1 per module = 3) spent upfront; the\nbackground task refunds any module that fails. One active generation per book; a\nsecond call returns the active one WITHOUT charging again.","operationId":"start_aplus_api_jobs__job_id__aplus_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusGenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusStartResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus/{aplus_id}/regenerate":{"post":{"summary":"Regenerate Aplus Module","description":"Regenerate ONE A+ module (fresh render), optionally with an edited prompt\nand/or provider. Costs ``aplus_regenerate`` (1 credit), refunded on failure.","operationId":"regenerate_aplus_module_api_jobs__job_id__aplus__aplus_id__regenerate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"aplus_id","in":"path","required":true,"schema":{"type":"string","title":"Aplus Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusRegenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus/{aplus_id}/edit":{"post":{"summary":"Edit Aplus Module","description":"Edit ONE A+ module image-to-image with the pro model (a change instruction).\nCosts ``aplus_edit`` (2 credits), refunded on failure.","operationId":"edit_aplus_module_api_jobs__job_id__aplus__aplus_id__edit_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"aplus_id","in":"path","required":true,"schema":{"type":"string","title":"Aplus Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusEditRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus/latest":{"get":{"summary":"Get Latest Aplus","description":"The most recent A+ content set for a book, or ``{aplus_id: null}`` if none.","operationId":"get_latest_aplus_api_jobs__job_id__aplus_latest_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus/{aplus_id}/status":{"get":{"summary":"Get Aplus Status","operationId":"get_aplus_status_api_jobs__job_id__aplus__aplus_id__status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"aplus_id","in":"path","required":true,"schema":{"type":"string","title":"Aplus Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AplusStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/jobs/{job_id}/aplus/{aplus_id}/download/{module}":{"get":{"summary":"Download Aplus Module","operationId":"download_aplus_module_api_jobs__job_id__aplus__aplus_id__download__module__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"aplus_id","in":"path","required":true,"schema":{"type":"string","title":"Aplus Id"}},{"name":"module","in":"path","required":true,"schema":{"type":"string","title":"Module"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AddFrontmatterRequest":{"properties":{"page_type":{"type":"string","enum":["copyright","tips","review","test"],"title":"Page Type"}},"type":"object","required":["page_type"],"title":"AddFrontmatterRequest","description":"Add a front-matter page (copyright/tips/review/test) to an existing book."},"AnalyticsConsentResponse":{"properties":{"analytics_consent":{"anyOf":[{"type":"string","enum":["accepted","rejected"]},{"type":"null"}],"title":"Analytics Consent"},"analytics_consent_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analytics Consent At"}},"type":"object","title":"AnalyticsConsentResponse"},"AnalyticsConsentUpdate":{"properties":{"decision":{"type":"string","enum":["accepted","rejected"],"title":"Decision"}},"type":"object","required":["decision"],"title":"AnalyticsConsentUpdate"},"AplusEditRequest":{"properties":{"module":{"type":"string","maxLength":20,"title":"Module"},"instruction":{"type":"string","maxLength":1000,"minLength":3,"title":"Instruction"}},"type":"object","required":["module","instruction"],"title":"AplusEditRequest","description":"Edit ONE module image-to-image with the pro model (a change instruction)."},"AplusGenerateRequest":{"properties":{"palette":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Palette"},"provider":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Provider"}},"type":"object","title":"AplusGenerateRequest","description":"Optional knobs for an A+ content generation. The module set is fixed\n(hero / specs / lifestyle); palette + image provider are tunable."},"AplusModuleState":{"properties":{"status":{"type":"string","title":"Status"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt"},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Provider"}},"type":"object","required":["status"],"title":"AplusModuleState"},"AplusRegenerateRequest":{"properties":{"module":{"type":"string","maxLength":20,"title":"Module"},"prompt":{"anyOf":[{"type":"string","maxLength":6000},{"type":"null"}],"title":"Prompt"},"provider":{"anyOf":[{"type":"string","maxLength":20},{"type":"null"}],"title":"Provider"}},"type":"object","required":["module"],"title":"AplusRegenerateRequest","description":"Regenerate ONE module, optionally with an edited prompt and/or provider."},"AplusStartResponse":{"properties":{"aplus_id":{"type":"string","title":"Aplus Id"},"status":{"type":"string","title":"Status"}},"type":"object","required":["aplus_id","status"],"title":"AplusStartResponse"},"AplusStatusResponse":{"properties":{"aplus_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aplus Id"},"job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Id"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"modules":{"anyOf":[{"additionalProperties":{"$ref":"#/components/schemas/AplusModuleState"},"type":"object"},{"type":"null"}],"title":"Modules"}},"type":"object","title":"AplusStatusResponse"},"AsyncOpStartResponse":{"properties":{"status":{"type":"string","title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["status","message"],"title":"AsyncOpStartResponse","description":"Returned when a long page operation (edit/regenerate) is kicked off in the\nbackground. The result is fetched by polling the op-status endpoint."},"BillingBalanceResponse":{"properties":{"plan_credits":{"type":"integer","title":"Plan Credits"},"topup_credits":{"type":"integer","title":"Topup Credits"},"total_credits":{"type":"integer","title":"Total Credits"},"plan_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Id"},"plan_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Name"},"plan_interval":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Plan Interval"},"subscription_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Status"},"current_period_end":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Period End"},"cancel_at_period_end":{"type":"boolean","title":"Cancel At Period End","default":false},"is_free":{"type":"boolean","title":"Is Free","default":true},"available_plan_ids":{"items":{"type":"string"},"type":"array","title":"Available Plan Ids"},"free_max_pages":{"type":"integer","title":"Free Max Pages","default":3}},"type":"object","required":["plan_credits","topup_credits","total_credits"],"title":"BillingBalanceResponse"},"BookFeedbackRequest":{"properties":{"rating":{"anyOf":[{"type":"integer","maximum":5.0,"minimum":1.0},{"type":"null"}],"title":"Rating"},"comment":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Comment"},"dismissed":{"type":"boolean","title":"Dismissed","default":false}},"type":"object","title":"BookFeedbackRequest","description":"A rating (1-5 stars + optional private comment) or a \"not now\".\n\n``dismissed=true`` records a \"not now\" and ignores ``rating``/``comment``.\nOtherwise ``rating`` is required. ``comment`` is stripped and truncated to\n2000 characters server-side (blank becomes null)."},"BookFeedbackResponse":{"properties":{"status":{"type":"string","enum":["submitted","dismissed"],"title":"Status"}},"type":"object","required":["status"],"title":"BookFeedbackResponse","description":"The status the feedback row ended up with. A \"not now\" sent after the\nbook was already rated answers ``submitted`` (ratings are never downgraded)."},"BookLength":{"type":"string","enum":["test","short","medium","long"],"title":"BookLength"},"BookPlanConfig":{"properties":{"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"},"length":{"$ref":"#/components/schemas/BookLength","default":"short"},"pages":{"type":"integer","maximum":60.0,"minimum":3.0,"title":"Pages","default":25},"distribution_type":{"type":"string","enum":["progressive","bold_and_easy","cute_and_cozy"],"title":"Distribution Type","default":"progressive"},"character_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Character Count"},"language":{"type":"string","enum":["en","es"],"title":"Language","default":"en"},"style_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Id"},"style_description":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}],"title":"Style Description"},"allow_text":{"type":"boolean","title":"Allow Text","default":false}},"type":"object","required":["theme"],"title":"BookPlanConfig","description":"The book the agent proposes — a superset compatible with GenerateRequest.\n\nOn approval the FE forwards this straight to POST /api/generate. ``pages`` is\nthe authoritative page count (the user picks it explicitly); ``length`` is only\na coarse label (the nearest LENGTH bucket) and is not used to derive pages."},"BrandResponse":{"properties":{"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"}},"type":"object","title":"BrandResponse","description":"The caller's brand / series signature line. ``null`` when unset.\n\nStored inside the per-user cover preset (single source of truth, also used on\ncovers), but exposed here as a standalone account setting so it can be read /\nedited outside the cover flow (settings page, copyright-page gate)."},"BrandUpdateRequest":{"properties":{"brand_signature":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Brand Signature"}},"type":"object","title":"BrandUpdateRequest"},"ChangePasswordRequest":{"properties":{"current_password":{"type":"string","maxLength":72,"title":"Current Password"},"new_password":{"type":"string","maxLength":72,"minLength":6,"title":"New Password"}},"type":"object","required":["current_password","new_password"],"title":"ChangePasswordRequest"},"ChangePasswordResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"ChangePasswordResponse"},"CheckoutSessionResponse":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"CheckoutSessionResponse"},"CoverCopySuggestionsResponse":{"properties":{"subtitle":{"type":"string","title":"Subtitle"},"audience":{"type":"string","title":"Audience"},"badge":{"type":"string","title":"Badge"}},"type":"object","required":["subtitle","audience","badge"],"title":"CoverCopySuggestionsResponse"},"CoverEditRequest":{"properties":{"change_request":{"type":"string","maxLength":1000,"minLength":3,"title":"Change Request"},"title":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Title"},"subtitle":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}],"title":"Subtitle"}},"type":"object","required":["change_request"],"title":"CoverEditRequest"},"CoverFiles":{"properties":{"preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview"},"front":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Front"},"png":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Png"},"pdf":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pdf"}},"type":"object","title":"CoverFiles"},"CoverGenerateRequest":{"properties":{"title":{"type":"string","maxLength":120,"minLength":1,"title":"Title"},"sample_page_indexes":{"items":{"type":"integer"},"type":"array","maxItems":4,"minItems":3,"title":"Sample Page Indexes"},"style":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Style"},"instructions":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Instructions"},"template":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Template"},"font_preset":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Font Preset"},"subtitle":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}],"title":"Subtitle"},"audience_label":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Audience Label"},"badge":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Badge"},"text_color":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Text Color"},"brand_signature":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Brand Signature"},"art_mode":{"anyOf":[{"type":"string","maxLength":16},{"type":"null"}],"title":"Art Mode"},"title_layout":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Title Layout"}},"type":"object","required":["title","sample_page_indexes"],"title":"CoverGenerateRequest"},"CoverLayoutUpdateRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Title"},"subtitle":{"anyOf":[{"type":"string","maxLength":160},{"type":"null"}],"title":"Subtitle"},"audience_label":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Audience Label"},"badge":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Badge"},"text_color":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Text Color"},"font_preset":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Font Preset"},"title_layout":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"Title Layout"},"brand_signature":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Brand Signature"},"sample_page_indexes":{"anyOf":[{"items":{"type":"integer"},"type":"array","maxItems":4,"minItems":3},{"type":"null"}],"title":"Sample Page Indexes"}},"type":"object","title":"CoverLayoutUpdateRequest","description":"Free, deterministic text/layout edit for a v2 cover (no credits, no model).\n\nOnly the fields present in the request are changed (``exclude_unset``). For the\noptional copy slots, sending an empty string clears them. ``art_mode`` is NOT\nhere on purpose: changing the artwork style requires regenerating the art."},"CoverPresetResponse":{"properties":{"font_preset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font Preset"},"audience_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Label"},"text_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text Color"},"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"}},"type":"object","title":"CoverPresetResponse","description":"A user's reusable cover preset (Phase 5b series branding). All fields are\nnull when the user has not saved a preset yet. The TEMPLATE is intentionally\nNOT part of the preset — it is chosen per book by distribution type."},"CoverPresetUpdateRequest":{"properties":{"font_preset":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Font Preset"},"audience_label":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Audience Label"},"text_color":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Text Color"},"brand_signature":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"Brand Signature"}},"type":"object","title":"CoverPresetUpdateRequest"},"CoverQuoteSummary":{"properties":{"included":{"type":"boolean","title":"Included","default":true},"credits":{"type":"integer","title":"Credits"},"variant_count":{"type":"integer","title":"Variant Count","default":1}},"type":"object","required":["credits"],"title":"CoverQuoteSummary"},"CoverSelectVariantRequest":{"properties":{"variant":{"type":"integer","maximum":11.0,"minimum":0.0,"title":"Variant"}},"type":"object","required":["variant"],"title":"CoverSelectVariantRequest"},"CoverStartResponse":{"properties":{"cover_id":{"type":"string","title":"Cover Id"},"status":{"type":"string","title":"Status"},"message":{"type":"string","title":"Message","default":"Cover generation started"}},"type":"object","required":["cover_id","status"],"title":"CoverStartResponse"},"CoverStatusResponse":{"properties":{"cover_id":{"type":"string","title":"Cover Id"},"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"title":{"type":"string","title":"Title"},"theme":{"type":"string","title":"Theme"},"style":{"type":"string","title":"Style"},"sample_page_indexes":{"items":{"type":"integer"},"type":"array","title":"Sample Page Indexes"},"dimensions":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Dimensions"},"files":{"anyOf":[{"$ref":"#/components/schemas/CoverFiles"},{"type":"null"}]},"variants":{"anyOf":[{"items":{"anyOf":[{"type":"string"},{"type":"null"}]},"type":"array"},{"type":"null"}],"title":"Variants"},"selected_variant":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Selected Variant"},"variant_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Variant Count"},"variant_states":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Variant States"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"created_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Created At"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template"},"font_preset":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font Preset"},"subtitle":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subtitle"},"audience_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Label"},"badge":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Badge"},"text_color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text Color"},"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"},"render_version":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Render Version"},"art_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Art Mode"},"title_layout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Layout"}},"type":"object","required":["cover_id","job_id","status","title","theme","style","sample_page_indexes"],"title":"CoverStatusResponse"},"CoverSummary":{"properties":{"cover_id":{"type":"string","title":"Cover Id"},"status":{"type":"string","title":"Status"},"title":{"type":"string","title":"Title"},"preview_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview Url"},"front_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Front Url"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"generation_elapsed_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Generation Elapsed Seconds"},"estimated_generation_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Estimated Generation Seconds"},"estimate_sample_count":{"type":"integer","title":"Estimate Sample Count","default":0}},"type":"object","required":["cover_id","status","title"],"title":"CoverSummary"},"CoverTitleSuggestionsRequest":{"properties":{"count":{"type":"integer","maximum":8.0,"minimum":1.0,"title":"Count","default":4}},"type":"object","title":"CoverTitleSuggestionsRequest"},"CoverTitleSuggestionsResponse":{"properties":{"titles":{"items":{"type":"string"},"type":"array","title":"Titles"}},"type":"object","required":["titles"],"title":"CoverTitleSuggestionsResponse"},"CoverVariantsRequest":{"properties":{"count":{"type":"integer","maximum":4.0,"minimum":1.0,"title":"Count","default":3}},"type":"object","title":"CoverVariantsRequest"},"CreateStyleRequest":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"},"description":{"type":"string","maxLength":2000,"minLength":1,"title":"Description"}},"type":"object","required":["name","description"],"title":"CreateStyleRequest"},"CreditTransactionListResponse":{"properties":{"transactions":{"items":{"$ref":"#/components/schemas/CreditTransactionResponse"},"type":"array","title":"Transactions"}},"type":"object","required":["transactions"],"title":"CreditTransactionListResponse"},"CreditTransactionResponse":{"properties":{"tx_id":{"type":"string","title":"Tx Id"},"amount":{"type":"integer","title":"Amount"},"kind":{"type":"string","title":"Kind"},"created_at":{"type":"string","title":"Created At"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","required":["tx_id","amount","kind","created_at"],"title":"CreditTransactionResponse"},"DistributionRange":{"properties":{"start_page":{"type":"integer","minimum":1.0,"title":"Start Page"},"end_page":{"type":"integer","minimum":1.0,"title":"End Page"},"theme":{"type":"string","maxLength":120,"minLength":1,"title":"Theme"},"description":{"anyOf":[{"type":"string","maxLength":600},{"type":"null"}],"title":"Description"}},"type":"object","required":["start_page","end_page","theme"],"title":"DistributionRange","description":"One contiguous section of the book's page plan.\n\nShared contract with the frontend: ranges are contiguous and cover pages\n``1..config.pages`` exactly. ``theme`` is a short user-facing label (in the\nuser's language); ``description`` is an optional English brief that is fed\nto the page-prompt generator."},"EditImageRequest":{"properties":{"edit_instructions":{"type":"string","maxLength":500,"minLength":5,"title":"Edit Instructions"}},"type":"object","required":["edit_instructions"],"title":"EditImageRequest"},"EmailPreferencesResponse":{"properties":{"marketing_opt_in":{"type":"boolean","title":"Marketing Opt In"},"marketing_locale":{"type":"string","enum":["en","es"],"title":"Marketing Locale"},"marketing_opt_in_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketing Opt In At"},"unsubscribed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Unsubscribed At"},"suppressed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Suppressed At"}},"type":"object","required":["marketing_opt_in","marketing_locale"],"title":"EmailPreferencesResponse"},"EmailPreferencesUpdate":{"properties":{"marketing_opt_in":{"type":"boolean","title":"Marketing Opt In"},"marketing_locale":{"type":"string","enum":["en","es"],"title":"Marketing Locale","default":"en"}},"type":"object","required":["marketing_opt_in"],"title":"EmailPreferencesUpdate"},"FeedbackPromptResponse":{"properties":{"eligible":{"type":"boolean","title":"Eligible"}},"type":"object","required":["eligible"],"title":"FeedbackPromptResponse","description":"Whether the frontend should show the \"rate your book\" popup."},"FirstTouchAttribution":{"properties":{"utm_source":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Utm Source"},"utm_medium":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Utm Medium"},"utm_campaign":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Utm Campaign"},"utm_term":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Utm Term"},"utm_content":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Utm Content"},"origin_channel":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Origin Channel"},"origin_source":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Origin Source"},"origin_landing_path":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Origin Landing Path"}},"type":"object","title":"FirstTouchAttribution","description":"Consented first-touch campaign data captured at account creation."},"ForgotPasswordRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"}},"type":"object","required":["email"],"title":"ForgotPasswordRequest"},"ForgotPasswordResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"ForgotPasswordResponse"},"GenerateRequest":{"properties":{"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"},"title":{"anyOf":[{"type":"string","maxLength":120,"minLength":1},{"type":"null"}],"title":"Title"},"length":{"$ref":"#/components/schemas/BookLength"},"pages":{"anyOf":[{"type":"integer","maximum":60.0,"minimum":3.0},{"type":"null"}],"title":"Pages"},"style_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Id"},"custom_style":{"anyOf":[{"type":"string","maxLength":2000,"minLength":3},{"type":"null"}],"title":"Custom Style"},"reference_prompt":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Reference Prompt"},"distribution_type":{"type":"string","enum":["progressive","bold_and_easy","cute_and_cozy"],"title":"Distribution Type","default":"progressive"},"character_count":{"anyOf":[{"type":"integer","maximum":4.0,"minimum":0.0},{"type":"null"}],"title":"Character Count"},"language":{"type":"string","enum":["en","es"],"title":"Language","default":"en"},"style_description":{"anyOf":[{"type":"string","maxLength":4000},{"type":"null"}],"title":"Style Description"},"allow_text":{"type":"boolean","title":"Allow Text","default":false},"distribution":{"anyOf":[{"items":{"$ref":"#/components/schemas/DistributionRange"},"type":"array"},{"type":"null"}],"title":"Distribution"},"include_copyright":{"type":"boolean","title":"Include Copyright","default":false},"include_tips":{"type":"boolean","title":"Include Tips","default":false},"include_review":{"type":"boolean","title":"Include Review","default":false},"include_test":{"type":"boolean","title":"Include Test","default":false}},"type":"object","required":["theme","length"],"title":"GenerateRequest"},"GenerationQuoteRequest":{"properties":{"theme":{"type":"string","title":"Theme","default":""},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"length":{"$ref":"#/components/schemas/BookLength","default":"short"},"pages":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Pages"},"style_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Id"},"custom_style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Style"},"reference_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reference Prompt"},"distribution_type":{"type":"string","enum":["progressive","bold_and_easy","cute_and_cozy"],"title":"Distribution Type","default":"progressive"},"character_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Character Count"},"language":{"type":"string","enum":["en","es"],"title":"Language","default":"en"},"style_description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Description"},"allow_text":{"type":"boolean","title":"Allow Text","default":false},"distribution":{"anyOf":[{"items":{"$ref":"#/components/schemas/DistributionRange"},"type":"array"},{"type":"null"}],"title":"Distribution"},"include_copyright":{"type":"boolean","title":"Include Copyright","default":false},"include_tips":{"type":"boolean","title":"Include Tips","default":false},"include_review":{"type":"boolean","title":"Include Review","default":false},"include_test":{"type":"boolean","title":"Include Test","default":false}},"type":"object","title":"GenerationQuoteRequest","description":"Lenient twin of GenerateRequest, used only to price a book.\n\nThe price must never be what stops a creation. POST /api/generate re-validates\neverything (moderation, plan limits, credits) before spending a single credit,\nso POST /api/generate/quote prices whatever the planner produced instead of\nanswering 422 — a 422 the UI could only show as \"Could not calculate the final\nprice, try again\", with the Create button stuck on its loading state forever.\n\nThe price depends on ``pages`` and the front-matter flags alone, so every text\nfield here drops its length bounds and the page count is clamped into the\nrange /api/generate accepts rather than rejected."},"GenerationQuoteResponse":{"properties":{"title":{"type":"string","title":"Title"},"pages":{"type":"integer","title":"Pages"},"frontmatter_pages":{"type":"integer","title":"Frontmatter Pages"},"cover_credits":{"type":"integer","title":"Cover Credits"},"cover":{"$ref":"#/components/schemas/CoverQuoteSummary"},"required_credits":{"type":"integer","title":"Required Credits"},"credits_to_charge":{"type":"integer","title":"Credits To Charge"},"available_credits":{"type":"integer","title":"Available Credits"},"is_free":{"type":"boolean","title":"Is Free"},"can_create":{"type":"boolean","title":"Can Create"},"blocker_code":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Blocker Code"},"blocker_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Blocker Message"}},"type":"object","required":["title","pages","frontmatter_pages","cover_credits","cover","required_credits","credits_to_charge","available_credits","is_free","can_create"],"title":"GenerationQuoteResponse"},"GoogleAuthRequest":{"properties":{"credential":{"type":"string","title":"Credential"},"terms_accepted":{"type":"boolean","title":"Terms Accepted","default":false},"attribution":{"anyOf":[{"$ref":"#/components/schemas/FirstTouchAttribution"},{"type":"null"}]},"marketing_opt_in":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Marketing Opt In"}},"type":"object","required":["credential"],"title":"GoogleAuthRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"ImageStatus":{"properties":{"slot":{"type":"integer","title":"Slot"},"status":{"type":"string","title":"Status"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt"},"simple_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Prompt"},"simple_prompt_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Prompt Es"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"creative_brief":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creative Brief"},"simple_creative_brief":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Creative Brief"},"simple_creative_brief_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Creative Brief Es"},"bw_image_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Path"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"retries":{"type":"integer","title":"Retries","default":0},"bw_image_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Prompt"},"bw_image_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Model"},"completed_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Completed At"},"framed":{"type":"boolean","title":"Framed","default":false},"page_type":{"type":"string","title":"Page Type","default":"coloring"}},"type":"object","required":["slot","status"],"title":"ImageStatus"},"ImproveBatchRequest":{"properties":{"styles":{"items":{"additionalProperties":{"type":"string"},"type":"object"},"type":"array","title":"Styles"},"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"}},"type":"object","required":["styles","theme"],"title":"ImproveBatchRequest"},"ImproveBatchResponse":{"properties":{"improved_styles":{"items":{"$ref":"#/components/schemas/ImprovedStyleResponse"},"type":"array","title":"Improved Styles"}},"type":"object","required":["improved_styles"],"title":"ImproveBatchResponse"},"ImproveStyleRequest":{"properties":{"style_id":{"type":"string","title":"Style Id"},"style_description":{"type":"string","maxLength":2000,"title":"Style Description"},"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"}},"type":"object","required":["style_id","style_description","theme"],"title":"ImproveStyleRequest"},"ImprovedStyleResponse":{"properties":{"original_style_id":{"type":"string","title":"Original Style Id"},"improved_style_id":{"type":"string","title":"Improved Style Id"},"improved_name":{"type":"string","title":"Improved Name"},"style_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Name"},"improved_description":{"type":"string","title":"Improved Description"},"sample_url":{"type":"string","title":"Sample Url"},"bw_image_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Prompt"}},"type":"object","required":["original_style_id","improved_style_id","improved_name","improved_description","sample_url"],"title":"ImprovedStyleResponse"},"JobListResponse":{"properties":{"jobs":{"items":{"$ref":"#/components/schemas/JobStatusPayload"},"type":"array","title":"Jobs"},"total":{"type":"integer","title":"Total"}},"type":"object","required":["jobs","total"],"title":"JobListResponse"},"JobStatusPayload":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"progress":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Progress"},"theme":{"type":"string","title":"Theme"},"title":{"type":"string","title":"Title"},"pages":{"type":"integer","title":"Pages"},"selected_style":{"type":"string","title":"Selected Style"},"images":{"items":{"$ref":"#/components/schemas/ImageStatus"},"type":"array","title":"Images"},"created_at":{"type":"string","title":"Created At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"watermarked":{"type":"boolean","title":"Watermarked","default":false},"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"},"language":{"type":"string","title":"Language","default":"en"},"is_shared":{"type":"boolean","title":"Is Shared","default":false},"amazon_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amazon Url"},"shared_page_slots":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Shared Page Slots"},"cover":{"anyOf":[{"$ref":"#/components/schemas/CoverSummary"},{"type":"null"}]}},"type":"object","required":["job_id","status","progress","theme","title","pages","selected_style","images","created_at"],"title":"JobStatusPayload"},"KdpMetadataGenerateRequest":{"properties":{"audience_hint":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Audience Hint"},"extra_instructions":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}],"title":"Extra Instructions"}},"type":"object","title":"KdpMetadataGenerateRequest","description":"Optional knobs when (re)generating KDP metadata for a book."},"KdpMetadataResponse":{"properties":{"title":{"type":"string","title":"Title"},"subtitle":{"type":"string","title":"Subtitle","default":""},"description":{"type":"string","title":"Description"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"},"categories":{"items":{"type":"string"},"type":"array","title":"Categories"},"author":{"type":"string","title":"Author","default":""},"marketing_blurb":{"type":"string","title":"Marketing Blurb","default":""},"audience":{"type":"string","title":"Audience","default":""},"reading_age":{"type":"string","title":"Reading Age","default":""},"language":{"type":"string","title":"Language","default":"en"},"generated_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Generated At"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"}},"type":"object","required":["title","description","keywords","categories"],"title":"KdpMetadataResponse","description":"The persisted/wire shape — the validated agent output plus provenance."},"KdpMetadataUpdateRequest":{"properties":{"title":{"type":"string","maxLength":200,"minLength":1,"title":"Title"},"subtitle":{"type":"string","maxLength":200,"title":"Subtitle","default":""},"description":{"type":"string","maxLength":4000,"minLength":1,"title":"Description"},"keywords":{"items":{"type":"string"},"type":"array","maxItems":7,"minItems":1,"title":"Keywords"},"categories":{"items":{"type":"string"},"type":"array","maxItems":3,"minItems":1,"title":"Categories"},"author":{"type":"string","maxLength":120,"title":"Author","default":""},"marketing_blurb":{"type":"string","maxLength":400,"title":"Marketing Blurb","default":""},"audience":{"type":"string","maxLength":80,"title":"Audience","default":""},"reading_age":{"type":"string","maxLength":40,"title":"Reading Age","default":""}},"type":"object","required":["title","description","keywords","categories"],"title":"KdpMetadataUpdateRequest","description":"User edits to the KDP metadata (all fields editable, length-capped)."},"LoginResponse":{"properties":{"access_token":{"type":"string","title":"Access Token"},"refresh_token":{"type":"string","title":"Refresh Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"user":{"$ref":"#/components/schemas/UserResponse"},"is_new_user":{"type":"boolean","title":"Is New User","default":false}},"type":"object","required":["access_token","refresh_token","user"],"title":"LoginResponse"},"MilestoneItem":{"properties":{"key":{"type":"string","title":"Key"},"page":{"type":"string","title":"Page"},"rarity":{"type":"string","title":"Rarity"},"status":{"type":"string","title":"Status"},"current":{"type":"integer","title":"Current"},"target":{"type":"integer","title":"Target"},"earned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Earned At"}},"type":"object","required":["key","page","rarity","status","current","target"],"title":"MilestoneItem","description":"One sticker of the album. ``status`` is ``earned``, ``in_progress``,\n``locked`` (seasonal, not open yet) or ``missed`` (season over)."},"MilestoneSeason":{"properties":{"page":{"type":"string","title":"Page"},"year":{"type":"integer","title":"Year"},"starts_at":{"type":"string","title":"Starts At"},"ends_at":{"type":"string","title":"Ends At"}},"type":"object","required":["page","year","starts_at","ends_at"],"title":"MilestoneSeason"},"MilestonesResponse":{"properties":{"milestones":{"items":{"$ref":"#/components/schemas/MilestoneItem"},"type":"array","title":"Milestones"},"seasons":{"items":{"$ref":"#/components/schemas/MilestoneSeason"},"type":"array","title":"Seasons"}},"type":"object","required":["milestones","seasons"],"title":"MilestonesResponse"},"OAuthConsentDecision":{"properties":{"request":{"type":"string","maxLength":10000,"minLength":20,"title":"Request"},"approved":{"type":"boolean","title":"Approved"}},"type":"object","required":["request","approved"],"title":"OAuthConsentDecision"},"PageFrameResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"framed":{"type":"boolean","title":"Framed"}},"type":"object","required":["framed"],"title":"PageFrameResponse","description":"Result of applying/removing a page frame: the now-current image + state."},"PageOpStatusResponse":{"properties":{"status":{"type":"string","title":"Status"},"op":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Op"},"preview_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preview Url"},"new_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Prompt"},"simple_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Prompt"},"simple_prompt_es":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Simple Prompt Es"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["status"],"title":"PageOpStatusResponse","description":"Poll result for a background per-page operation."},"PlanChatRequest":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/PlannerMessage"},"type":"array","maxItems":60,"minItems":1,"title":"Messages"},"language":{"anyOf":[{"type":"string","enum":["en","es"]},{"type":"null"}],"title":"Language"},"chat_language":{"anyOf":[{"type":"string","maxLength":35},{"type":"null"}],"title":"Chat Language"}},"type":"object","required":["messages"],"title":"PlanChatRequest"},"PlannerMessage":{"properties":{"role":{"type":"string","enum":["user","assistant"],"title":"Role"},"content":{"type":"string","maxLength":4000,"title":"Content"}},"type":"object","required":["role","content"],"title":"PlannerMessage","description":"One turn of the planning conversation. Sent by the FE on every request\n(the chat is stateless on the backend — see /api/plan/chat)."},"PlannerOption":{"properties":{"label":{"type":"string","title":"Label"},"value":{"type":"string","title":"Value"},"emoji":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Emoji"}},"type":"object","required":["label","value"],"title":"PlannerOption","description":"A selectable chip for a multiple-choice question turn."},"PlannerTurn":{"properties":{"kind":{"type":"string","enum":["question","plan"],"title":"Kind"},"message":{"type":"string","maxLength":2000,"title":"Message"},"options":{"items":{"$ref":"#/components/schemas/PlannerOption"},"type":"array","title":"Options"},"multi_select":{"type":"boolean","title":"Multi Select","default":false},"allow_free_text":{"type":"boolean","title":"Allow Free Text","default":true},"collected":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Collected"},"summary":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Summary"},"config":{"anyOf":[{"$ref":"#/components/schemas/BookPlanConfig"},{"type":"null"}]},"style_candidates":{"anyOf":[{"items":{"$ref":"#/components/schemas/StyleCandidate"},"type":"array"},{"type":"null"}],"title":"Style Candidates"},"sample_scene":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Scene"},"distribution":{"anyOf":[{"items":{"$ref":"#/components/schemas/DistributionRange"},"type":"array"},{"type":"null"}],"title":"Distribution"},"handled_requests":{"items":{"type":"string"},"type":"array","title":"Handled Requests"},"help_topic":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Help Topic"}},"type":"object","required":["kind","message"],"title":"PlannerTurn","description":"One assistant turn. ``kind`` discriminates the shape:\n\n- ``question``: render ``message`` + ``options`` (chips) and/or a free-text box.\n- ``plan``: render ``message`` + ``summary`` bullets + the 3 invented\n  ``style_candidates`` (rendered against one shared ``sample_scene`` so the user\n  can compare looks and pick one), plus Approve / give-feedback CTAs (``config``\n  is hidden state)."},"PublicStatsResponse":{"properties":{"users":{"type":"integer","title":"Users"},"countries":{"type":"integer","title":"Countries"},"books":{"type":"integer","title":"Books"}},"type":"object","required":["users","countries","books"],"title":"PublicStatsResponse","description":"Unauthenticated community counters shown on the landing page."},"RefreshRequest":{"properties":{"refresh_token":{"type":"string","title":"Refresh Token"}},"type":"object","required":["refresh_token"],"title":"RefreshRequest"},"ResetPasswordRequest":{"properties":{"token":{"type":"string","maxLength":4096,"minLength":20,"title":"Token"},"new_password":{"type":"string","maxLength":72,"minLength":6,"title":"New Password"}},"type":"object","required":["token","new_password"],"title":"ResetPasswordRequest"},"ResetPasswordResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"ResetPasswordResponse"},"SaveEditedImageRequest":{"properties":{"preview_url":{"type":"string","title":"Preview Url"},"new_prompt":{"type":"string","maxLength":4000,"title":"New Prompt"},"simple_prompt":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Simple Prompt"},"simple_prompt_es":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Simple Prompt Es"}},"type":"object","required":["preview_url","new_prompt"],"title":"SaveEditedImageRequest"},"SetPageFrameRequest":{"properties":{"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["enabled"],"title":"SetPageFrameRequest","description":"Toggle a deterministic black KDP-safe frame on a single page."},"ShareBookRequest":{"properties":{"amazon_url":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Amazon Url"},"page_slots":{"items":{"type":"integer"},"type":"array","title":"Page Slots"}},"type":"object","title":"ShareBookRequest","description":"Opt a completed book into the public gallery.\n\n``amazon_url`` is optional: when provided (non-blank) it is validated\nserver-side against the allowed Amazon domains and rendered as the card's\nbuy CTA; when omitted/blank the book is shared without a buy button.\n``page_slots`` are the page slots to feature as samples (capped to 3,\nonly completed pages kept — both enforced in the route)."},"SharedBookCard":{"properties":{"job_id":{"type":"string","title":"Job Id"},"title":{"type":"string","title":"Title"},"style_label":{"type":"string","title":"Style Label"},"language":{"type":"string","title":"Language"},"cover_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cover Url"},"sample_urls":{"items":{"type":"string"},"type":"array","title":"Sample Urls"},"amazon_url":{"type":"string","title":"Amazon Url"},"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"},"shared_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shared At"}},"type":"object","required":["job_id","title","style_label","language","amazon_url"],"title":"SharedBookCard","description":"One entry in the public gallery feed. No owner identity beyond the optional\npublisher/series ``brand_signature`` — never the email/name."},"SharedBooksResponse":{"properties":{"books":{"items":{"$ref":"#/components/schemas/SharedBookCard"},"type":"array","title":"Books"},"total":{"type":"integer","title":"Total"},"has_more":{"type":"boolean","title":"Has More","default":false}},"type":"object","required":["books","total"],"title":"SharedBooksResponse","description":"One page of the public gallery feed (``skip``/``limit``)."},"StartJobResponse":{"properties":{"job_id":{"type":"string","title":"Job Id"},"status":{"type":"string","title":"Status"},"progress":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Progress"},"theme":{"type":"string","title":"Theme"},"title":{"type":"string","title":"Title"},"pages":{"type":"integer","title":"Pages"},"selected_style":{"type":"string","title":"Selected Style"},"images":{"items":{"$ref":"#/components/schemas/ImageStatus"},"type":"array","title":"Images"},"created_at":{"type":"string","title":"Created At"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"watermarked":{"type":"boolean","title":"Watermarked","default":false},"brand_signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Signature"},"language":{"type":"string","title":"Language","default":"en"},"is_shared":{"type":"boolean","title":"Is Shared","default":false},"amazon_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Amazon Url"},"shared_page_slots":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Shared Page Slots"},"cover":{"anyOf":[{"$ref":"#/components/schemas/CoverSummary"},{"type":"null"}]},"message":{"type":"string","title":"Message"}},"type":"object","required":["job_id","status","progress","theme","title","pages","selected_style","images","created_at","message"],"title":"StartJobResponse"},"StyleBase":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"style_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Name","description":"Friendly alias for 'name'."},"description":{"type":"string","title":"Description"},"sample_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sample Url"}},"type":"object","required":["id","name","description"],"title":"StyleBase"},"StyleCandidate":{"properties":{"key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Key"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"},"description":{"type":"string","maxLength":2000,"minLength":1,"title":"Description"},"name_local":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Name Local"},"description_local":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Description Local"}},"type":"object","required":["name","description"],"title":"StyleCandidate","description":"An AI-invented visual style for a planned book.\n\nThe planner model proposes these on a plan turn; it omits ``key`` and the\nserver slugifies ``name`` into a unique, stable key (see book_planner).\n\n``name``/``description`` stay in technical English (they feed the image\nmodel); ``name_local``/``description_local`` carry the same text translated\nto the user's chat language for display only."},"StyleListResponse":{"properties":{"styles":{"items":{"$ref":"#/components/schemas/StyleBase"},"type":"array","title":"Styles"}},"type":"object","required":["styles"],"title":"StyleListResponse"},"StylePreview":{"properties":{"key":{"type":"string","title":"Key"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"url":{"type":"string","title":"Url"},"name_local":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name Local"},"description_local":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description Local"}},"type":"object","required":["key","name","description","url"],"title":"StylePreview"},"StylePreviewRequest":{"properties":{"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"},"sample_scene":{"type":"string","maxLength":600,"minLength":1,"title":"Sample Scene"},"styles":{"items":{"$ref":"#/components/schemas/StyleCandidate"},"type":"array","maxItems":3,"minItems":1,"title":"Styles"}},"type":"object","required":["theme","sample_scene","styles"],"title":"StylePreviewRequest"},"StylePreviewResponse":{"properties":{"previews":{"items":{"$ref":"#/components/schemas/StylePreview"},"type":"array","title":"Previews"}},"type":"object","required":["previews"],"title":"StylePreviewResponse"},"StyleResponse":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"style_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Name"},"description":{"type":"string","title":"Description"},"created_at":{"type":"string","title":"Created At"},"updated_at":{"type":"string","title":"Updated At"}},"type":"object","required":["id","name","description","created_at","updated_at"],"title":"StyleResponse"},"StyleSuggestRequest":{"properties":{"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"},"count":{"type":"integer","maximum":8.0,"minimum":1.0,"title":"Count","default":4},"selected_style_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Selected Style Ids"},"edited_descriptions":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Edited Descriptions"}},"type":"object","required":["theme"],"title":"StyleSuggestRequest"},"StyleSuggestResponse":{"properties":{"styles":{"items":{"$ref":"#/components/schemas/StyleSuggestion"},"type":"array","title":"Styles"}},"type":"object","required":["styles"],"title":"StyleSuggestResponse"},"StyleSuggestion":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"style_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style Name","description":"Friendly alias for 'name'."},"description":{"type":"string","title":"Description"},"sample_url":{"type":"string","title":"Sample Url"},"bw_image_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Path"},"bw_image_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Prompt"},"bw_image_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bw Image Model"}},"type":"object","required":["id","name","description","sample_url"],"title":"StyleSuggestion"},"SubscriptionCheckoutRequest":{"properties":{"plan_id":{"type":"string","title":"Plan Id","description":"Internal plan_id (weekly | author | publisher; hobbyist is legacy)"},"ga_client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Client Id","description":"Browser GA4 client id; only sent when analytics consent let GA load"},"ga_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Session Id","description":"Browser GA4 session id"},"ga_origin_channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Origin Channel","description":"Visitor's first-party origin channel"},"ga_origin_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Origin Source","description":"Visitor's first-party origin source"},"revnu_anonymous_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Anonymous Id","description":"Revnu tag's opaque visitor id; only set once analytics consent let it run"},"revnu_consent_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Consent State","description":"Revnu tag consent at checkout: granted | denied | pending"},"revnu_google_ad_user_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Google Ad User Data","description":"Google ad-user-data choice at checkout: granted | denied | unknown"},"revnu_google_ad_personalization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Google Ad Personalization","description":"Google ad-personalization choice at checkout: granted | denied | unknown"}},"type":"object","required":["plan_id"],"title":"SubscriptionCheckoutRequest"},"TitleSuggestionsRequest":{"properties":{"theme":{"type":"string","maxLength":200,"minLength":1,"title":"Theme"},"language":{"type":"string","enum":["en","es"],"title":"Language","default":"en"},"count":{"type":"integer","maximum":8.0,"minimum":1.0,"title":"Count","default":4}},"type":"object","required":["theme"],"title":"TitleSuggestionsRequest"},"TopupCheckoutRequest":{"properties":{"pack_id":{"type":"string","title":"Pack Id","description":"Internal pack_id (topup_50 | topup_200 | topup_500)"},"ga_client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Client Id","description":"Browser GA4 client id; only sent when analytics consent let GA load"},"ga_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Session Id","description":"Browser GA4 session id"},"ga_origin_channel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Origin Channel","description":"Visitor's first-party origin channel"},"ga_origin_source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ga Origin Source","description":"Visitor's first-party origin source"},"revnu_anonymous_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Anonymous Id","description":"Revnu tag's opaque visitor id; only set once analytics consent let it run"},"revnu_consent_state":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Consent State","description":"Revnu tag consent at checkout: granted | denied | pending"},"revnu_google_ad_user_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Google Ad User Data","description":"Google ad-user-data choice at checkout: granted | denied | unknown"},"revnu_google_ad_personalization":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Revnu Google Ad Personalization","description":"Google ad-personalization choice at checkout: granted | denied | unknown"}},"type":"object","required":["pack_id"],"title":"TopupCheckoutRequest"},"UpdateDefaultStylesRequest":{"properties":{"default_style_ids":{"items":{"type":"string"},"type":"array","maxItems":20,"minItems":1,"title":"Default Style Ids"}},"type":"object","required":["default_style_ids"],"title":"UpdateDefaultStylesRequest"},"UpdateStyleRequest":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string","maxLength":2000,"minLength":1},{"type":"null"}],"title":"Description"}},"type":"object","title":"UpdateStyleRequest"},"UserLogin":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":72,"title":"Password"}},"type":"object","required":["email","password"],"title":"UserLogin"},"UserRegister":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"password":{"type":"string","maxLength":72,"minLength":6,"title":"Password"},"name":{"type":"string","maxLength":100,"minLength":2,"title":"Name"},"terms_accepted":{"type":"boolean","const":true,"title":"Terms Accepted"},"attribution":{"anyOf":[{"$ref":"#/components/schemas/FirstTouchAttribution"},{"type":"null"}]},"marketing_opt_in":{"type":"boolean","title":"Marketing Opt In","default":false}},"type":"object","required":["email","password","name","terms_accepted"],"title":"UserRegister"},"UserResponse":{"properties":{"user_id":{"type":"string","title":"User Id"},"email":{"type":"string","title":"Email"},"name":{"type":"string","title":"Name"},"created_at":{"type":"string","title":"Created At"},"default_style_ids":{"items":{"type":"string"},"type":"array","title":"Default Style Ids"},"auth_provider":{"type":"string","title":"Auth Provider","default":"local"},"subscription_plan_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subscription Plan Id"},"is_free":{"type":"boolean","title":"Is Free","default":true},"analytics_excluded":{"type":"boolean","title":"Analytics Excluded","default":false},"analytics_consent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Analytics Consent"}},"type":"object","required":["user_id","email","name","created_at","default_style_ids"],"title":"UserResponse"},"UserStylesListResponse":{"properties":{"styles":{"items":{"$ref":"#/components/schemas/StyleResponse"},"type":"array","title":"Styles"}},"type":"object","required":["styles"],"title":"UserStylesListResponse"},"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"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}