{"openapi":"3.0.3","info":{"title":"ScrinAssist API","version":"1.0.0","description":"Production ScrinAssist Lambda API. Swagger examples contain realistic values that can be edited in Try it out. Protected endpoints require Authorize with a Bearer access token returned by signin/signup."},"servers":[{"url":"https://dev.api.scrinassist.com"}],"tags":[{"name":"Auth","description":"Authentication, sessions, OAuth, and account security"},{"name":"Onboarding","description":"Backend source of truth for post-auth onboarding flow"},{"name":"User Preferences","description":"User settings and document preferences"},{"name":"Notifications","description":"Push notification preferences and device registration"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object"},"message":{"type":"string","example":"OK"}}},"ErrorResponse":{"type":"object","properties":{"success":{"type":"boolean","example":false},"error":{"type":"object","properties":{"code":{"type":"string","example":"AUTH_INVALID_TOKEN"},"message":{"type":"string","example":"Invalid token"}}}}},"ForgotPasswordRequest":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email","description":"Email address for the account that needs a password reset code.","example":"jordan@example.com"}},"example":{"email":"jordan@example.com"}},"ResetPasswordRequest":{"type":"object","required":["email","code","password","confirmPassword"],"properties":{"email":{"type":"string","format":"email","description":"Email address that requested the password reset code.","example":"jordan@example.com"},"code":{"type":"string","pattern":"^[0-9]{6}$","description":"6-digit password reset code sent by email. Numeric JSON values are also accepted by the backend.","example":"778315"},"password":{"type":"string","format":"password","minLength":8,"description":"New password. Must satisfy the auth password policy.","example":"N3wPassw0rd!"},"confirmPassword":{"type":"string","format":"password","description":"Must match password.","example":"N3wPassw0rd!"}},"example":{"email":"jordan@example.com","code":"778315","password":"N3wPassw0rd!","confirmPassword":"N3wPassw0rd!"}},"OnboardingStepState":{"type":"object","properties":{"completed":{"type":"boolean","description":"Whether the step is complete."},"completed_at":{"type":"string","nullable":true,"description":"Completion timestamp, or null."}}},"OnboardingStatusResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"data":{"type":"object","example":{"user_id":"usr_123","onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}},"preferences":{"storage_mode":null,"document_destination":null,"sync_enabled":null,"cloud_storage":null,"reminder_defaults":null,"notification_permission_status":"not_requested"}}}}},"CloudStorageLocation":{"type":"object","description":"Private S3 location reserved for this user's ScrinAssist cloud documents.","properties":{"bucket":{"type":"string","description":"Private S3 bucket used for ScrinAssist cloud storage."},"prefix":{"type":"string","description":"Document object prefix for this user."},"user_root_prefix":{"type":"string","description":"User root prefix that contains all cloud storage subfolders."},"documents_prefix":{"type":"string","description":"Alias of prefix for document objects."}},"example":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","user_root_prefix":"cloud-storage/users/usr_123/","documents_prefix":"cloud-storage/users/usr_123/documents/"}},"DashboardFile":{"type":"object","description":"Compact file payload used by the Home dashboard.","properties":{"id":{"type":"string","description":"File ID."},"title":{"type":"string","description":"Document display title."},"description":{"type":"string","description":"Human-readable AI or user summary for the document. Prefer AI extraction summary/notification body/action reason, with notes as fallback."},"sender":{"type":"string","description":"Issuer, sender, or organization name."},"category":{"type":"string","description":"Document category such as bill, tax, insurance, renewal, or other."},"amount":{"type":"string","description":"Amount due when known."},"dueDate":{"type":"string","format":"date","description":"Due date in YYYY-MM-DD format when known."},"folderId":{"type":"string","description":"Folder ID containing this file."},"status":{"type":"string","description":"File status."},"sourceType":{"type":"string","description":"manual or upload."},"updatedAt":{"type":"integer","description":"Unix timestamp for last update."}},"example":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}},"DashboardReminder":{"type":"object","description":"Compact reminder payload used by the Home dashboard.","properties":{"id":{"type":"string","description":"Reminder ID."},"fileId":{"type":"string","description":"Related file ID when available."},"title":{"type":"string","description":"Reminder title."},"description":{"type":"string","description":"Human-readable reminder context. Uses reminder description/notes when present, otherwise falls back to the linked file AI summary, notification body, action reason, or notes."},"status":{"type":"string","description":"Reminder status such as critical, urgent, upcoming, or completed."},"dueDate":{"type":"string","format":"date","description":"Document due date in YYYY-MM-DD format when known."},"reminderDate":{"type":"string","format":"date","description":"Date the reminder should be sent."},"reminderTime":{"type":"string","description":"Reminder time in HH:MM format."},"channels":{"type":"array","items":{"type":"string","enum":["push","email","call"]},"description":"Notification channels selected for this reminder."},"done":{"type":"boolean","description":"Whether the reminder is completed."}},"example":{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}},"DashboardAttentionItem":{"type":"object","description":"Actionable document payload for Home widgets such as Needs Attention, Due This Week, and Renewals.","properties":{"id":{"type":"string","description":"File ID."},"fileId":{"type":"string","description":"File ID alias for mobile clients."},"name":{"type":"string","description":"Display name of the document or task."},"title":{"type":"string","description":"Document title alias."},"description":{"type":"string","description":"AI-generated or user-entered explanation of the task, reminder reason, or document summary."},"amount":{"type":"string","description":"Amount due when known."},"dueDate":{"type":"string","format":"date","description":"Due date in YYYY-MM-DD format when known."},"org":{"type":"string","description":"Organization, issuer, or sender display name."},"sender":{"type":"string","description":"Sender alias."},"note":{"type":"string","description":"Short note, summary, or action reason."},"category":{"type":"string","description":"Document category."},"urgency":{"type":"string","description":"Urgency marker such as urgent or critical."},"status":{"type":"string","description":"File status."},"sourceType":{"type":"string","description":"manual or upload."},"actionRequired":{"type":"boolean","description":"Whether AI extraction marked this as requiring action."},"actionReason":{"type":"string","description":"Reason the item needs attention when known."}},"example":{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}},"DashboardEmptyState":{"type":"object","description":"Home empty-state decision for users with no active documents.","properties":{"show":{"type":"boolean","description":"Whether the mobile app should show the empty-state screen."},"screen":{"type":"string","enum":["HomeEmptyState"],"description":"Empty-state screen name."},"reason":{"type":"string","description":"Machine-readable empty-state reason, for example no_active_documents."}},"example":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"}},"DashboardFileCounts":{"type":"object","description":"File counters for Home dashboard widgets.","properties":{"active":{"type":"integer","description":"Number of active files."},"archived":{"type":"integer","description":"Number of archived files."},"total":{"type":"integer","description":"Number of non-deleted files."},"byCategory":{"type":"object","additionalProperties":{"type":"integer"},"description":"Active file count grouped by category."}},"example":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}}},"DashboardReminderCounts":{"type":"object","description":"Reminder counters for Home dashboard widgets.","properties":{"overdue":{"type":"integer","description":"Open critical reminders."},"urgent":{"type":"integer","description":"Open urgent reminders."},"upcoming":{"type":"integer","description":"Open upcoming reminders."},"completed":{"type":"integer","description":"Completed reminders."},"total":{"type":"integer","description":"Total non-deleted reminders."}},"example":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7}},"DashboardSummary":{"type":"object","description":"Dashboard content shown on HomeDashboard.","properties":{"files":{"$ref":"#/components/schemas/DashboardFileCounts"},"reminders":{"$ref":"#/components/schemas/DashboardReminderCounts"},"latestFiles":{"type":"array","items":{"$ref":"#/components/schemas/DashboardFile"},"description":"Most recently updated active files, maximum 5."},"nextReminders":{"type":"array","items":{"$ref":"#/components/schemas/DashboardReminder"},"description":"Next open reminders sorted by reminder date and time, maximum 5."},"needsAttention":{"type":"array","items":{"$ref":"#/components/schemas/DashboardAttentionItem"},"description":"Detailed list of documents needing user action. Each item includes name, description, amount, dueDate, org/sender, and note. Maximum 10."},"needsAttentionCount":{"type":"integer","description":"Total count of active documents needing user action. Use this for the Needs Attention badge/count even when only the first 10 items are returned.","example":1},"urgent":{"type":"integer","description":"Dashboard-level urgent/action count derived from needsAttention. This matches the documents shown in the Needs Attention list. Note: reminders.urgent remains a reminder-only count.","example":1},"dueThisWeek":{"type":"integer","description":"Count of active documents with a due date from today through the next 7 days.","example":1},"renewals":{"type":"integer","description":"Count of active renewal documents detected by category, title, notes, or AI action type.","example":1}},"example":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}},"DashboardSummaryData":{"type":"object","description":"Home dashboard summary and screen decision payload.","properties":{"user_id":{"type":"string","description":"Authenticated user ID."},"home_screen":{"type":"string","enum":["HomeDashboard","HomeEmptyState"],"description":"Home screen the mobile app should render."},"has_documents":{"type":"boolean","description":"Whether the user has active documents."},"empty_state":{"$ref":"#/components/schemas/DashboardEmptyState"},"summary":{"$ref":"#/components/schemas/DashboardSummary"}},"example":{"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}}},"DashboardSummaryResponse":{"type":"object","description":"Home dashboard summary and empty-state decision.","properties":{"ok":{"type":"boolean","example":true},"success":{"type":"boolean","example":true},"data":{"$ref":"#/components/schemas/DashboardSummaryData"},"user_id":{"type":"string","description":"Top-level compatibility copy of data.user_id."},"home_screen":{"type":"string","description":"Top-level compatibility copy of data.home_screen."},"has_documents":{"type":"boolean","description":"Top-level compatibility copy of data.has_documents."},"empty_state":{"$ref":"#/components/schemas/DashboardEmptyState"},"summary":{"$ref":"#/components/schemas/DashboardSummary"}},"example":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}},"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}}},"UploadInitRequest":{"type":"object","required":["fileName","contentType","fileSize"],"properties":{"fileName":{"type":"string","description":"Original file name from camera scan or file picker."},"contentType":{"type":"string","description":"MIME type, for example application/pdf or image/jpeg."},"fileSize":{"type":"integer","description":"File size in bytes. Checked against the user's plan upload limit."},"folderId":{"type":"string","description":"Destination folder, defaults to inbox."},"title":{"type":"string","description":"Initial file title."},"category":{"type":"string","description":"Initial category hint."}},"example":{"fileName":"IMG_2041.jpg","contentType":"image/jpeg","fileSize":348912}},"UploadInitUpload":{"type":"object","description":"Presigned S3 upload target. Mobile should PUT the raw file bytes to uploadUrl without an Authorization header.","properties":{"id":{"type":"string","description":"Upload record ID."},"uploadUrl":{"type":"string","description":"Time-limited S3 presigned PUT URL."},"objectKey":{"type":"string","description":"Private S3 object key created for the uploaded file."},"bucket":{"type":"string","description":"Private uploads bucket."},"contentType":{"type":"string","description":"Content-Type that must be used in the S3 PUT request."},"maxUploadBytes":{"type":"integer","description":"Maximum file size allowed for the authenticated user's plan."},"plan":{"type":"string","description":"Plan code used to calculate upload limits."},"storageMode":{"type":"string","enum":["local","cloud"],"description":"Storage mode selected during onboarding."},"documentDestination":{"type":"string","description":"Document destination selected during onboarding."},"uploadPurpose":{"type":"string","enum":["cloud_document","temporary_extraction"],"description":"cloud_document means the uploaded file remains in ScrinAssist cloud storage. temporary_extraction means the object is only used for OCR/AI and is deleted after extraction."},"temporary":{"type":"boolean","description":"Whether the object is temporary and should not be treated as the user's stored document."},"deleteAfterExtraction":{"type":"boolean","description":"Whether /api/ai/extract deletes the uploaded object after OCR/AI processing."}},"example":{"id":"upload_123","uploadUrl":"https://s3-presigned-upload-url","objectKey":"cloud-storage/users/usr_123/documents/upload_123/council-tax.pdf","bucket":"scrinassist-dev-cloud-storage","contentType":"application/pdf","maxUploadBytes":10485760,"plan":"free","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false}},"UploadInitFile":{"type":"object","description":"Tracked file stub created before the bytes are uploaded. AI extraction later enriches this record.","properties":{"id":{"type":"string","description":"Tracked file ID. Use this as fileId for /api/ai/extract."},"title":{"type":"string","description":"Initial title. Defaults to fileName when the request omits title."},"sender":{"type":"string","description":"Sender or organization if supplied, otherwise empty until extraction/review."},"category":{"type":"string","description":"Initial category. Defaults to other when omitted."},"amount":{"type":"string","description":"Amount due if supplied, otherwise empty until extraction/review."},"dueDate":{"type":"string","description":"Due date if supplied, otherwise empty until extraction/review."},"folderId":{"type":"string","description":"Folder ID. Defaults to inbox when omitted."},"status":{"type":"string","description":"Tracked file status."},"sourceType":{"type":"string","enum":["upload"],"description":"Upload-created records use upload."},"storageMode":{"type":"string","enum":["local","cloud"],"description":"Storage mode selected during onboarding."},"documentDestination":{"type":"string","description":"Document destination selected during onboarding."},"uploadPurpose":{"type":"string","enum":["cloud_document","temporary_extraction"],"description":"How the uploaded S3 object is retained."},"temporary":{"type":"boolean","description":"True for local-storage temporary extraction uploads."},"deleteAfterExtraction":{"type":"boolean","description":"True when the object is deleted after AI extraction."},"uploadObjectDeleted":{"type":"boolean","description":"Set true after the temporary object has been deleted."}},"example":{"id":"file_123","title":"Council Tax Bill","sender":"","category":"bill","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false}},"UploadInitResponse":{"type":"object","description":"Response returned by POST /api/files/upload-init before the mobile app uploads bytes to S3.","properties":{"ok":{"type":"boolean","example":true},"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"upload":{"$ref":"#/components/schemas/UploadInitUpload"},"file":{"$ref":"#/components/schemas/UploadInitFile"}}},"upload":{"$ref":"#/components/schemas/UploadInitUpload"},"file":{"$ref":"#/components/schemas/UploadInitFile"}},"example":{"ok":true,"success":true,"data":{"upload":{"id":"upload_456","uploadUrl":"https://s3-presigned-upload-url","objectKey":"temporary-extraction/users/usr_123/upload_456/IMG_2041.jpg","bucket":"scrinassist-dev-cloud-storage","contentType":"image/jpeg","maxUploadBytes":10485760,"plan":"free","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true},"file":{"id":"file_456","title":"IMG_2041.jpg","sender":"","category":"other","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true}},"upload":{"id":"upload_456","uploadUrl":"https://s3-presigned-upload-url","objectKey":"temporary-extraction/users/usr_123/upload_456/IMG_2041.jpg","bucket":"scrinassist-dev-cloud-storage","contentType":"image/jpeg","maxUploadBytes":10485760,"plan":"free","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true},"file":{"id":"file_456","title":"IMG_2041.jpg","sender":"","category":"other","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true}}},"DocumentCategory":{"type":"object","description":"Canonical document category used across files, AI extraction, dashboard, search, reminders, and mobile category pickers.","properties":{"id":{"type":"string","description":"Stable category ID to store and send to backend."},"label":{"type":"string","description":"Human-readable label for UI display."},"description":{"type":"string","description":"When this category should be used."}},"example":{"id":"bill","label":"Bills & Payments","description":"Payment requests, invoices, council tax bills, utility bills, and other amounts due."}},"CategoriesListResponse":{"type":"object","description":"Backend-owned category vocabulary response.","properties":{"ok":{"type":"boolean","example":true},"success":{"type":"boolean","example":true},"data":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DocumentCategory"},"description":"Canonical category objects."},"default":{"type":"string","description":"Default category for unknown or omitted category values."},"ids":{"type":"array","items":{"type":"string"},"description":"Stable category ID list."}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/DocumentCategory"}},"default":{"type":"string"},"ids":{"type":"array","items":{"type":"string"}}},"example":{"ok":true,"success":true,"data":{"items":[{"id":"bill","label":"Bills & Payments","description":"Payment requests, invoices, council tax bills, utility bills, and other amounts due."},{"id":"notice","label":"Notices","description":"Letters or notices that need review, response, or acknowledgement."},{"id":"renewal","label":"Renewals","description":"Policies, subscriptions, contracts, or services that need renewal."},{"id":"medical","label":"Medical","description":"Health, appointment, prescription, and medical admin documents."},{"id":"tax","label":"Tax","description":"Tax documents, tax deadlines, assessments, and HMRC-style letters."},{"id":"insurance","label":"Insurance","description":"Insurance policies, claims, quotes, renewals, and coverage documents."},{"id":"utilities","label":"Utilities","description":"Energy, water, broadband, phone, and service provider documents."},{"id":"legal","label":"Legal","description":"Legal notices, contracts, claims, agreements, and solicitor letters."},{"id":"banking","label":"Banking","description":"Bank, card, loan, mortgage, and financial account documents."},{"id":"subscription","label":"Subscriptions","description":"Recurring subscriptions, memberships, and paid service notices."},{"id":"housing","label":"Housing","description":"Rent, tenancy, property, mortgage, council, and housing documents."},{"id":"education","label":"Education","description":"School, university, training, fees, and education admin documents."},{"id":"vehicle","label":"Vehicle","description":"Car, MOT, road tax, parking, insurance, finance, and vehicle documents."},{"id":"government","label":"Government","description":"Government, council, benefits, identity, immigration, and public-service documents."},{"id":"other","label":"Other","description":"Fallback category when no specific category applies."}],"default":"other","ids":["bill","notice","renewal","medical","tax","insurance","utilities","legal","banking","subscription","housing","education","vehicle","government","other"]},"items":[{"id":"bill","label":"Bills & Payments","description":"Payment requests, invoices, council tax bills, utility bills, and other amounts due."},{"id":"notice","label":"Notices","description":"Letters or notices that need review, response, or acknowledgement."},{"id":"renewal","label":"Renewals","description":"Policies, subscriptions, contracts, or services that need renewal."},{"id":"medical","label":"Medical","description":"Health, appointment, prescription, and medical admin documents."},{"id":"tax","label":"Tax","description":"Tax documents, tax deadlines, assessments, and HMRC-style letters."},{"id":"insurance","label":"Insurance","description":"Insurance policies, claims, quotes, renewals, and coverage documents."},{"id":"utilities","label":"Utilities","description":"Energy, water, broadband, phone, and service provider documents."},{"id":"legal","label":"Legal","description":"Legal notices, contracts, claims, agreements, and solicitor letters."},{"id":"banking","label":"Banking","description":"Bank, card, loan, mortgage, and financial account documents."},{"id":"subscription","label":"Subscriptions","description":"Recurring subscriptions, memberships, and paid service notices."},{"id":"housing","label":"Housing","description":"Rent, tenancy, property, mortgage, council, and housing documents."},{"id":"education","label":"Education","description":"School, university, training, fees, and education admin documents."},{"id":"vehicle","label":"Vehicle","description":"Car, MOT, road tax, parking, insurance, finance, and vehicle documents."},{"id":"government","label":"Government","description":"Government, council, benefits, identity, immigration, and public-service documents."},{"id":"other","label":"Other","description":"Fallback category when no specific category applies."}],"default":"other","ids":["bill","notice","renewal","medical","tax","insurance","utilities","legal","banking","subscription","housing","education","vehicle","government","other"]}},"ManualItemRequest":{"type":"object","required":["title"],"properties":{"title":{"type":"string","description":"Manual item title."},"category":{"type":"string","description":"Document category such as bill, tax, insurance, renewal, other."},"sender":{"type":"string","description":"Issuer, sender, or organization name."},"amount":{"type":"string","description":"Amount as entered by the user."},"dueDate":{"type":"string","format":"date","description":"Due date in YYYY-MM-DD format when known."},"referenceNumber":{"type":"string","description":"Reference or account number from the document."},"folderId":{"type":"string","description":"Folder destination. Defaults to inbox."},"urgency":{"type":"string","description":"Optional urgency hint from the manual form."},"notes":{"type":"string","description":"User-entered notes from ManualAddScreen."},"sourceType":{"type":"string","enum":["manual"],"description":"Use manual for manually created items."}},"example":{"title":"Council Tax Payment","category":"bill","sender":"Bristol Council","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","folderId":"council-tax","urgency":"urgent","notes":"Pay before month end","sourceType":"manual"}},"CreateFolderRequest":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Folder display name."},"color":{"type":"string","description":"Hex color used by folder UI.","example":"#4A9EFF"},"parentFolderId":{"type":"string","description":"Optional parent folder ID. Use inbox or an existing folder ID."}},"example":{"name":"Council Tax","color":"#4A9EFF","parentFolderId":"utilities"}},"UpdateFileRequest":{"type":"object","properties":{"title":{"type":"string","description":"Updated file title."},"sender":{"type":"string","description":"Issuer, sender, or organization name."},"category":{"type":"string","description":"Document category such as bill, tax, insurance, renewal, other."},"amount":{"type":"string","description":"Amount as entered or extracted."},"dueDate":{"type":"string","format":"date","description":"Due date in YYYY-MM-DD format when known."},"referenceNumber":{"type":"string","description":"Reference or account number."},"urgency":{"type":"string","description":"Urgency hint used by file lists and reminder views."},"notes":{"type":"string","description":"User notes shown in FileDetail/EditFileInfo."},"favorite":{"type":"boolean","description":"Whether the file appears under the Favorites tab."},"isFavorite":{"type":"boolean","description":"Mobile-friendly alias for favorite."}},"example":{"title":"Council Tax Payment 2026","sender":"Local Council","category":"bill","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","urgency":"urgent","notes":"Pay before month end","favorite":true}},"MoveFileRequest":{"type":"object","required":["folderId"],"properties":{"folderId":{"type":"string","description":"Destination folder ID. Use inbox for the virtual inbox."}},"example":{"folderId":"utilities"}},"SaveExtractedDetailsRequest":{"type":"object","required":["details"],"properties":{"details":{"type":"object","description":"Reviewed or AI-extracted file metadata.","additionalProperties":true}},"example":{"details":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]}}},"FinalizeReviewedUploadRequest":{"type":"object","required":["folderId","details"],"properties":{"folderId":{"type":"string","description":"Selected destination folder ID from FolderSuggestion/Select Folder. Use inbox for the virtual inbox."},"details":{"type":"object","description":"Final user-reviewed extracted details from ExtractedDetailsReview. Stored as extractedDetails.","additionalProperties":true},"file":{"type":"object","description":"Optional top-level file fields to update. If omitted, backend derives title, sender, category, amount, dueDate, referenceNumber, and notes from details where possible.","properties":{"title":{"type":"string"},"sender":{"type":"string"},"category":{"type":"string"},"amount":{"type":"string"},"dueDate":{"type":"string","format":"date"},"referenceNumber":{"type":"string"},"urgency":{"type":"string"},"notes":{"type":"string"}}}},"example":{"folderId":"utilities","details":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"file":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","notes":"Council tax payment is due by 31 May 2026."}}},"CreateReminderRequest":{"type":"object","required":["title"],"properties":{"fileId":{"type":"string","description":"File/tracked item ID returned from manual item creation."},"title":{"type":"string","description":"Reminder title."},"dueDate":{"type":"string","format":"date","description":"Due date in YYYY-MM-DD format."},"reminderDate":{"type":"string","format":"date","description":"Date the reminder should fire."},"reminderTime":{"type":"string","description":"Local reminder time in HH:MM format."},"channels":{"type":"array","items":{"type":"string","enum":["push","email","call"]}},"status":{"type":"string","enum":["critical","urgent","upcoming","completed"]}},"example":{"fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming"}},"UpdateReminderRequest":{"type":"object","properties":{"fileId":{"type":"string","description":"Optional new file/tracked item link."},"title":{"type":"string","description":"Updated reminder title."},"dueDate":{"type":"string","format":"date","description":"Updated due date in YYYY-MM-DD format."},"reminderDate":{"type":"string","format":"date","description":"Updated reminder fire date."},"reminderTime":{"type":"string","description":"Updated local reminder time in HH:MM format."},"channels":{"type":"array","items":{"type":"string","enum":["push","email","call"]}},"status":{"type":"string","enum":["critical","urgent","upcoming","completed"]},"done":{"type":"boolean","description":"Whether the reminder has been completed."}},"example":{"title":"Council Tax Payment","reminderDate":"2026-05-28","reminderTime":"10:00","channels":["push","email"],"status":"upcoming","done":false}},"ReminderResponse":{"type":"object","description":"Reminder payload returned by create, get, update, and delete.","example":{"ok":true,"success":true,"data":{"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}},"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}}},"SettingsUpdateRequest":{"type":"object","properties":{"storageMode":{"type":"string","enum":["local","cloud"],"description":"General storage mode alias. Use /api/settings/storage for complete storage updates."},"notificationChannels":{"type":"array","items":{"type":"string","enum":["push","email","call"]},"description":"Default reminder delivery channels. SMS is not accepted until SMS dispatch exists."},"defaultReminderOffsets":{"type":"array","items":{"type":"integer","minimum":0},"description":"Default reminder offsets in days before due date. 0 means on due date."},"timezone":{"type":"string","description":"IANA timezone, for example Europe/London."},"language":{"type":"string"},"theme":{"type":"string","enum":["light","dark","system"]},"escalationEnabled":{"type":"boolean"},"escalationDelayHours":{"type":"integer","enum":[12,24,48,72]}},"example":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":true,"escalationDelayHours":24}},"StorageSettingsUpdateRequest":{"type":"object","required":["storageMode"],"properties":{"storageMode":{"type":"string","enum":["local","cloud"],"description":"local keeps real documents on the device; cloud stores future documents in ScrinAssist S3 cloud storage."},"documentDestination":{"type":"string","enum":["device_only","scrinassist_cloud","google_drive","icloud","dropbox"],"description":"Third-party destinations are documented for future use but currently return STORAGE_PROVIDER_UNSUPPORTED."},"syncEnabled":{"type":"boolean","description":"Whether cloud sync is enabled for future uploads."},"deleteAfterUpload":{"type":"boolean","description":"Retention toggle used by StorageSettings."},"autoExportMonthly":{"type":"boolean","description":"Whether monthly export automation is requested."}},"example":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true}},"ReminderSettingsUpdateRequest":{"type":"object","required":["defaultReminderOffsets","defaultChannels","timezone"],"properties":{"defaultReminderEnabled":{"type":"boolean"},"defaultReminderOffsets":{"type":"array","items":{"type":"integer","minimum":0},"description":"Default offsets in days before due date. 0 means due-date reminder."},"defaultChannels":{"type":"array","items":{"type":"string","enum":["push","email","call"]},"description":"Default reminder channels. call requires a premium plan and verified phone."},"timezone":{"type":"string","description":"IANA timezone."},"quietHoursEnabled":{"type":"boolean"},"quietHoursStart":{"type":"string","example":"21:00"},"quietHoursEnd":{"type":"string","example":"08:00"},"escalationEnabled":{"type":"boolean"},"escalationDelayHours":{"type":"integer","enum":[12,24,48,72]}},"example":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultChannels":["push","email"],"timezone":"Europe/London","quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","escalationEnabled":true,"escalationDelayHours":24}},"NotificationDevice":{"type":"object","description":"Registered notification device. Raw push tokens are not returned.","properties":{"deviceId":{"type":"string"},"platform":{"type":"string","enum":["ios","android"]},"pushTokenStored":{"type":"boolean"},"snsEndpointArn":{"type":"string"},"snsTopicSubscriptionArn":{"type":"string"},"appVersion":{"type":"string"},"deviceName":{"type":"string"},"notificationEnabled":{"type":"boolean"},"endpointStatus":{"type":"string","enum":["active","disabled","invalid"]},"lastError":{"type":"string"},"lastSeenAt":{"type":"integer"},"createdAt":{"type":"integer"},"updatedAt":{"type":"integer"}},"example":{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}},"NotificationPreferencesUpdateRequest":{"type":"object","properties":{"notificationChannels":{"type":"array","items":{"type":"string","enum":["push","email","call"]},"description":"Enabled reminder delivery channels."},"deviceId":{"type":"string","description":"Device to toggle when notificationEnabled is supplied."},"notificationEnabled":{"type":"boolean","description":"Enable or disable a registered device."}},"example":{"notificationChannels":["push","email"]}},"RegisterDeviceRequest":{"type":"object","required":["deviceId","platform"],"properties":{"deviceId":{"type":"string","description":"Stable app/device identifier."},"platform":{"type":"string","enum":["ios","android"]},"pushToken":{"type":"string","description":"APNS or FCM token. Required when notificationEnabled=true."},"appVersion":{"type":"string"},"deviceName":{"type":"string"},"notificationEnabled":{"type":"boolean"}},"example":{"deviceId":"device_abc123","platform":"ios","pushToken":"apns_or_fcm_device_token_here","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true}},"UnregisterDeviceRequest":{"type":"object","required":["deviceId"],"properties":{"deviceId":{"type":"string","description":"Device identifier to unregister."}},"example":{"deviceId":"device_abc123"}},"TestNotificationRequest":{"type":"object","properties":{"deviceId":{"type":"string","description":"Optional device ID. Omit to send to all active devices."},"title":{"type":"string"},"body":{"type":"string"},"reminderId":{"type":"string","description":"Optional reminder deep-link target."}},"example":{"deviceId":"device_abc123","title":"ScrinAssist Test Notification","body":"Push delivery is configured for this device.","reminderId":"reminder_123"}},"PhoneVerificationStartRequest":{"type":"object","required":["phoneNumber"],"properties":{"phoneNumber":{"type":"string","description":"User phone number in E.164 format. This is the number Amazon Connect calls.","example":"+447700900123"}},"example":{"phoneNumber":"+447700900123"}},"PhoneVerificationConfirmRequest":{"type":"object","required":["phoneNumber","code"],"properties":{"phoneNumber":{"type":"string","description":"Phone number being verified in E.164 format."},"verificationId":{"type":"string","description":"Verification ID returned by the start endpoint."},"code":{"type":"string","description":"Six-digit challenge code entered in the Amazon Connect call."}},"example":{"phoneNumber":"+447700900123","verificationId":"phone_verification_123","code":"123456"}},"AIExtractRequest":{"type":"object","properties":{"fileId":{"type":"string","description":"Tracked file ID created by upload-init."},"text":{"type":"string","description":"Optional dev/test fallback. Production mobile uploads should omit this so the backend reads S3 and Textract."},"title":{"type":"string","description":"Optional extraction hint."},"sender":{"type":"string","description":"Optional extraction hint."},"category":{"type":"string","description":"Optional extraction hint."}},"example":{"fileId":"file_123"}},"AIExtractResponse":{"type":"object","description":"Structured document action intelligence from Textract plus OpenAI structured output.","example":{"ok":true,"success":true,"data":{"request_id":"ai_req_123","file_id":"file_123","status":"completed","result":{"document_type":"bill","title":"Council Tax Bill","sender":"Bristol Council","summary":"Council tax bill requiring payment by 2026-05-31.","category":"bill","action_required":true,"action_type":"payment_due","action_reason":"The document contains an amount due and a due date.","due_date":"2026-05-31","dueDate":"2026-05-31","amount":"145.30","currency":"GBP","reference_number":"CT-2026-001","referenceNumber":"CT-2026-001","notification_title":"Council tax payment due","notificationTitle":"Council tax payment due","notification_body":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","notificationBody":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","recommended_reminders":[7,3,1],"recommendedReminders":[7,3,1],"confidence":0.87,"needs_human_review":false,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano"},"metadata":{"status":"completed","provider":"openai","model":"gpt-5.4-nano","ocr_provider":"aws_textract","line_count":42,"fallback_used":false}},"request_id":"ai_req_123","file_id":"file_123","status":"completed","result":{"document_type":"bill","title":"Council Tax Bill","sender":"Bristol Council","summary":"Council tax bill requiring payment by 2026-05-31.","category":"bill","action_required":true,"action_type":"payment_due","action_reason":"The document contains an amount due and a due date.","due_date":"2026-05-31","dueDate":"2026-05-31","amount":"145.30","currency":"GBP","reference_number":"CT-2026-001","referenceNumber":"CT-2026-001","notification_title":"Council tax payment due","notificationTitle":"Council tax payment due","notification_body":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","notificationBody":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","recommended_reminders":[7,3,1],"recommendedReminders":[7,3,1],"confidence":0.87,"needs_human_review":false,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano"},"metadata":{"status":"completed","provider":"openai","model":"gpt-5.4-nano","ocr_provider":"aws_textract","line_count":42,"fallback_used":false}}},"StoragePreferenceRequest":{"type":"object","required":["storage_mode","document_destination"],"properties":{"storage_mode":{"type":"string","enum":["local","cloud"],"description":"Where document data should be stored."},"document_destination":{"type":"string","enum":["device_only","scrinassist_cloud","google_drive","icloud","dropbox"],"description":"Chosen document destination. Third-party providers are documented but currently return ONBOARDING_STORAGE_PROVIDER_UNSUPPORTED."},"sync_enabled":{"type":"boolean","description":"Whether cloud sync is enabled. Use false for device_only local storage."}},"example":{"storage_mode":"cloud","document_destination":"scrinassist_cloud","sync_enabled":true}},"ReminderPreferencesRequest":{"type":"object","required":["default_reminder_enabled","default_reminder_days_before","timezone","preferred_channels"],"properties":{"default_reminder_enabled":{"type":"boolean"},"default_reminder_days_before":{"type":"array","items":{"type":"integer","minimum":0},"description":"Reminder offsets in days before due date. 0 means on the due date."},"quiet_hours_enabled":{"type":"boolean"},"quiet_hours_start":{"type":"string","example":"21:00"},"quiet_hours_end":{"type":"string","example":"08:00"},"timezone":{"type":"string","description":"Valid IANA timezone.","example":"Europe/London"},"preferred_channels":{"type":"array","items":{"type":"string","enum":["push","email","call"]}}},"example":{"default_reminder_enabled":true,"default_reminder_days_before":[7,3,1,0],"quiet_hours_enabled":true,"quiet_hours_start":"21:00","quiet_hours_end":"08:00","timezone":"Europe/London","preferred_channels":["push","email"]}},"NotificationPermissionRequest":{"type":"object","required":["permission_status","platform"],"properties":{"permission_status":{"type":"string","enum":["granted","denied","provisional","not_requested"]},"platform":{"type":"string","enum":["ios","android","web"]},"device_token":{"type":"string","description":"Required when permission_status is granted."},"provider":{"type":"string","example":"sns"},"device_id":{"type":"string","description":"Stable mobile device identifier."}},"example":{"permission_status":"granted","platform":"ios","device_token":"apns_or_fcm_device_token_here","provider":"sns","device_id":"device_abc123"}}}},"paths":{"/":{"get":{"operationId":"get","summary":"GET /","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/openapi":{"get":{"operationId":"getopenapi","summary":"GET /openapi","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/docs":{"get":{"operationId":"getdocs","summary":"GET /docs","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/swagger":{"get":{"operationId":"getswagger","summary":"GET /swagger","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/redoc":{"get":{"operationId":"getredoc","summary":"GET /redoc","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/openapi.json":{"get":{"operationId":"getopenapi.json","summary":"GET /openapi.json","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/openapi.yaml":{"get":{"operationId":"getopenapi.yaml","summary":"GET /openapi.yaml","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/openapi.yam":{"get":{"operationId":"getopenapi.yam","summary":"GET /openapi.yam","tags":["docs"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}}}},"/api/auth/signup":{"post":{"operationId":"postapi_auth_signup","summary":"Create email/password account","tags":["Auth"],"parameters":[],"responses":{"201":{"description":"Account created","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}},"maskedEmail":"j***n@example.com"},"message":"Account created. Verify your email to continue.","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}},"maskedEmail":"j***n@example.com"}}}},"200":{"description":"Unverified signup resumed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}},"maskedEmail":"j***n@example.com"},"message":"Verification code sent. Verify your email to continue.","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}},"maskedEmail":"j***n@example.com"}}}},"409":{"description":"Email exists","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_EMAIL_EXISTS","message":"An account already exists for this email"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Jordan Smith"},"email":{"type":"string","example":"jordan@example.com"},"password":{"type":"string","example":"Str0ngPass123"},"confirmPassword":{"type":"string","example":"Str0ngPass123"},"rememberMe":{"type":"boolean","example":true},"deviceInfo":{"type":"object","example":{"deviceId":"ios-simulator-001","platform":"ios","appVersion":"1.0.0"}}},"required":["name","email","password","confirmPassword"]},"example":{"name":"Jordan Smith","email":"jordan@example.com","password":"Str0ngPass123","confirmPassword":"Str0ngPass123","rememberMe":true,"deviceInfo":{"deviceId":"ios-simulator-001","platform":"ios","appVersion":"1.0.0"}}}}}}},"/api/auth/signin":{"post":{"operationId":"postapi_auth_signin","summary":"Sign in with email/password","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Signed in","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}},"message":"Signed in","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}}}}},"401":{"description":"Invalid credentials","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_CREDENTIALS","message":"Email or password is incorrect"}}}}},"403":{"description":"Email not verified","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_EMAIL_NOT_VERIFIED","message":"Verify your email before signing in"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","example":"jordan@example.com"},"password":{"type":"string","example":"Str0ngPass123"},"rememberMe":{"type":"boolean","example":true},"deviceInfo":{"type":"object","example":{"deviceId":"ios-simulator-001","platform":"ios"}}},"required":["email","password"]},"example":{"email":"jordan@example.com","password":"Str0ngPass123","rememberMe":true,"deviceInfo":{"deviceId":"ios-simulator-001","platform":"ios"}}}}}}},"/api/auth/oauth/google":{"post":{"operationId":"postapi_auth_oauth_google","summary":"Sign in or sign up with Google ID token","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Signed in","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}},"message":"Signed in","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}}}}},"401":{"description":"OAuth validation failed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_OAUTH_VALIDATION_FAILED","message":"Google sign-in could not be verified"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idToken":{"type":"string","example":"google-id-token-from-native-sdk"},"rememberMe":{"type":"boolean","example":true},"deviceInfo":{"type":"object","example":{"deviceId":"ios-simulator-001"}}},"required":["idToken"]},"example":{"idToken":"google-id-token-from-native-sdk","rememberMe":true,"deviceInfo":{"deviceId":"ios-simulator-001"}}}}}}},"/api/auth/oauth/apple":{"post":{"operationId":"postapi_auth_oauth_apple","summary":"Sign in or sign up with Apple identity token","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Signed in","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}},"message":"Signed in","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}}}}},"401":{"description":"OAuth validation failed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_OAUTH_VALIDATION_FAILED","message":"Apple sign-in could not be verified"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"identityToken":{"type":"string","example":"apple-identity-token-from-native-sdk"},"name":{"type":"string","example":"Jordan Smith"},"rememberMe":{"type":"boolean","example":true},"deviceInfo":{"type":"object","example":{"deviceId":"ios-simulator-001"}}},"required":["identityToken"]},"example":{"identityToken":"apple-identity-token-from-native-sdk","name":"Jordan Smith","rememberMe":true,"deviceInfo":{"deviceId":"ios-simulator-001"}}}}}}},"/api/auth/session":{"get":{"operationId":"getapi_auth_session","summary":"Return current authenticated session with onboarding state","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Session loaded","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}},"message":"Session loaded","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}}}}},"401":{"description":"Invalid token","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/verify-email":{"post":{"operationId":"postapi_auth_verify_email","summary":"Verify email with a 6-digit code","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Email verified","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}},"message":"Email verified","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}}}}},"400":{"description":"Invalid code","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_VERIFICATION_CODE","message":"Invalid verification code"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","example":"jordan@example.com"},"code":{"type":"string","example":"123456"}},"required":["email","code"]},"example":{"email":"jordan@example.com","code":"123456"}}}}}},"/api/auth/resend-verification":{"post":{"operationId":"postapi_auth_resend_verification","summary":"Resend verification code","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Verification sent","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"maskedEmail":"j***n@example.com"},"message":"Verification code sent","maskedEmail":"j***n@example.com"}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_RATE_LIMITED","message":"Too many requests. Try again later."}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","example":"jordan@example.com"}},"required":["email"]},"example":{"email":"jordan@example.com"}}}}}},"/api/auth/forgot-password":{"post":{"operationId":"postapi_auth_forgot_password","summary":"Request password reset code","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Password reset code requested","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"maskedEmail":"j***n@example.com","masked_email":"j***n@example.com","devResetCode":"778315","dev_reset_code":"778315"},"message":"If an account exists for this email, we've sent password reset instructions.","maskedEmail":"j***n@example.com","masked_email":"j***n@example.com","devResetCode":"778315","dev_reset_code":"778315"}}}},"400":{"description":"Invalid email","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_EMAIL","message":"Enter a valid email address"}}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_RATE_LIMITED","message":"Too many requests. Try again later."}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForgotPasswordRequest"},"example":{"email":"jordan@example.com"}}}}}},"/api/auth/reset-password":{"post":{"operationId":"postapi_auth_reset_password","summary":"Reset password with code","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Password reset","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"Password reset. Sign in with your new password."}}}},"400":{"description":"Invalid password","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_PASSWORD_TOO_WEAK","message":"Password must include an uppercase letter"}}}}},"401":{"description":"Invalid or expired reset code","content":{"application/json":{"schema":{"type":"object"},"examples":{"invalidCode":{"summary":"Invalid code","value":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Reset token is invalid"}}},"expiredCode":{"summary":"Expired code","value":{"success":false,"error":{"code":"AUTH_EXPIRED_TOKEN","message":"Reset token expired"}}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResetPasswordRequest"},"example":{"email":"jordan@example.com","code":"778315","password":"N3wPassw0rd!","confirmPassword":"N3wPassw0rd!"}}}}}},"/api/auth/change-password":{"post":{"operationId":"postapi_auth_change_password","summary":"Change password for signed-in email user","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Password changed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"Password changed. Sign in again on your devices."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"currentPassword":{"type":"string","example":"Str0ngPass123"},"newPassword":{"type":"string","example":"N3wPassw0rd!"},"confirmPassword":{"type":"string","example":"N3wPassw0rd!"}},"required":["currentPassword","newPassword","confirmPassword"]},"example":{"currentPassword":"Str0ngPass123","newPassword":"N3wPassw0rd!","confirmPassword":"N3wPassw0rd!"}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/change-email":{"post":{"operationId":"postapi_auth_change_email","summary":"Start verified email change","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Verification sent","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"maskedEmail":"j***n@example.com"},"message":"Verification code sent to your new email","maskedEmail":"j***n@example.com"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"newEmail":{"type":"string","example":"jordan.new@example.com"}},"required":["newEmail"]},"example":{"newEmail":"jordan.new@example.com"}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/refresh-token":{"post":{"operationId":"postapi_auth_refresh_token","summary":"Rotate refresh token and issue new access token","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Session refreshed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}},"message":"Session refreshed","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.signature","refreshToken":"refresh-token-from-response","refresh_token":"refresh-token-from-response","expiresIn":2592000,"expires_in":2592000,"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","session_id":"58f50c89-8f42-41a7-8657-35f501928dd0","refreshExpiresAt":1774896000,"refresh_expires_at":1774896000,"onboarding":{"onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}}}}}}},"401":{"description":"Session expired","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_SESSION_EXPIRED","message":"Session expired"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","example":"refresh-token-from-response"}},"required":["refreshToken"]},"example":{"refreshToken":"refresh-token-from-response"}}}}}},"/api/auth/signout":{"post":{"operationId":"postapi_auth_signout","summary":"Sign out current session","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Signed out","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"Signed out"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","example":"refresh-token-from-response"}}},"example":{"refreshToken":"refresh-token-from-response"}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/signout-all":{"post":{"operationId":"postapi_auth_signout_all","summary":"Sign out all devices","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Signed out everywhere","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"Signed out on all devices"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{}},"example":{}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/delete-account":{"delete":{"operationId":"deleteapi_auth_delete_account","summary":"Soft delete account","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Deletion scheduled","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"deletedAt":1767225600,"permanentDeletionScheduledAt":1769817600},"message":"Account deletion scheduled","deletedAt":1767225600,"permanentDeletionScheduledAt":1769817600}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string","example":"Str0ngPass123"},"confirmation":{"type":"string","example":"DELETE"}}},"example":{"password":"Str0ngPass123","confirmation":"DELETE"}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/me":{"get":{"operationId":"getapi_auth_me","summary":"Get current authenticated user","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"Current user","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}},"message":"OK","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"API alias for /auth/me. Use this or /api/user/profile to hydrate AccountSettings.","security":[{"bearerAuth":[]}]}},"/api/user/profile":{"get":{"operationId":"getapi_user_profile","summary":"Get user profile","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Profile","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}},"message":"OK","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns profile fields for AccountSettings, including name, email verification state, auth method, plan, and profile photo URL.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_user_profile","summary":"Update profile name","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Profile updated","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}},"message":"Profile updated","user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Jordan Smith"}},"required":["name"]},"example":{"name":"Jordan Smith"}}}},"security":[{"bearerAuth":[]}]}},"/api/user/profile-photo":{"post":{"operationId":"postapi_user_profile_photo","summary":"Create profile photo upload URL or remove photo","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Upload initialized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"upload":{"uploadUrl":"https://s3-presigned-upload-url","objectKey":"profile-photos/usr_123/photo.jpg","bucket":"scrinassist-dev-uploads","contentType":"image/jpeg","expiresIn":900},"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}},"message":"Profile photo upload URL created","upload":{"uploadUrl":"https://s3-presigned-upload-url","objectKey":"profile-photos/usr_123/photo.jpg","bucket":"scrinassist-dev-uploads","contentType":"image/jpeg","expiresIn":900},"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","example":"image/jpeg"},"fileSize":{"type":"integer","example":342144},"remove":{"type":"boolean","example":false}}},"example":{"contentType":"image/jpeg","fileSize":342144,"remove":false}}}},"security":[{"bearerAuth":[]}]}},"/api/user/sessions":{"get":{"operationId":"getapi_user_sessions","summary":"List active user sessions","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Sessions","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"sessions":[{"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","deviceInfo":{"platform":"ios"},"ipAddress":"203.0.113.10","createdAt":1767225600,"lastActiveAt":1767229200,"expiresAt":1774896000,"revokedAt":0,"isCurrent":true}]},"message":"OK","sessions":[{"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","deviceInfo":{"platform":"ios"},"ipAddress":"203.0.113.10","createdAt":1767225600,"lastActiveAt":1767229200,"expiresAt":1774896000,"revokedAt":0,"isCurrent":true}]}}}}},"security":[{"bearerAuth":[]}]}},"/api/user/sessions/{session_id}":{"delete":{"operationId":"deleteapi_user_sessions_session_id","summary":"Revoke a single session","tags":["User Preferences"],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-session-id"}],"responses":{"200":{"description":"Session revoked","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","signedOutCurrentDevice":false},"message":"Session signed out","sessionId":"58f50c89-8f42-41a7-8657-35f501928dd0","signedOutCurrentDevice":false}}}}},"security":[{"bearerAuth":[]}]}},"/api/onboarding/status":{"get":{"operationId":"getapi_onboarding_status","summary":"Get onboarding progress and next mobile screen","tags":["Onboarding"],"parameters":[],"responses":{"200":{"description":"Onboarding status","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user_id":"usr_123","onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}},"preferences":{"storage_mode":null,"document_destination":null,"sync_enabled":null,"cloud_storage":null,"reminder_defaults":null,"notification_permission_status":"not_requested"}},"message":"OK","user_id":"usr_123","onboarding_completed":false,"current_step":"storage_preference","next_screen":"StoragePreferenceSetup","steps":{"storage_preference":{"completed":false,"completed_at":null},"reminder_preferences":{"completed":false,"completed_at":null},"notification_permission":{"completed":false,"completed_at":null}},"preferences":{"storage_mode":null,"document_destination":null,"sync_enabled":null,"cloud_storage":null,"reminder_defaults":null,"notification_permission_status":"not_requested"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/onboarding/storage-preference":{"patch":{"operationId":"patchapi_onboarding_storage_preference","summary":"Save document storage preference","tags":["Onboarding"],"parameters":[],"responses":{"200":{"description":"Storage preference saved","content":{"application/json":{"schema":{"type":"object"},"examples":{"cloud":{"summary":"Cloud storage saved","value":{"success":true,"data":{"user_id":"usr_123","current_step":"reminder_preferences","next_screen":"ReminderPreferenceSetup","onboarding_completed":false,"preferences":{"storage_mode":"cloud","document_destination":"scrinassist_cloud","sync_enabled":true,"cloud_storage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","user_root_prefix":"cloud-storage/users/usr_123/","documents_prefix":"cloud-storage/users/usr_123/documents/"}}},"message":"Storage preference saved successfully.","user_id":"usr_123","current_step":"reminder_preferences","next_screen":"ReminderPreferenceSetup","onboarding_completed":false,"preferences":{"storage_mode":"cloud","document_destination":"scrinassist_cloud","sync_enabled":true,"cloud_storage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","user_root_prefix":"cloud-storage/users/usr_123/","documents_prefix":"cloud-storage/users/usr_123/documents/"}}}},"local":{"summary":"Local storage saved","value":{"success":true,"data":{"user_id":"usr_123","current_step":"reminder_preferences","next_screen":"ReminderPreferenceSetup","onboarding_completed":false,"preferences":{"storage_mode":"local","document_destination":"device_only","sync_enabled":false,"cloud_storage":null}},"message":"Storage preference saved successfully.","user_id":"usr_123","current_step":"reminder_preferences","next_screen":"ReminderPreferenceSetup","onboarding_completed":false,"preferences":{"storage_mode":"local","document_destination":"device_only","sync_enabled":false,"cloud_storage":null}}}}}}},"400":{"description":"Invalid or unsupported storage preference","content":{"application/json":{"schema":{"type":"object"},"examples":{"invalidPayload":{"summary":"Invalid enum or mode/destination pairing","value":{"success":false,"error":{"code":"ONBOARDING_INVALID_PAYLOAD","message":"Please check your onboarding preferences and try again."}}},"unsupportedProvider":{"summary":"Third-party provider not implemented","value":{"success":false,"error":{"code":"ONBOARDING_STORAGE_PROVIDER_UNSUPPORTED","message":"This storage provider is not available yet. Please choose device_only or scrinassist_cloud."}}}}}}},"409":{"description":"Out of order","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"ONBOARDING_STEP_OUT_OF_ORDER","message":"Please complete your storage preference first."}}}}}},"description":"Saves the user's document storage choice. Cloud storage creates a private per-user S3 prefix under cloud-storage/users/<user_id>/documents/.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoragePreferenceRequest"},"examples":{"scrinassistCloud":{"summary":"ScrinAssist cloud storage","value":{"storage_mode":"cloud","document_destination":"scrinassist_cloud","sync_enabled":true}},"deviceOnly":{"summary":"Device-only local storage","value":{"storage_mode":"local","document_destination":"device_only","sync_enabled":false}},"unsupportedThirdParty":{"summary":"Documented but not yet supported","value":{"storage_mode":"cloud","document_destination":"google_drive","sync_enabled":true}}}}}},"security":[{"bearerAuth":[]}]}},"/api/onboarding/reminder-preferences":{"patch":{"operationId":"patchapi_onboarding_reminder_preferences","summary":"Save default reminder preferences","tags":["Onboarding"],"parameters":[],"responses":{"200":{"description":"Reminder preferences saved","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user_id":"usr_123","current_step":"notification_permission","next_screen":"NotificationPermissionPrompt","onboarding_completed":false,"preferences":{"default_reminder_enabled":true,"default_reminder_days_before":[7,3,1,0],"quiet_hours_enabled":true,"quiet_hours_start":"21:00","quiet_hours_end":"08:00","timezone":"Europe/London","preferred_channels":["push","email"]}},"message":"Reminder preferences saved successfully.","user_id":"usr_123","current_step":"notification_permission","next_screen":"NotificationPermissionPrompt","onboarding_completed":false,"preferences":{"default_reminder_enabled":true,"default_reminder_days_before":[7,3,1,0],"quiet_hours_enabled":true,"quiet_hours_start":"21:00","quiet_hours_end":"08:00","timezone":"Europe/London","preferred_channels":["push","email"]}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"ONBOARDING_INVALID_PAYLOAD","message":"Please check your onboarding preferences and try again."}}}}},"409":{"description":"Out of order","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"ONBOARDING_STEP_OUT_OF_ORDER","message":"Please complete your storage preference first."}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReminderPreferencesRequest"},"example":{"default_reminder_enabled":true,"default_reminder_days_before":[7,3,1,0],"quiet_hours_enabled":true,"quiet_hours_start":"21:00","quiet_hours_end":"08:00","timezone":"Europe/London","preferred_channels":["push","email"]}}}},"security":[{"bearerAuth":[]}]}},"/api/onboarding/notification-permission":{"patch":{"operationId":"patchapi_onboarding_notification_permission","summary":"Save notification permission result and device token","tags":["Onboarding"],"parameters":[],"responses":{"200":{"description":"Notification preference saved","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user_id":"usr_123","current_step":"completed","next_screen":"Home","onboarding_completed":true,"notification":{"permission_status":"granted","platform":"ios","device_registered":true}},"message":"Notification preference saved successfully.","user_id":"usr_123","current_step":"completed","next_screen":"Home","onboarding_completed":true,"notification":{"permission_status":"granted","platform":"ios","device_registered":true}}}}},"400":{"description":"Invalid notification permission payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"invalidPayload":{"summary":"Unsupported permission status or platform","value":{"success":false,"error":{"code":"ONBOARDING_INVALID_PAYLOAD","message":"Please check your onboarding preferences and try again."}}},"tokenRequired":{"summary":"Granted permission without device token","value":{"success":false,"error":{"code":"ONBOARDING_NOTIFICATION_TOKEN_REQUIRED","message":"device_token is required when notification permission is granted."}}}}}}},"409":{"description":"Out of order","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"ONBOARDING_STEP_OUT_OF_ORDER","message":"Please complete your reminder preferences first."}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPermissionRequest"},"examples":{"grantedIos":{"summary":"Permission granted on iOS","value":{"permission_status":"granted","platform":"ios","device_token":"apns_or_fcm_device_token_here","provider":"sns","device_id":"device_abc123"}},"deniedAndroid":{"summary":"Permission denied on Android","value":{"permission_status":"denied","platform":"android","device_id":"device_abc123"}},"decideLater":{"summary":"User skipped permission prompt","value":{"permission_status":"not_requested","platform":"android","device_id":"device_abc123"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/onboarding/complete":{"patch":{"operationId":"patchapi_onboarding_complete","summary":"Explicitly mark onboarding complete after all steps","tags":["Onboarding"],"parameters":[],"responses":{"200":{"description":"Onboarding completed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{"user_id":"usr_123","onboarding_completed":true,"current_step":"completed","next_screen":"Home"},"message":"Onboarding completed successfully.","user_id":"usr_123","onboarding_completed":true,"current_step":"completed","next_screen":"Home"}}}},"409":{"description":"Out of order","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"ONBOARDING_STEP_OUT_OF_ORDER","message":"Please complete all onboarding steps first."}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"completed":{"type":"boolean","example":true}},"required":["completed"]},"example":{"completed":true}}}},"security":[{"bearerAuth":[]}]}},"/auth/bootstrap":{"post":{"operationId":"postauth_bootstrap","summary":"POST /auth/bootstrap","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","example":"jordan@example.com"},"name":{"type":"string","example":"Jordan Smith"},"deviceId":{"type":"string","example":"ios-simulator-001"}}},"example":{"email":"jordan@example.com","name":"Jordan Smith","deviceId":"ios-simulator-001"}}}}}},"/auth/register":{"post":{"operationId":"postauth_register","summary":"POST /auth/register","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Jordan Smith"},"email":{"type":"string","example":"jordan@example.com"},"password":{"type":"string","example":"Str0ngPass123"},"confirmPassword":{"type":"string","example":"Str0ngPass123"}}},"example":{"name":"Jordan Smith","email":"jordan@example.com","password":"Str0ngPass123","confirmPassword":"Str0ngPass123"}}}}}},"/auth/login":{"post":{"operationId":"postauth_login","summary":"POST /auth/login","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","example":"jordan@example.com"},"password":{"type":"string","example":"Str0ngPass123"},"deviceId":{"type":"string","example":"ios-simulator-001"}}},"example":{"email":"jordan@example.com","password":"Str0ngPass123","deviceId":"ios-simulator-001"}}}}}},"/auth/refresh":{"post":{"operationId":"postauth_refresh","summary":"POST /auth/refresh","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","example":"refresh-token-from-response"}},"required":["refreshToken"]},"example":{"refreshToken":"refresh-token-from-response"}}}}}},"/auth/logout":{"post":{"operationId":"postauth_logout","summary":"POST /auth/logout","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string","example":"refresh-token-from-response"}}},"example":{"refreshToken":"refresh-token-from-response"}}}},"security":[{"bearerAuth":[]}]}},"/auth/me":{"get":{"operationId":"getauth_me","summary":"GET /auth/me","tags":["Auth"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/dashboard":{"get":{"operationId":"getapi_dashboard","summary":"Get home dashboard summary and empty-state decision","tags":["dashboard"],"parameters":[],"responses":{"200":{"description":"Dashboard summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSummaryResponse"},"examples":{"withDocuments":{"summary":"Show HomeDashboard","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}},"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}}},"emptyState":{"summary":"Show HomeEmptyState","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}},"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns counts, latest files, next reminders, Needs Attention items, Due This Week items, Renewals, and the Home screen the mobile app should render after onboarding is complete.","security":[{"bearerAuth":[]}]}},"/api/dashboard/summary":{"get":{"operationId":"getapi_dashboard_summary","summary":"Get home dashboard summary and empty-state decision","tags":["dashboard"],"parameters":[],"responses":{"200":{"description":"Dashboard summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSummaryResponse"},"examples":{"withDocuments":{"summary":"Show HomeDashboard","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}},"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}}},"emptyState":{"summary":"Show HomeEmptyState","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}},"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns counts, latest files, next reminders, Needs Attention items, Due This Week items, Renewals, and the Home screen the mobile app should render after onboarding is complete.","security":[{"bearerAuth":[]}]}},"/dashboard/summary":{"get":{"operationId":"getdashboard_summary","summary":"Get home dashboard summary and empty-state decision","tags":["dashboard"],"parameters":[],"responses":{"200":{"description":"Dashboard summary","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardSummaryResponse"},"examples":{"withDocuments":{"summary":"Show HomeDashboard","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}},"user_id":"usr_123","home_screen":"HomeDashboard","has_documents":true,"empty_state":{"show":false,"screen":"HomeEmptyState","reason":""},"summary":{"files":{"active":3,"archived":1,"total":4,"byCategory":{"bill":2,"insurance":1}},"reminders":{"overdue":0,"urgent":1,"upcoming":2,"completed":4,"total":7},"latestFiles":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"nextReminders":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}],"needsAttention":[{"id":"file_123","fileId":"file_123","name":"Council Tax Bill","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","amount":"145.30","dueDate":"2026-05-31","org":"Bristol Council","sender":"Bristol Council","note":"Pay before month end","category":"bill","urgency":"urgent","status":"active","sourceType":"upload","actionRequired":true,"actionReason":"Detected an amount and due date."}],"needsAttentionCount":1,"urgent":1,"dueThisWeek":1,"renewals":1}}},"emptyState":{"summary":"Show HomeEmptyState","value":{"ok":true,"success":true,"data":{"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}},"user_id":"usr_123","home_screen":"HomeEmptyState","has_documents":false,"empty_state":{"show":true,"screen":"HomeEmptyState","reason":"no_active_documents"},"summary":{"files":{"active":0,"archived":0,"total":0,"byCategory":{}},"reminders":{"overdue":0,"urgent":0,"upcoming":0,"completed":0,"total":0},"latestFiles":[],"nextReminders":[],"needsAttention":[],"needsAttentionCount":0,"urgent":0,"dueThisWeek":0,"renewals":0}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Backward-compatible non-/api dashboard route. Mobile clients should use /api/dashboard/summary. Returns counts, latest files, next reminders, Needs Attention items, Due This Week items, and Renewals.","security":[{"bearerAuth":[]}]}},"/api/files":{"get":{"operationId":"getapi_files","summary":"List user files for Home dashboard and file views","tags":["files"],"parameters":[{"name":"folderId","in":"query","required":false,"schema":{"type":"string"},"example":"inbox"},{"name":"tab","in":"query","required":false,"schema":{"type":"string","enum":["all","allFolders","urgent","recent","favorites","upcoming"]},"example":"urgent"},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["all","urgent","recent","favorites","upcoming"]},"description":"Alias for tab.","example":"favorites"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"example":"council"},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["active","archived","deleted"]},"example":"active"}],"responses":{"200":{"description":"Files","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"items":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"tab":"all","folderId":"inbox","counts":{"all":12,"allFolders":12,"urgent":2,"upcoming":5,"recent":12,"favorites":3}},"items":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"tab":"all","folderId":"inbox","counts":{"all":12,"allFolders":12,"urgent":2,"upcoming":5,"recent":12,"favorites":3}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Lists files for the Files screen and FolderDetail screen. Use tab=view filters to power mobile headers: all/allFolders, urgent, recent, favorites, and upcoming. Use folderId with tab to filter inside a selected folder.","security":[{"bearerAuth":[]}]}},"/files":{"get":{"operationId":"getfiles","summary":"GET /files","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/files/items":{"post":{"operationId":"postapi_files_items","summary":"Create a manual tracked item","tags":["files"],"parameters":[],"responses":{"200":{"description":"Manual item created","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Payment","sender":"Bristol Council","category":"bill","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","folderId":"council-tax","status":"active","archived":false,"sourceType":"manual"}},"file":{"id":"file_123","title":"Council Tax Payment","sender":"Bristol Council","category":"bill","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","folderId":"council-tax","status":"active","archived":false,"sourceType":"manual"}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"Title is required"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Creates a document/tracked item from ManualAddScreen without requiring an uploaded file. Notes, reference number, urgency, amount, due date, and folder are persisted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManualItemRequest"},"example":{"title":"Council Tax Payment","category":"bill","sender":"Bristol Council","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","folderId":"council-tax","urgency":"urgent","notes":"Pay before month end","sourceType":"manual"}}}},"security":[{"bearerAuth":[]}]}},"/api/files/upload-init":{"post":{"operationId":"postapi_files_upload_init","summary":"Create a presigned upload URL for scanned or selected documents","tags":["files"],"parameters":[],"responses":{"200":{"description":"Upload initialized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadInitResponse"},"examples":{"minimalScanOrUpload":{"summary":"Local storage: temporary extraction upload initialized","value":{"ok":true,"success":true,"data":{"upload":{"id":"upload_456","uploadUrl":"https://s3-presigned-upload-url","objectKey":"temporary-extraction/users/usr_123/upload_456/IMG_2041.jpg","bucket":"scrinassist-dev-cloud-storage","contentType":"image/jpeg","maxUploadBytes":10485760,"plan":"free","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true},"file":{"id":"file_456","title":"IMG_2041.jpg","sender":"","category":"other","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true}},"upload":{"id":"upload_456","uploadUrl":"https://s3-presigned-upload-url","objectKey":"temporary-extraction/users/usr_123/upload_456/IMG_2041.jpg","bucket":"scrinassist-dev-cloud-storage","contentType":"image/jpeg","maxUploadBytes":10485760,"plan":"free","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true},"file":{"id":"file_456","title":"IMG_2041.jpg","sender":"","category":"other","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"local","documentDestination":"device_only","uploadPurpose":"temporary_extraction","temporary":true,"deleteAfterExtraction":true}}},"withOptionalHints":{"summary":"Cloud storage: permanent document upload initialized","value":{"ok":true,"success":true,"data":{"upload":{"id":"upload_123","uploadUrl":"https://s3-presigned-upload-url","objectKey":"cloud-storage/users/usr_123/documents/upload_123/council-tax.pdf","bucket":"scrinassist-dev-cloud-storage","contentType":"application/pdf","maxUploadBytes":10485760,"plan":"free","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false},"file":{"id":"file_123","title":"Council Tax Bill","sender":"","category":"bill","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false}},"upload":{"id":"upload_123","uploadUrl":"https://s3-presigned-upload-url","objectKey":"cloud-storage/users/usr_123/documents/upload_123/council-tax.pdf","bucket":"scrinassist-dev-cloud-storage","contentType":"application/pdf","maxUploadBytes":10485760,"plan":"free","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false},"file":{"id":"file_123","title":"Council Tax Bill","sender":"","category":"bill","amount":"","dueDate":"","folderId":"inbox","status":"active","sourceType":"upload","storageMode":"cloud","documentDestination":"scrinassist_cloud","uploadPurpose":"cloud_document","temporary":false,"deleteAfterExtraction":false}}}}}}},"413":{"description":"Plan upload limit exceeded","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"UPLOAD_PLAN_LIMIT_EXCEEDED","message":"Upload exceeds the 10 MB limit for your current plan."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Creates an upload record and tracked file stub. The backend reads the authenticated user's onboarding storage preference. Cloud users receive a permanent cloud document upload target. Local-storage users receive a temporary private extraction upload target; after /api/ai/extract runs OCR/AI, the backend deletes the temporary object and stores only extracted metadata.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadInitRequest"},"examples":{"minimalScanOrUpload":{"summary":"Minimal scan/upload request","value":{"fileName":"IMG_2041.jpg","contentType":"image/jpeg","fileSize":348912}},"withOptionalHints":{"summary":"Upload with optional title/category/folder hints","value":{"fileName":"council-tax.pdf","contentType":"application/pdf","fileSize":502144,"title":"Council Tax Bill","category":"bill","folderId":"inbox"}}}}}},"security":[{"bearerAuth":[]}]}},"/files/items":{"post":{"operationId":"postfiles_items","summary":"POST /files/items","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Council Tax Bill"},"category":{"type":"string","example":"bill"},"sender":{"type":"string","example":"Bristol Council"},"amount":{"type":"string","example":"\u00a3145.30"},"dueDate":{"type":"string","example":"2026-05-31"},"folderId":{"type":"string","example":"inbox"}},"required":["title"]},"example":{"title":"Council Tax Bill","category":"bill","sender":"Bristol Council","amount":"\u00a3145.30","dueDate":"2026-05-31","folderId":"inbox"}}}},"security":[{"bearerAuth":[]}]}},"/files/upload-init":{"post":{"operationId":"postfiles_upload_init","summary":"POST /files/upload-init","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","example":"council-tax.pdf"},"contentType":{"type":"string","example":"application/pdf"},"fileSize":{"type":"integer","example":502144},"title":{"type":"string","example":"Council Tax Bill"},"category":{"type":"string","example":"bill"},"folderId":{"type":"string","example":"inbox"}},"required":["fileName","contentType","fileSize"]},"example":{"fileName":"council-tax.pdf","contentType":"application/pdf","fileSize":502144,"title":"Council Tax Bill","category":"bill","folderId":"inbox"}}}},"security":[{"bearerAuth":[]}]}},"/files/uploads/init":{"post":{"operationId":"postfiles_uploads_init","summary":"POST /files/uploads/init","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","example":"council-tax.pdf"},"contentType":{"type":"string","example":"application/pdf"},"fileSize":{"type":"integer","example":502144},"title":{"type":"string","example":"Council Tax Bill"},"category":{"type":"string","example":"bill"},"folderId":{"type":"string","example":"inbox"}},"required":["fileName","contentType","fileSize"]},"example":{"fileName":"council-tax.pdf","contentType":"application/pdf","fileSize":502144,"title":"Council Tax Bill","category":"bill","folderId":"inbox"}}}},"security":[{"bearerAuth":[]}]}},"/uploads/init":{"post":{"operationId":"postuploads_init","summary":"POST /uploads/init","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileName":{"type":"string","example":"council-tax.pdf"},"contentType":{"type":"string","example":"application/pdf"},"fileSize":{"type":"integer","example":502144},"title":{"type":"string","example":"Council Tax Bill"},"category":{"type":"string","example":"bill"},"folderId":{"type":"string","example":"inbox"}},"required":["fileName","contentType","fileSize"]},"example":{"fileName":"council-tax.pdf","contentType":"application/pdf","fileSize":502144,"title":"Council Tax Bill","category":"bill","folderId":"inbox"}}}},"security":[{"bearerAuth":[]}]}},"/api/files/categories":{"get":{"operationId":"getapi_files_categories","summary":"List canonical document categories","tags":["files"],"parameters":[],"responses":{"200":{"description":"Categories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoriesListResponse"},"examples":{"categories":{"summary":"Canonical document categories","value":{"ok":true,"success":true,"data":{"items":[{"id":"bill","label":"Bills & Payments","description":"Payment requests, invoices, council tax bills, utility bills, and other amounts due."},{"id":"notice","label":"Notices","description":"Letters or notices that need review, response, or acknowledgement."},{"id":"renewal","label":"Renewals","description":"Policies, subscriptions, contracts, or services that need renewal."},{"id":"medical","label":"Medical","description":"Health, appointment, prescription, and medical admin documents."},{"id":"tax","label":"Tax","description":"Tax documents, tax deadlines, assessments, and HMRC-style letters."},{"id":"insurance","label":"Insurance","description":"Insurance policies, claims, quotes, renewals, and coverage documents."},{"id":"utilities","label":"Utilities","description":"Energy, water, broadband, phone, and service provider documents."},{"id":"legal","label":"Legal","description":"Legal notices, contracts, claims, agreements, and solicitor letters."},{"id":"banking","label":"Banking","description":"Bank, card, loan, mortgage, and financial account documents."},{"id":"subscription","label":"Subscriptions","description":"Recurring subscriptions, memberships, and paid service notices."},{"id":"housing","label":"Housing","description":"Rent, tenancy, property, mortgage, council, and housing documents."},{"id":"education","label":"Education","description":"School, university, training, fees, and education admin documents."},{"id":"vehicle","label":"Vehicle","description":"Car, MOT, road tax, parking, insurance, finance, and vehicle documents."},{"id":"government","label":"Government","description":"Government, council, benefits, identity, immigration, and public-service documents."},{"id":"other","label":"Other","description":"Fallback category when no specific category applies."}],"default":"other","ids":["bill","notice","renewal","medical","tax","insurance","utilities","legal","banking","subscription","housing","education","vehicle","government","other"]},"items":[{"id":"bill","label":"Bills & Payments","description":"Payment requests, invoices, council tax bills, utility bills, and other amounts due."},{"id":"notice","label":"Notices","description":"Letters or notices that need review, response, or acknowledgement."},{"id":"renewal","label":"Renewals","description":"Policies, subscriptions, contracts, or services that need renewal."},{"id":"medical","label":"Medical","description":"Health, appointment, prescription, and medical admin documents."},{"id":"tax","label":"Tax","description":"Tax documents, tax deadlines, assessments, and HMRC-style letters."},{"id":"insurance","label":"Insurance","description":"Insurance policies, claims, quotes, renewals, and coverage documents."},{"id":"utilities","label":"Utilities","description":"Energy, water, broadband, phone, and service provider documents."},{"id":"legal","label":"Legal","description":"Legal notices, contracts, claims, agreements, and solicitor letters."},{"id":"banking","label":"Banking","description":"Bank, card, loan, mortgage, and financial account documents."},{"id":"subscription","label":"Subscriptions","description":"Recurring subscriptions, memberships, and paid service notices."},{"id":"housing","label":"Housing","description":"Rent, tenancy, property, mortgage, council, and housing documents."},{"id":"education","label":"Education","description":"School, university, training, fees, and education admin documents."},{"id":"vehicle","label":"Vehicle","description":"Car, MOT, road tax, parking, insurance, finance, and vehicle documents."},{"id":"government","label":"Government","description":"Government, council, benefits, identity, immigration, and public-service documents."},{"id":"other","label":"Other","description":"Fallback category when no specific category applies."}],"default":"other","ids":["bill","notice","renewal","medical","tax","insurance","utilities","legal","banking","subscription","housing","education","vehicle","government","other"]}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns the backend-owned category vocabulary. Mobile should call this to keep category IDs, labels, and fallback behavior aligned with AI extraction, manual add, file update, search, dashboard grouping, and folder suggestions.","security":[{"bearerAuth":[]}]}},"/files/categories":{"get":{"operationId":"getfiles_categories","summary":"GET /files/categories","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/files/folders":{"get":{"operationId":"getapi_files_folders","summary":"List folders for the authenticated user","tags":["files"],"parameters":[{"name":"tab","in":"query","required":false,"schema":{"type":"string","enum":["allFolders","all","urgent","recent","favorites","upcoming"]},"example":"urgent"},{"name":"view","in":"query","required":false,"schema":{"type":"string","enum":["allFolders","all","urgent","recent","favorites","upcoming"]},"description":"Alias for tab.","example":"favorites"},{"name":"previewLimit","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":20},"description":"Maximum files returned per folder group in filesPreview/files.","example":5}],"responses":{"200":{"description":"Folders","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"items":[{"id":"inbox","name":"Inbox","color":"#4A9EFF","parentFolderId":"","fileCount":2,"activeFileCount":2,"archivedFileCount":0,"matchingFileCount":1,"hasMoreFiles":false,"filesPreview":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"files":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}]},{"id":"utilities","name":"Utilities","color":"#34C759","parentFolderId":"","fileCount":3,"activeFileCount":2,"archivedFileCount":1,"matchingFileCount":1,"hasMoreFiles":false,"filesPreview":[{"id":"file_456","title":"Energy Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"utilities","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000}],"files":[{"id":"file_456","title":"Energy Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"utilities","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000}]}],"tab":"allFolders","previewLimit":5,"counts":{"all":12,"allFolders":12,"urgent":2,"upcoming":5,"recent":12,"favorites":3}},"items":[{"id":"inbox","name":"Inbox","color":"#4A9EFF","parentFolderId":"","fileCount":2,"activeFileCount":2,"archivedFileCount":0,"matchingFileCount":1,"hasMoreFiles":false,"filesPreview":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}],"files":[{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000}]},{"id":"utilities","name":"Utilities","color":"#34C759","parentFolderId":"","fileCount":3,"activeFileCount":2,"archivedFileCount":1,"matchingFileCount":1,"hasMoreFiles":false,"filesPreview":[{"id":"file_456","title":"Energy Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"utilities","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000}],"files":[{"id":"file_456","title":"Energy Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"utilities","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000}]}],"tab":"allFolders","previewLimit":5,"counts":{"all":12,"allFolders":12,"urgent":2,"upcoming":5,"recent":12,"favorites":3}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns user-created folders plus the virtual Inbox folder using one folder-group shape for all file-screen tabs. Use tab=allFolders, urgent, recent, favorites, or upcoming to keep the same response structure while changing the filesPreview/files inside each folder group.","security":[{"bearerAuth":[]}]},"post":{"operationId":"postapi_files_folders","summary":"Create a folder","tags":["files"],"parameters":[],"responses":{"200":{"description":"Folder created","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"folder":{"id":"folder_123","name":"Council Tax","color":"#4A9EFF","parentFolderId":"utilities","fileCount":0,"activeFileCount":0,"archivedFileCount":0}},"folder":{"id":"folder_123","name":"Council Tax","color":"#4A9EFF","parentFolderId":"utilities","fileCount":0,"activeFileCount":0,"archivedFileCount":0}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"Folder name is required"}}}}},"404":{"description":"Parent folder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Parent folder not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Creates a user folder. parentFolderId is optional; when supplied it must be an existing folder or inbox.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFolderRequest"},"example":{"name":"Council Tax","color":"#4A9EFF","parentFolderId":"utilities"}}}},"security":[{"bearerAuth":[]}]}},"/api/files/{file_id}":{"get":{"operationId":"getapi_files_file_id","summary":"Get file details","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"File","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns one file or tracked item owned by the authenticated user, including aiSummary for the file detail AI summary section, reminders for the reminders section, and activityHistory for the activity timeline.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_files_file_id","summary":"Update file metadata","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"File updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates editable file fields from FileDetail/EditFileInfo. The file must exist and belong to the authenticated user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFileRequest"},"example":{"title":"Council Tax Payment 2026","sender":"Local Council","category":"bill","amount":"247.80","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","urgency":"urgent","notes":"Pay before month end","favorite":true}}}},"security":[{"bearerAuth":[]}]},"delete":{"operationId":"deleteapi_files_file_id","summary":"Delete file","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"File deleted","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Soft-deletes a file by marking it deleted and archived. The record is retained for audit and recovery workflows.","security":[{"bearerAuth":[]}]}},"/api/files/{file_id}/move":{"post":{"operationId":"postapi_files_file_id_move","summary":"Move file to folder","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"File moved","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"folderId is required"}}}}},"404":{"description":"File or destination folder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File or destination folder not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Moves a file to an existing folder or the virtual inbox folder.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MoveFileRequest"},"example":{"folderId":"utilities"}}}},"security":[{"bearerAuth":[]}]}},"/api/files/{file_id}/archive":{"post":{"operationId":"postapi_files_file_id_archive","summary":"Archive file","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"File archived","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Marks a file as archived so it no longer appears in active file lists unless status=archived is requested.","security":[{"bearerAuth":[]}]}},"/api/files/{file_id}/extracted-details":{"post":{"operationId":"postapi_files_file_id_extracted_details","summary":"Save extracted file details","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"Extracted details saved","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Bristol Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"inbox","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Pay before month end","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"details must be an object"}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Persists AI or user-reviewed extracted details against an existing file.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveExtractedDetailsRequest"},"example":{"details":{"referenceNumber":"CT-2026-001","amount":"145.30","dueDate":"2026-05-31","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]}}}}},"security":[{"bearerAuth":[]}]}},"/api/files/{file_id}/finalize":{"post":{"operationId":"postapi_files_file_id_finalize","summary":"Finalize reviewed upload details and selected folder","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"Reviewed upload finalized","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Reviewed document details saved successfully.","data":{"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Council tax payment is due by 31 May 2026.","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]},"nextScreen":"SaveSuccess"},"file":{"id":"file_123","title":"Council Tax Bill","description":"Council tax bill requiring payment by 2026-05-31.","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","folderId":"utilities","status":"active","sourceType":"upload","updatedAt":1770000000,"referenceNumber":"CT-2026-001","notes":"Council tax payment is due by 31 May 2026.","urgency":"urgent","favorite":true,"isFavorite":true,"archived":false,"createdAt":1770000000,"extractedDetails":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"aiSummary":{"summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1],"confidence":0.87,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano","extractedAt":1770000050},"reminders":{"items":[{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}],"count":1,"activeCount":1,"nextReminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Bill due","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push","email"],"status":"upcoming","done":false,"createdAt":1770000060,"updatedAt":1770000060}},"activityHistory":[{"id":"file_123:ai_extracted","type":"ai_extracted","title":"AI extraction completed","description":"ScrinAssist extracted key details and action information.","createdAt":1770000050},{"id":"reminder_123:created","type":"reminder_created","title":"Council Tax Bill due","description":"Reminder scheduled for 2026-05-24.","createdAt":1770000060}]},"nextScreen":"SaveSuccess"}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"missingFolder":{"summary":"Missing folder","value":{"success":false,"error":{"code":"validation_error","message":"folderId is required"}}},"badDetails":{"summary":"Bad details","value":{"success":false,"error":{"code":"validation_error","message":"details must be an object"}}}}}}},"404":{"description":"File or folder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File or destination folder not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Single mobile Save endpoint after AI extraction review and folder selection. It validates the file and destination folder, stores the edited extracted details, updates top-level file metadata, moves the file to the selected folder, and returns nextScreen=SaveSuccess.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FinalizeReviewedUploadRequest"},"example":{"folderId":"utilities","details":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","summary":"Council tax payment is due by 31 May 2026.","actionRequired":true,"actionType":"payment_due","actionReason":"Detected amount and due date.","notificationTitle":"Council Tax Bill needs attention","notificationBody":"Council Tax Bill is due on 2026-05-31.","recommendedReminders":[7,3,1]},"file":{"title":"Council Tax Bill","sender":"Manchester City Council","category":"bill","amount":"145.30","dueDate":"2026-05-31","referenceNumber":"CT-2026-001","notes":"Council tax payment is due by 31 May 2026."}}}}},"security":[{"bearerAuth":[]}]}},"/files/folders":{"get":{"operationId":"getfiles_folders","summary":"GET /files/folders","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"post":{"operationId":"postfiles_folders","summary":"POST /files/folders","tags":["files"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","example":"Bills"},"color":{"type":"string","example":"#4A9EFF"},"parentFolderId":{"type":"string","example":""}},"required":["name"]},"example":{"name":"Bills","color":"#4A9EFF","parentFolderId":""}}}},"security":[{"bearerAuth":[]}]}},"/files/{file_id}":{"get":{"operationId":"getfiles_file_id","summary":"GET /files/{file_id}","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchfiles_file_id","summary":"PATCH /files/{file_id}","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Updated Council Tax Bill"},"sender":{"type":"string","example":"Bristol Council"},"category":{"type":"string","example":"bill"},"amount":{"type":"string","example":"\u00a3145.30"},"dueDate":{"type":"string","example":"2026-05-31"},"notes":{"type":"string","example":"Pay before end of month"}}},"example":{"title":"Updated Council Tax Bill","sender":"Bristol Council","category":"bill","amount":"\u00a3145.30","dueDate":"2026-05-31","notes":"Pay before end of month"}}}},"security":[{"bearerAuth":[]}]},"delete":{"operationId":"deletefiles_file_id","summary":"DELETE /files/{file_id}","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/files/{file_id}/move":{"post":{"operationId":"postfiles_file_id_move","summary":"POST /files/{file_id}/move","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":"string","example":"folder-bills"}},"required":["folderId"]},"example":{"folderId":"folder-bills"}}}},"security":[{"bearerAuth":[]}]}},"/files/{file_id}/archive":{"post":{"operationId":"postfiles_file_id_archive","summary":"POST /files/{file_id}/archive","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/files/{file_id}/extracted-details":{"post":{"operationId":"postfiles_file_id_extracted_details","summary":"POST /files/{file_id}/extracted-details","tags":["files"],"parameters":[{"name":"file_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-file-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"details":{"type":"object","example":{"referenceNumber":"CT-2026-001","amount":"\u00a3145.30","dueDate":"2026-05-31"}}},"required":["details"]},"example":{"details":{"referenceNumber":"CT-2026-001","amount":"\u00a3145.30","dueDate":"2026-05-31"}}}}},"security":[{"bearerAuth":[]}]}},"/api/reminders":{"get":{"operationId":"getapi_reminders","summary":"List user reminders","tags":["reminders"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["critical","urgent","upcoming","completed"]},"example":"upcoming"},{"name":"fileId","in":"query","required":false,"schema":{"type":"string"},"example":"file_123"},{"name":"q","in":"query","required":false,"schema":{"type":"string"},"example":"council"}],"responses":{"200":{"description":"Reminders","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"items":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}]},"items":[{"id":"rem_123","fileId":"file_123","title":"Pay council tax","description":"Council tax bill requiring payment by 2026-05-31.","status":"urgent","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"done":false}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Lists reminders for RemindersTimeline, RemindersListView, OverdueReminders, and Home dashboard widgets.","security":[{"bearerAuth":[]}]},"post":{"operationId":"postapi_reminders","summary":"Create a reminder for a manual or uploaded item","tags":["reminders"],"parameters":[],"responses":{"200":{"description":"Reminder created","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}},"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"missingTitle":{"summary":"Missing title","value":{"success":false,"error":{"code":"validation_error","message":"title is required"}}},"badDate":{"summary":"Bad date","value":{"success":false,"error":{"code":"validation_error","message":"reminderDate must be a valid YYYY-MM-DD date"}}},"badChannel":{"summary":"Bad channel","value":{"success":false,"error":{"code":"validation_error","message":"Unsupported reminder channel"}}},"phoneNotVerified":{"summary":"Phone not verified","value":{"success":false,"error":{"code":"CALL_PHONE_NOT_VERIFIED","message":"Verify your phone number before enabling call reminders."}}}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"File not found"}}}}},"403":{"description":"Call plan required","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"CALL_REMINDERS_PLAN_REQUIRED","message":"Call reminders are available on premium plans."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Creates a reminder. If push, email, or call is enabled and scheduler infrastructure is configured, an EventBridge Scheduler one-time schedule is created. Dispatch sends SNS push, SES email, and Amazon Connect calls based on the reminder channels and user notification preferences. If scheduler env vars are missing, scheduleState is pending_config.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReminderRequest"},"example":{"fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming"}}}},"security":[{"bearerAuth":[]}]}},"/reminders":{"get":{"operationId":"getreminders","summary":"GET /reminders","tags":["reminders"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"post":{"operationId":"postreminders","summary":"POST /reminders","tags":["reminders"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Pay council tax"},"fileId":{"type":"string","example":"file-123"},"dueDate":{"type":"string","example":"2026-05-31"},"reminderDate":{"type":"string","example":"2026-05-24"},"reminderTime":{"type":"string","example":"09:00"},"channels":{"type":"array","example":["push"]},"status":{"type":"string","example":"upcoming"}},"required":["title"]},"example":{"title":"Pay council tax","fileId":"file-123","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming"}}}},"security":[{"bearerAuth":[]}]}},"/api/reminders/{reminder_id}":{"get":{"operationId":"getapi_reminders_reminder_id","summary":"Get reminder details","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"Reminder","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}},"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}}}}},"404":{"description":"Reminder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Reminder not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns a single reminder owned by the authenticated user for ReminderDetail.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_reminders_reminder_id","summary":"Update reminder schedule, channels, or done state","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"Reminder updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}},"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"badTime":{"summary":"Bad time","value":{"success":false,"error":{"code":"validation_error","message":"reminderTime must be in HH:MM format"}}},"badStatus":{"summary":"Bad status","value":{"success":false,"error":{"code":"validation_error","message":"Unsupported reminder status"}}},"phoneNotVerified":{"summary":"Phone not verified","value":{"success":false,"error":{"code":"CALL_PHONE_NOT_VERIFIED","message":"Verify your phone number before enabling call reminders."}}}}}}},"404":{"description":"Reminder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Reminder not found"}}}}},"403":{"description":"Call plan required","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"CALL_REMINDERS_PLAN_REQUIRED","message":"Call reminders are available on premium plans."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates reminder fields from EditReminderSchedule, ReminderChannelSelection, CustomReminderEdit, or mark-done actions. Scheduler state is recalculated after every update for enabled push/email/call channels.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReminderRequest"},"examples":{"scheduleUpdate":{"summary":"Edit reminder schedule","value":{"title":"Council Tax Payment","reminderDate":"2026-05-28","reminderTime":"10:00","channels":["push","email"],"status":"upcoming","done":false}},"markDone":{"summary":"Mark reminder done","value":{"done":true,"status":"completed"}}}}}},"security":[{"bearerAuth":[]}]},"delete":{"operationId":"deleteapi_reminders_reminder_id","summary":"Delete reminder","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"Reminder deleted","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}},"reminder":{"id":"reminder_123","fileId":"file_123","title":"Council Tax Payment","dueDate":"2026-05-31","reminderDate":"2026-05-24","reminderTime":"09:00","channels":["push"],"status":"upcoming","done":false,"scheduleState":"scheduled"}}}}},"404":{"description":"Reminder not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Reminder not found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Soft-deletes a reminder, disables its schedule metadata, and deletes the EventBridge Scheduler schedule when configured.","security":[{"bearerAuth":[]}]}},"/reminders/{reminder_id}":{"get":{"operationId":"getreminders_reminder_id","summary":"GET /reminders/{reminder_id}","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchreminders_reminder_id","summary":"PATCH /reminders/{reminder_id}","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"Pay council tax"},"reminderDate":{"type":"string","example":"2026-05-25"},"reminderTime":{"type":"string","example":"10:00"},"channels":{"type":"array","example":["push","email"]},"status":{"type":"string","example":"upcoming"},"done":{"type":"boolean","example":false}}},"example":{"title":"Pay council tax","reminderDate":"2026-05-25","reminderTime":"10:00","channels":["push","email"],"status":"upcoming","done":false}}}},"security":[{"bearerAuth":[]}]},"delete":{"operationId":"deletereminders_reminder_id","summary":"DELETE /reminders/{reminder_id}","tags":["reminders"],"parameters":[{"name":"reminder_id","in":"path","required":true,"schema":{"type":"string"},"example":"test-reminder-id"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/settings":{"get":{"operationId":"getsettings","summary":"Get general user settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns the authenticated user's general settings used by settings screens and mobile defaults.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchsettings","summary":"PATCH /settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"storageMode":{"type":"string","example":"sync"},"notificationChannels":{"type":"array","example":["push"]},"defaultReminderOffsets":{"type":"array","example":[7,1]},"timezone":{"type":"string","example":"Europe/London"},"language":{"type":"string","example":"en"},"theme":{"type":"string","example":"light"}}},"example":{"storageMode":"sync","notificationChannels":["push"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light"}}}},"security":[{"bearerAuth":[]}]}},"/api/settings":{"get":{"operationId":"getapi_settings","summary":"Get general user settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns the authenticated user's general settings used by settings screens and mobile defaults.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_settings","summary":"Update general user settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Settings updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Settings updated successfully.","data":{"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates general settings. Prefer /api/settings/storage and /api/settings/reminders for screen-specific settings writes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateRequest"},"example":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":true,"escalationDelayHours":24}}}},"security":[{"bearerAuth":[]}]}},"/api/settings/overview":{"get":{"operationId":"getapi_settings_overview","summary":"Get settings overview bootstrap payload","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Settings overview","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"plan":{"code":"free","status":"active","isPremium":false,"storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"callReminders":false,"smsReminders":false,"aiExtractionLimit":50},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24},"onboarding":{"onboarding_completed":true,"current_step":"completed","next_screen":"Home","steps":{"storage_preference":{"completed":true,"completed_at":"2026-05-01T10:00:00Z"},"reminder_preferences":{"completed":true,"completed_at":"2026-05-01T10:02:00Z"},"notification_permission":{"completed":true,"completed_at":"2026-05-01T10:03:00Z"}}}},"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"plan":{"code":"free","status":"active","isPremium":false,"storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"callReminders":false,"smsReminders":false,"aiExtractionLimit":50},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24},"onboarding":{"onboarding_completed":true,"current_step":"completed","next_screen":"Home","steps":{"storage_preference":{"completed":true,"completed_at":"2026-05-01T10:00:00Z"},"reminder_preferences":{"completed":true,"completed_at":"2026-05-01T10:02:00Z"},"notification_permission":{"completed":true,"completed_at":"2026-05-01T10:03:00Z"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Single-call payload for SettingsOverview. Includes account profile, plan, storage usage, general settings, and onboarding state.","security":[{"bearerAuth":[]}]}},"/api/settings/storage":{"get":{"operationId":"getapi_settings_storage","summary":"Get storage settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Storage settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns storage mode, document destination, cloud prefix information, usage count, and retention toggles for StorageSettings.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_settings_storage","summary":"Update storage settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Storage settings updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Storage settings updated successfully.","data":{"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"invalidMode":{"summary":"Invalid storage mode","value":{"success":false,"error":{"code":"validation_error","message":"storageMode must be local or cloud"}}},"unsupportedProvider":{"summary":"Unsupported third-party provider","value":{"success":false,"error":{"code":"STORAGE_PROVIDER_UNSUPPORTED","message":"This storage provider is not available yet."}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates post-onboarding storage preferences. Cloud mode creates/validates the user's S3 cloud-storage prefix. Local mode keeps future documents on the user's device and uses temporary extraction uploads only.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageSettingsUpdateRequest"},"examples":{"cloud":{"summary":"Enable ScrinAssist cloud storage","value":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true}},"local":{"summary":"Use local device storage","value":{"storageMode":"local","documentDestination":"device_only","syncEnabled":false,"deleteAfterUpload":false,"autoExportMonthly":false}}}}}},"security":[{"bearerAuth":[]}]}},"/api/settings/reminders":{"get":{"operationId":"getapi_settings_reminders","summary":"Get reminder settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Reminder settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}},"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns default reminder offsets, channels, quiet hours, escalation settings, and plan gating for ReminderSettings.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_settings_reminders","summary":"Update reminder settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Reminder settings updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Reminder settings updated successfully.","data":{"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}},"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"badOffsets":{"summary":"Bad offsets","value":{"success":false,"error":{"code":"validation_error","message":"defaultReminderOffsets must contain non-negative integers"}}},"smsUnsupported":{"summary":"SMS unsupported","value":{"success":false,"error":{"code":"validation_error","message":"SMS reminders are not available yet. Use call for premium phone reminders."}}},"badTimezone":{"summary":"Bad timezone","value":{"success":false,"error":{"code":"validation_error","message":"timezone must be a valid IANA timezone"}}}}}}},"403":{"description":"Call plan required","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"CALL_REMINDERS_PLAN_REQUIRED","message":"Call reminders are available on premium plans."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates default reminder preferences outside onboarding. Offsets allow 0 for due-date reminders. Channels support push, email, and premium call; SMS is documented as unsupported until an SMS provider is implemented.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReminderSettingsUpdateRequest"},"example":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultChannels":["push","email"],"timezone":"Europe/London","quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","escalationEnabled":true,"escalationDelayHours":24}}}},"security":[{"bearerAuth":[]}]}},"/settings/overview":{"get":{"operationId":"getsettings_overview","summary":"Get settings overview bootstrap payload","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Settings overview","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"plan":{"code":"free","status":"active","isPremium":false,"storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"callReminders":false,"smsReminders":false,"aiExtractionLimit":50},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24},"onboarding":{"onboarding_completed":true,"current_step":"completed","next_screen":"Home","steps":{"storage_preference":{"completed":true,"completed_at":"2026-05-01T10:00:00Z"},"reminder_preferences":{"completed":true,"completed_at":"2026-05-01T10:02:00Z"},"notification_permission":{"completed":true,"completed_at":"2026-05-01T10:03:00Z"}}}},"user":{"id":"usr_123","user_id":"usr_123","email":"jordan@example.com","emailVerified":true,"email_verified":true,"name":"Jordan Smith","status":"active","authMethod":"email","auth_method":"email","plan":"free","planCode":"free","plan_code":"free","profilePhotoUrl":""},"plan":{"code":"free","status":"active","isPremium":false,"storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"callReminders":false,"smsReminders":false,"aiExtractionLimit":50},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false},"settings":{"storageMode":"local","notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en","theme":"light","escalationEnabled":false,"escalationDelayHours":24},"onboarding":{"onboarding_completed":true,"current_step":"completed","next_screen":"Home","steps":{"storage_preference":{"completed":true,"completed_at":"2026-05-01T10:00:00Z"},"reminder_preferences":{"completed":true,"completed_at":"2026-05-01T10:02:00Z"},"notification_permission":{"completed":true,"completed_at":"2026-05-01T10:03:00Z"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Single-call payload for SettingsOverview. Includes account profile, plan, storage usage, general settings, and onboarding state.","security":[{"bearerAuth":[]}]}},"/settings/storage":{"get":{"operationId":"getsettings_storage","summary":"Get storage settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Storage settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns storage mode, document destination, cloud prefix information, usage count, and retention toggles for StorageSettings.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchsettings_storage","summary":"Update storage settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Storage settings updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Storage settings updated successfully.","data":{"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}},"storage":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true,"storageUsed":23,"storageLimit":50,"usageUnit":"documents","cloudStorage":{"bucket":"scrinassist-dev-main-abc12345","prefix":"cloud-storage/users/usr_123/documents/","documentsPrefix":"cloud-storage/users/usr_123/documents/"},"uploadPurposeForNewFiles":"cloud_document","localModeKeepsDocumentsOnDevice":false}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"invalidMode":{"summary":"Invalid storage mode","value":{"success":false,"error":{"code":"validation_error","message":"storageMode must be local or cloud"}}},"unsupportedProvider":{"summary":"Unsupported third-party provider","value":{"success":false,"error":{"code":"STORAGE_PROVIDER_UNSUPPORTED","message":"This storage provider is not available yet."}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates post-onboarding storage preferences. Cloud mode creates/validates the user's S3 cloud-storage prefix. Local mode keeps future documents on the user's device and uses temporary extraction uploads only.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorageSettingsUpdateRequest"},"examples":{"cloud":{"summary":"Enable ScrinAssist cloud storage","value":{"storageMode":"cloud","documentDestination":"scrinassist_cloud","syncEnabled":true,"deleteAfterUpload":false,"autoExportMonthly":true}},"local":{"summary":"Use local device storage","value":{"storageMode":"local","documentDestination":"device_only","syncEnabled":false,"deleteAfterUpload":false,"autoExportMonthly":false}}}}}},"security":[{"bearerAuth":[]}]}},"/settings/reminders":{"get":{"operationId":"getsettings_reminders","summary":"Get reminder settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Reminder settings","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}},"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns default reminder offsets, channels, quiet hours, escalation settings, and plan gating for ReminderSettings.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchsettings_reminders","summary":"Update reminder settings","tags":["User Preferences"],"parameters":[],"responses":{"200":{"description":"Reminder settings updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"message":"Reminder settings updated successfully.","data":{"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}},"reminders":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultTimingDays":7,"quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","timezone":"Europe/London","defaultChannels":["push","email"],"escalationEnabled":true,"escalationDelayHours":24,"supportedChannels":["call","email","push"],"unsupportedChannels":["sms"]},"planAllows":{"push":true,"email":true,"call":false,"sms":false}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"badOffsets":{"summary":"Bad offsets","value":{"success":false,"error":{"code":"validation_error","message":"defaultReminderOffsets must contain non-negative integers"}}},"smsUnsupported":{"summary":"SMS unsupported","value":{"success":false,"error":{"code":"validation_error","message":"SMS reminders are not available yet. Use call for premium phone reminders."}}},"badTimezone":{"summary":"Bad timezone","value":{"success":false,"error":{"code":"validation_error","message":"timezone must be a valid IANA timezone"}}}}}}},"403":{"description":"Call plan required","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"CALL_REMINDERS_PLAN_REQUIRED","message":"Call reminders are available on premium plans."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates default reminder preferences outside onboarding. Offsets allow 0 for due-date reminders. Channels support push, email, and premium call; SMS is documented as unsupported until an SMS provider is implemented.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReminderSettingsUpdateRequest"},"example":{"defaultReminderEnabled":true,"defaultReminderOffsets":[7,1,0],"defaultChannels":["push","email"],"timezone":"Europe/London","quietHoursEnabled":true,"quietHoursStart":"21:00","quietHoursEnd":"08:00","escalationEnabled":true,"escalationDelayHours":24}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications":{"get":{"operationId":"getapi_notifications","summary":"Get notification preferences and registered devices","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Notification preferences","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"},"devices":[{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}]},"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"},"devices":[{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Alias of /api/notifications/preferences. Returns user notification channel defaults and all registered devices without exposing raw push tokens.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_notifications","summary":"Update notification preferences or device toggle","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Notification preferences updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"}},"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"Unsupported notification channel"}}}}},"404":{"description":"Device not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Device not found"}}}}},"503":{"description":"Push not configured","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"service_unavailable","message":"Push notifications are not configured for platform=ios"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Alias of /api/notifications/preferences. Updates notification channels and can enable or disable a registered device.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesUpdateRequest"},"examples":{"channels":{"summary":"Update channels","value":{"notificationChannels":["push","email"]}},"toggleDevice":{"summary":"Toggle device","value":{"deviceId":"device_abc123","notificationEnabled":false}}}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/preferences":{"get":{"operationId":"getapi_notifications_preferences","summary":"Get notification preferences and registered devices","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Notification preferences","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"},"devices":[{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}]},"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"},"devices":[{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}]}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns user notification channel defaults and all registered devices without exposing raw push tokens.","security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchapi_notifications_preferences","summary":"Update notification preferences or device toggle","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Notification preferences updated","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"}},"preferences":{"notificationChannels":["push","email"],"defaultReminderOffsets":[7,1],"timezone":"Europe/London","language":"en"}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"Unsupported notification channel"}}}}},"404":{"description":"Device not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"Device not found"}}}}},"503":{"description":"Push not configured","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"service_unavailable","message":"Push notifications are not configured for platform=ios"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Updates notification channels and can enable or disable a registered device.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPreferencesUpdateRequest"},"examples":{"channels":{"summary":"Update channels","value":{"notificationChannels":["push","email"]}},"toggleDevice":{"summary":"Toggle device","value":{"deviceId":"device_abc123","notificationEnabled":false}}}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/register-device":{"post":{"operationId":"postapi_notifications_register_device","summary":"Register or update a push notification device","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Device registered","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"device":{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}},"device":{"deviceId":"device_abc123","platform":"ios","pushTokenStored":true,"snsEndpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","snsTopicSubscriptionArn":"arn:aws:sns:eu-north-1:123456789012:scrinassist-dev-mobile-push:subscription-id","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true,"endpointStatus":"active","lastError":"","lastSeenAt":1770000000,"createdAt":1770000000,"updatedAt":1770000000}}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"examples":{"missingDevice":{"summary":"Missing device","value":{"success":false,"error":{"code":"validation_error","message":"deviceId is required"}}},"badPlatform":{"summary":"Unsupported platform","value":{"success":false,"error":{"code":"validation_error","message":"platform must be ios or android"}}},"missingToken":{"summary":"Token required","value":{"success":false,"error":{"code":"validation_error","message":"pushToken is required when notificationEnabled=true"}}}}}}},"503":{"description":"Push not configured","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"service_unavailable","message":"Push notifications are not configured for platform=ios"}}}}},"502":{"description":"SNS registration failed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"push_registration_failed","message":"Failed to register device endpoint"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Registers a mobile device token with SNS when push is enabled. Raw push tokens are accepted in the request but are never returned in responses.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterDeviceRequest"},"example":{"deviceId":"device_abc123","platform":"ios","pushToken":"apns_or_fcm_device_token_here","appVersion":"54.0.6","deviceName":"iPhone 15","notificationEnabled":true}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/unregister-device":{"post":{"operationId":"postapi_notifications_unregister_device","summary":"Unregister a push notification device","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Device unregistered","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"unregistered":true},"unregistered":true}}}},"400":{"description":"Invalid payload","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"deviceId is required"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Unsubscribes the SNS topic subscription, deletes the platform endpoint, and removes the device record when present.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnregisterDeviceRequest"},"example":{"deviceId":"device_abc123"}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/test":{"post":{"operationId":"postapi_notifications_test","summary":"Send a test push notification","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Test notification sent","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"sent":1,"failed":0,"results":{"successes":[{"deviceId":"device_abc123","endpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","messageId":"sns-message-id"}],"failures":[]}},"sent":1,"failed":0,"results":{"successes":[{"deviceId":"device_abc123","endpointArn":"arn:aws:sns:eu-north-1:123456789012:endpoint/APNS/app/device","messageId":"sns-message-id"}],"failures":[]}}}}},"404":{"description":"No active devices","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"not_found","message":"No active push-enabled devices found"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Publishes a test notification to one device or all active push-enabled devices for the authenticated user.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestNotificationRequest"},"example":{"deviceId":"device_abc123","title":"ScrinAssist Test Notification","body":"Push delivery is configured for this device.","reminderId":"reminder_123"}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/phone-verification/start":{"post":{"operationId":"postapi_notifications_phone_verification_start","summary":"Start phone verification by Amazon Connect call","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Phone verification call started","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"verificationId":"phone_verification_123","phoneNumber":"+447700900123","expiresAt":1770000600,"challengeCode":"123456","call":{"provider":"amazon_connect","status":"started","contactId":"connect-contact-id"}},"verificationId":"phone_verification_123","phoneNumber":"+447700900123","expiresAt":1770000600,"challengeCode":"123456","call":{"provider":"amazon_connect","status":"started","contactId":"connect-contact-id"}}}}},"400":{"description":"Invalid phone","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"validation_error","message":"phoneNumber must be a valid E.164 phone number"}}}}},"502":{"description":"Call failed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"PHONE_VERIFICATION_CALL_FAILED","message":"Failed to start phone verification call"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Creates a short-lived phone verification challenge and starts an Amazon Connect outbound call. The Connect contact flow should ask the user to enter the challengeCode shown in the mobile app, then invoke the notifications Lambda with internalAction=confirmPhoneVerification.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneVerificationStartRequest"},"example":{"phoneNumber":"+447700900123"}}}},"security":[{"bearerAuth":[]}]}},"/api/notifications/phone-verification/confirm":{"post":{"operationId":"postapi_notifications_phone_verification_confirm","summary":"Confirm phone verification code","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"Phone verified","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"phone":{"user_id":"usr_123","phoneNumber":"+447700900123","phoneVerified":true,"phoneVerifiedAt":1770000100,"verificationId":"phone_verification_123"}},"phone":{"user_id":"usr_123","phoneNumber":"+447700900123","phoneVerified":true,"phoneVerifiedAt":1770000100,"verificationId":"phone_verification_123"}}}}},"400":{"description":"Invalid code","content":{"application/json":{"schema":{"type":"object"},"examples":{"badCode":{"summary":"Invalid code","value":{"success":false,"error":{"code":"PHONE_INVALID_VERIFICATION_CODE","message":"Invalid phone verification code"}}},"expired":{"summary":"Expired code","value":{"success":false,"error":{"code":"PHONE_VERIFICATION_EXPIRED","message":"Phone verification code has expired"}}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Fallback/manual confirmation endpoint for the same code collected by Amazon Connect. On success the user's profile is marked phoneVerified=true.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneVerificationConfirmRequest"},"example":{"phoneNumber":"+447700900123","verificationId":"phone_verification_123","code":"123456"}}}},"security":[{"bearerAuth":[]}]}},"/notifications":{"get":{"operationId":"getnotifications","summary":"GET /notifications","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchnotifications","summary":"PATCH /notifications","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notificationChannels":{"type":"array","example":["push"]},"deviceId":{"type":"string","example":"ios-simulator-001"},"notificationEnabled":{"type":"boolean","example":true}}},"example":{"notificationChannels":["push"],"deviceId":"ios-simulator-001","notificationEnabled":true}}}},"security":[{"bearerAuth":[]}]}},"/notifications/preferences":{"get":{"operationId":"getnotifications_preferences","summary":"GET /notifications/preferences","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]},"patch":{"operationId":"patchnotifications_preferences","summary":"PATCH /notifications/preferences","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"notificationChannels":{"type":"array","example":["push"]},"deviceId":{"type":"string","example":"ios-simulator-001"},"notificationEnabled":{"type":"boolean","example":true}}},"example":{"notificationChannels":["push"],"deviceId":"ios-simulator-001","notificationEnabled":true}}}},"security":[{"bearerAuth":[]}]}},"/notifications/register-device":{"post":{"operationId":"postnotifications_register_device","summary":"POST /notifications/register-device","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","example":"ios-simulator-001"},"platform":{"type":"string","example":"ios"},"pushToken":{"type":"string","example":"ExponentPushToken[test]"},"appVersion":{"type":"string","example":"1.0.0"},"deviceName":{"type":"string","example":"iPhone 15"},"notificationEnabled":{"type":"boolean","example":true}},"required":["deviceId","platform"]},"example":{"deviceId":"ios-simulator-001","platform":"ios","pushToken":"ExponentPushToken[test]","appVersion":"1.0.0","deviceName":"iPhone 15","notificationEnabled":true}}}},"security":[{"bearerAuth":[]}]}},"/notifications/unregister-device":{"post":{"operationId":"postnotifications_unregister_device","summary":"POST /notifications/unregister-device","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","example":"ios-simulator-001"}},"required":["deviceId"]},"example":{"deviceId":"ios-simulator-001"}}}},"security":[{"bearerAuth":[]}]}},"/notifications/test":{"post":{"operationId":"postnotifications_test","summary":"POST /notifications/test","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","example":"ScrinAssist Test Notification"},"body":{"type":"string","example":"Push delivery is configured."},"reminderId":{"type":"string","example":"reminder-123"},"deviceId":{"type":"string","example":"ios-simulator-001"}}},"example":{"title":"ScrinAssist Test Notification","body":"Push delivery is configured.","reminderId":"reminder-123","deviceId":"ios-simulator-001"}}}},"security":[{"bearerAuth":[]}]}},"/notifications/phone-verification/start":{"post":{"operationId":"postnotifications_phone_verification_start","summary":"POST /notifications/phone-verification/start","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/notifications/phone-verification/confirm":{"post":{"operationId":"postnotifications_phone_verification_confirm","summary":"POST /notifications/phone-verification/confirm","tags":["Notifications"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/plan":{"get":{"operationId":"getapi_plan","summary":"Get authenticated user's plan and upload limits","tags":["plan"],"parameters":[],"responses":{"200":{"description":"Plan details","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"plan":{"code":"free","status":"active","storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"smsReminders":false,"aiExtractionLimit":50}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Returns the active plan, storage limit, upload-size gate, and feature flags used by mobile for paywall and capability checks.","security":[{"bearerAuth":[]}]}},"/plan":{"get":{"operationId":"getplan","summary":"Get authenticated user's plan and upload limits","tags":["plan"],"parameters":[],"responses":{"200":{"description":"Plan details","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"plan":{"code":"free","status":"active","storageLimit":50,"maxUploadBytes":10485760,"maxUploadMb":10,"smartReminders":false,"smsReminders":false,"aiExtractionLimit":50}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Alias of /api/plan. Returns the active plan, storage limit, upload-size gate, and feature flags used by mobile for paywall and capability checks.","security":[{"bearerAuth":[]}]}},"/api/ai/extract":{"post":{"operationId":"postapi_ai_extract","summary":"Run OCR and structured AI extraction for an uploaded document","tags":["ai"],"parameters":[],"responses":{"200":{"description":"Extraction completed","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"request_id":"ai_req_123","file_id":"file_123","status":"completed","result":{"document_type":"bill","title":"Council Tax Bill","sender":"Bristol Council","summary":"Council tax bill requiring payment by 2026-05-31.","category":"bill","action_required":true,"action_type":"payment_due","action_reason":"The document contains an amount due and a due date.","due_date":"2026-05-31","dueDate":"2026-05-31","amount":"145.30","currency":"GBP","reference_number":"CT-2026-001","referenceNumber":"CT-2026-001","notification_title":"Council tax payment due","notificationTitle":"Council tax payment due","notification_body":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","notificationBody":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","recommended_reminders":[7,3,1],"recommendedReminders":[7,3,1],"confidence":0.87,"needs_human_review":false,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano"},"metadata":{"status":"completed","provider":"openai","model":"gpt-5.4-nano","ocr_provider":"aws_textract","line_count":42,"fallback_used":false}},"request_id":"ai_req_123","file_id":"file_123","status":"completed","result":{"document_type":"bill","title":"Council Tax Bill","sender":"Bristol Council","summary":"Council tax bill requiring payment by 2026-05-31.","category":"bill","action_required":true,"action_type":"payment_due","action_reason":"The document contains an amount due and a due date.","due_date":"2026-05-31","dueDate":"2026-05-31","amount":"145.30","currency":"GBP","reference_number":"CT-2026-001","referenceNumber":"CT-2026-001","notification_title":"Council tax payment due","notificationTitle":"Council tax payment due","notification_body":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","notificationBody":"Your council tax payment of \u00a3145.30 is due on 31 May 2026.","recommended_reminders":[7,3,1],"recommendedReminders":[7,3,1],"confidence":0.87,"needs_human_review":false,"needsHumanReview":false,"provider":"openai","model":"gpt-5.4-nano"},"metadata":{"status":"completed","provider":"openai","model":"gpt-5.4-nano","ocr_provider":"aws_textract","line_count":42,"fallback_used":false}}}}},"400":{"description":"Invalid extraction request","content":{"application/json":{"schema":{"type":"object"},"examples":{"missingFile":{"summary":"fileId missing when no text supplied","value":{"success":false,"error":{"code":"AI_FILE_ID_REQUIRED","message":"fileId is required when text is not supplied."}}},"fileNotReady":{"summary":"Uploaded object key missing","value":{"success":false,"error":{"code":"AI_FILE_NOT_READY","message":"Uploaded file object is missing."}}}}}}},"404":{"description":"File not found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AI_FILE_NOT_FOUND","message":"File not found"}}}}},"422":{"description":"No text found","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AI_NO_TEXT_FOUND","message":"No readable text was found in this document."}}}}},"502":{"description":"AI provider failed","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AI_PROVIDER_FAILED","message":"AI provider request failed."}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"description":"Reads the uploaded S3 object for fileId, extracts text with AWS Textract, then uses OpenAI structured outputs to detect action required, summarize the document, and produce notification/event reason fields. The existing text field remains available for dev/test clients.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AIExtractRequest"},"examples":{"uploadedFile":{"summary":"Extract from uploaded file","value":{"fileId":"file_123"}},"textFallback":{"summary":"Dev/test text fallback","value":{"fileId":"file_123","text":"Council Tax Bill GBP 145.30 due 2026-05-31 reference CT-2026-001","title":"Council Tax Bill"}}}}}},"security":[{"bearerAuth":[]}]}},"/api/ai/reminder-suggestions":{"post":{"operationId":"postapi_ai_reminder_suggestions","summary":"Suggest reminder offsets for extracted document metadata","tags":["ai"],"parameters":[],"responses":{"200":{"description":"Reminder suggestions","content":{"application/json":{"schema":{"type":"object"},"example":{"ok":true,"success":true,"data":{"request_id":"ai_req_123","result":{"offsetDays":[7,1],"channels":["push","email"],"reason":"Suggested from bill pattern and due date 2026-05-31."}}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","example":"file_123"},"category":{"type":"string","example":"bill"},"dueDate":{"type":"string","example":"2026-05-31"}},"required":["category"]},"example":{"fileId":"file_123","category":"bill","dueDate":"2026-05-31"}}}},"security":[{"bearerAuth":[]}]}},"/ai/extract":{"post":{"operationId":"postai_extract","summary":"POST /ai/extract","tags":["ai"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","example":"file-123"},"text":{"type":"string","example":"Amount \u00a3145.30 due 2026-05-31"},"title":{"type":"string","example":"Council Tax Bill"},"sender":{"type":"string","example":"Bristol Council"},"category":{"type":"string","example":"bill"}},"required":["text"]},"example":{"fileId":"file-123","text":"Amount \u00a3145.30 due 2026-05-31","title":"Council Tax Bill","sender":"Bristol Council","category":"bill"}}}},"security":[{"bearerAuth":[]}]}},"/ai/reminder-suggestions":{"post":{"operationId":"postai_reminder_suggestions","summary":"POST /ai/reminder-suggestions","tags":["ai"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fileId":{"type":"string","example":"file-123"},"category":{"type":"string","example":"bill"},"dueDate":{"type":"string","example":"2026-05-31"}},"required":["category"]},"example":{"fileId":"file-123","category":"bill","dueDate":"2026-05-31"}}}},"security":[{"bearerAuth":[]}]}},"/search":{"get":{"operationId":"getsearch","summary":"GET /search","tags":["search"],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"example":"council tax"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"},"example":{"success":true,"data":{},"message":"OK"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"VALIDATION_ERROR","message":"Request validation failed"}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object"},"example":{"success":false,"error":{"code":"AUTH_INVALID_TOKEN","message":"Invalid token"}}}}}},"security":[{"bearerAuth":[]}]}}}}