{"openapi":"3.1.0","info":{"title":"FastAPI","version":"0.1.0"},"paths":{"/emit_counts":{"post":{"summary":"Emit Counts","operationId":"emit_counts_emit_counts_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CountsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/emit_person_updated":{"post":{"summary":"Emit Person Updated Endpoint","operationId":"emit_person_updated_endpoint_emit_person_updated_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonUpdatedRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/emit_tagging_step":{"post":{"summary":"Emit Tagging Step","description":"Internal endpoint called by Lambda workers after each tagging step completes.","operationId":"emit_tagging_step_emit_tagging_step_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TaggingStepRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addImages":{"post":{"summary":"Add Images Route","description":"Endpoint for registering multiple images by UUID and queuing tagging tasks to SQS.\n\nSync on purpose: every call inside add_images blocks (SQLAlchemy, boto3), so as\nan async handler a 50-image upload held the event loop for seconds and stalled\nevery other request on the worker. FastAPI runs sync handlers in its threadpool.","operationId":"add_images_route_addImages_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddImagesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{project_id}/images/tagging-failures":{"get":{"summary":"Get Tagging Failures","description":"Returns images that have failed or stuck tagging steps for a project.\nFailed = status 'failed'. Stuck = status 'pending' for more than 1 hour.\nFilter by steps using ?steps=general,rekognition,bda (defaults to all three).\nUse operator=AND to require ALL selected steps to match, OR to match any.\nUse statuses=failed,stuck,pending to control which statuses are included.","operationId":"get_tagging_failures_projects__project_id__images_tagging_failures_get","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","title":"Project Id"}},{"name":"steps","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Steps"}},{"name":"operator","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"OR","title":"Operator"}},{"name":"statuses","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Statuses"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/projects/{project_id}/images/retry-tagging":{"post":{"summary":"Retry Tagging","description":"Retry specific tagging steps for specific images.\nResets status to 'pending' and re-queues to the appropriate SQS queues.","operationId":"retry_tagging_projects__project_id__images_retry_tagging_post","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RetryTaggingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteImages":{"post":{"summary":"Delete Images Endpoint","description":"Deletes multiple images from the system.\n- If images are NOT in trash: performs soft delete (moves to trash)\n- If images are already in trash: performs permanent delete (removes from S3 and DB)\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to delete\n - 'projectId'\n\nReturns:\n - Success message with counts of deleted images\n - Error if imageIds is missing or invalid","operationId":"delete_images_endpoint_deleteImages_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteImagesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getTrashImages":{"get":{"summary":"Get Trash Images Endpoint","description":"Endpoint for retrieving deleted images (trash) for a single project, or across\nmultiple projects (the \"All Projects\" view) when projectIds[] is provided.","operationId":"get_trash_images_endpoint_getTrashImages_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":40,"title":"Pagesize"}},{"name":"sortBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sortby"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/restoreImages":{"post":{"summary":"Restore Images Endpoint","description":"Restores multiple images from trash (undeletes them).\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to restore\n - 'projectId'\n\nReturns:\n - Success message with counts of restored images\n - Error if imageIds is missing or invalid","operationId":"restore_images_endpoint_restoreImages_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreImagesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/countTrashImages":{"get":{"summary":"Count Trash Images Endpoint","description":"Count deleted images (trash) for a project or multiple projects. For photographer role, returns only that photographer's count (backend enforces).","operationId":"count_trash_images_endpoint_countTrashImages_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"type":"integer","title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/countImages":{"get":{"summary":"Count Images Endpoint","description":"Count images for a project or multiple projects. For photographer role, returns only that photographer's count (backend enforces).","operationId":"count_images_endpoint_countImages_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"type":"integer","title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getImages":{"get":{"summary":"Get Images Endpoint","description":"Endpoint for retrieving images with optional filters.\nNote: aiQuery should be sent via POST /searchImages endpoint.","operationId":"get_images_endpoint_getImages_get","parameters":[{"name":"id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"}},{"name":"startDate","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startdate"}},{"name":"endDate","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Enddate"}},{"name":"imageTitle","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Imagetitle"}},{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Projectids[]"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}},{"name":"folderName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Foldername"}},{"name":"personCategory","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personcategory"}},{"name":"tags","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Tags"}},{"name":"tagsByCategory","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tagsbycategory"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":10,"title":"Pagesize"}},{"name":"dateTakenStart","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datetakenstart"}},{"name":"dateTakenEnd","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Datetakenend"}},{"name":"dateUploadedStart","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dateuploadedstart"}},{"name":"dateUploadedEnd","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dateuploadedend"}},{"name":"filterTagsWithOr","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Filtertagswithor"}},{"name":"sortBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sortby"}},{"name":"dateTakenNull","in":"query","required":false,"schema":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Datetakennull"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/searchImages":{"post":{"summary":"Search Images Endpoint","description":"Endpoint for searching images with AI boolean query AST.\nAccepts aiQuery in request body along with other filters.","operationId":"search_images_endpoint_searchImages_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/generateThumbnail/{image_id}":{"post":{"summary":"Generate Thumbnail Endpoint","description":"Generates a thumbnail for the given image if it doesn't exist, uploads it to S3,\nand marks has_thumbnail = TRUE in the DB. Returns the presigned thumbnail URL.","operationId":"generate_thumbnail_endpoint_generateThumbnail__image_id__post","parameters":[{"name":"image_id","in":"path","required":true,"schema":{"type":"string","title":"Image Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/regenerateThumbnails":{"post":{"summary":"Regenerate Thumbnails Endpoint","description":"Maintenance: regenerate (overwrite) correctly-oriented thumbnails at the canonical key\n`thumbnails/{project_id}/{image_id}`. Fixes STALE/rotated thumbnail objects that were\nwritten by an older pipeline before EXIF orientation was baked in. Reuses the same\nload_downscaled_rgb path as /generateThumbnail (orientation baked into pixels).\n\nBody: {\"projectId\": } to regenerate every non-deleted image in a project, or\n{\"imageIds\": [...]} for a specific set. Runs in the background; returns 202-style\n{\"success\": true, \"queued\": N}. Idempotent — safe to re-run.","operationId":"regenerate_thumbnails_endpoint_regenerateThumbnails_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getImagesWithUnknownFaces":{"get":{"summary":"Get Images With Unknown Faces Endpoint","description":"Retrieves images that have at least one face with an unknown name (name IS NULL OR name = '?').\nThis is optimized to only return images that actually have unknown faces.","operationId":"get_images_with_unknown_faces_endpoint_getImagesWithUnknownFaces_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"page","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"default":50,"title":"Pagesize"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generateDownloadUrl":{"post":{"summary":"Generate Download Url Endpoint","description":"Generates a presigned URL for downloading images. If only one image is requested,\nreturns a direct download URL for that image. If multiple images, creates a ZIP file.\n\nRequest Body:\n imageIds: List of image IDs to include\n projectId: Project ID for the images\n \nReturns:\n JSON response with:\n - downloadUrl: The presigned URL\n - filename: The filename for download\n - isZip: Boolean indicating if it's a ZIP file or single image\n \nErrors:\n - 500 if download generation fails","operationId":"generate_download_url_endpoint_generateDownloadUrl_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZipDownloadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generatePresignedUrls":{"post":{"summary":"Generate Presigned Urls Endpoint","description":"Generates presigned URLs for uploading files to S3.\n\nRequest Body:\n files (list): List of file information with contentType (required)\n projectId (int): The ID of the project (required)\n folderName (str): Optional folder name for organization\n photographerId (str): Optional ID of the photographer\n \nReturns:\n JSON response with:\n - urls: List of objects containing file id, key, presigned URL, and contentType\n \nErrors:\n - 401 if user is not authenticated\n - 403 if user lacks permission\n - 400 if required parameters are missing\n - 500 if S3 service access fails","operationId":"generate_presigned_urls_endpoint_generatePresignedUrls_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GeneratePresignedUrlsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/createMultipartUpload":{"post":{"summary":"Create Multipart Upload Endpoint","description":"Initiate S3 multipart uploads and return presigned part URLs. Used for\nlarge files so the browser can upload parts in parallel (small files still\nuse the single-PUT /generatePresignedUrls path).","operationId":"create_multipart_upload_endpoint_createMultipartUpload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateMultipartUploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/completeMultipartUpload":{"post":{"summary":"Complete Multipart Upload Endpoint","operationId":"complete_multipart_upload_endpoint_completeMultipartUpload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompleteMultipartUploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/abortMultipartUpload":{"post":{"summary":"Abort Multipart Upload Endpoint","operationId":"abort_multipart_upload_endpoint_abortMultipartUpload_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbortMultipartUploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/createFolder":{"post":{"summary":"Create Folder Endpoint","operationId":"create_folder_endpoint_createFolder_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteFolder":{"post":{"summary":"Delete Folder Endpoint","operationId":"delete_folder_endpoint_deleteFolder_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteFolderWithContents":{"post":{"summary":"Delete Folder With Contents Endpoint","operationId":"delete_folder_with_contents_endpoint_deleteFolderWithContents_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FolderRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateFolderName":{"put":{"summary":"Update Folder Name Endpoint","operationId":"update_folder_name_endpoint_updateFolderName_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFolderNameRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectFolders":{"get":{"summary":"Get Project Folders Endpoint","description":"Gets all folders for a specified project or the union across multiple projects.","operationId":"get_project_folders_endpoint_getProjectFolders_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addImagesToFolder":{"post":{"summary":"Add Image To Folder Endpoint","description":"Associates multiple images with a folder by adding the folder name as a tag.\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to add to the folder\n - 'folderName': the name of the folder to add the images to\n - 'projectId'\n\nProcess:\n 1. Gets the project ID for each image\n 2. Checks if the folder exists for each project\n 3. Adds the folder name as a tag for each image that doesn't already have it\n\nReturns:\n - Success message with results for each image\n - Detailed results including successful and failed operations","operationId":"add_image_to_folder_endpoint_addImagesToFolder_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModifyFolderImagesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/removeImagesFromFolder":{"post":{"summary":"Remove Image From Folder Endpoint","description":"Removes multiple images from a folder by deleting the folder name tag.\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to remove from the folder\n - 'folderName': the name of the folder to remove the images from\n - 'projectId'\n\nProcess:\n 1. Gets the project ID for each image\n 2. Checks if the folder exists for each project\n 3. Removes the folder name tag for each image if it exists\n\nReturns:\n - Success message with results for each image\n - Detailed results including successful and failed operations","operationId":"remove_image_from_folder_endpoint_removeImagesFromFolder_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModifyFolderImagesRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateImagesPhotographer":{"post":{"summary":"Update Images Photographer Endpoint","description":"Sets the photographer for the given images in the project.\nExpects: projectId, imageIds, photographerId.\nPhotographer must be associated with the project.","operationId":"update_images_photographer_endpoint_updateImagesPhotographer_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateImagesPhotographerRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getPhotographers":{"get":{"summary":"Get Photographers Endpoint","description":"Retrieves photographers for a single project, or the union across multiple\nprojects (the \"All Projects\" view).\n\nQuery Parameters (one of):\n - projectId: A single project ID\n - projectIds[]: Multiple project IDs. Photographers are merged by identity\n (id) across projects, with totalImagesCount summed across them.\n\nReturns:\n JSON response with list of photographers containing:\n - id: unique identifier\n - name: photographer's name\n - email: photographer's email address\n - description: additional information about the photographer\n - isEventOrganizer: boolean indicating if photographer is also an event organizer\n - totalImagesCount: total number of images uploaded by this photographer\n\nErrors:\n - 400 if neither projectId nor projectIds[] is provided\n - 500 if database access fails","operationId":"get_photographers_endpoint_getPhotographers_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getRecipients":{"get":{"summary":"Get Recipients Endpoint","description":"Retrieves recipients for a single project, or the union across multiple\nprojects (the \"All Projects\" view) when projectIds[] is provided. The\nmulti-project payload includes per-recipient project membership (projectIds).","operationId":"get_recipients_endpoint_getRecipients_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addRecipientToProjects":{"post":{"summary":"Add Recipient To Projects Endpoint","description":"Attach an EXISTING recipient to additional projects (link-only). Used by the\nAll-Projects recipients panel. Body: { recipientId: str, projectIds: int[] }.","operationId":"add_recipient_to_projects_endpoint_addRecipientToProjects_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deletePhotographer":{"post":{"summary":"Delete Photographer Endpoint","description":"Removes a photographer's association with a specific project.\n\nExpects:\n - JSON with:\n - 'photographerId': unique identifier of the photographer\n - 'projectId': ID of the project to remove from\n\nReturns:\n - Success message if photographer was found and removed from project\n - Error if photographer not found or other issues occur","operationId":"delete_photographer_endpoint_deletePhotographer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/revokePhotographerProjectAccess":{"post":{"summary":"Revoke Photographer Project Access Endpoint","description":"Takes away a photographer's access to ONE project, keeping their row and image credit.\n\nExpects:\n - JSON with 'photographerId' and 'projectId'\n\nCounterpart to /invitePhotographer, which is the only thing that grants a project.\n/deletePhotographer is NOT the counterpart: it drops the association row, which also\ndrops the photographer out of that project's list. Idempotent — revoking access nobody\nhas is a success with changed=false.","operationId":"revoke_photographer_project_access_endpoint_revokePhotographerProjectAccess_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteRecipient":{"post":{"summary":"Delete Recipient Endpoint","description":"Removes a recipient's association with a specific project.\n\nExpects:\n - JSON with:\n - 'recipientId': unique identifier of the recipient\n - 'projectId': ID of the project to remove from\n\nReturns:\n - Success message if recipient was found and removed from project\n - Error if recipient not found or other issues occur","operationId":"delete_recipient_endpoint_deleteRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/editPhotographer":{"post":{"summary":"Edit Photographer Endpoint","description":"Updates a photographer's information in the database.\n\nExpects:\n - JSON with:\n - 'id': unique identifier of the photographer (required)\n - 'name': new name for the photographer (optional)\n - 'description': new description for the photographer (optional)\n - 'projectId'\n\nReturns:\n - Success message if photographer was found and updated\n - Error if photographer not found or other issues occur","operationId":"edit_photographer_endpoint_editPhotographer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/editRecipient":{"post":{"summary":"Edit Recipient Endpoint","description":"Updates a recipient's information in the database.\n\nExpects:\n - JSON with:\n - 'recipientId': unique identifier of the recipient (required)\n - 'name': new name for the recipient (optional)\n - 'primaryEmail': new primary email for the recipient (optional)\n - 'description': new description for the recipient (optional)\n - 'additionalEmails': list of additional emails (optional)\n - 'projectId'\n\nReturns:\n - Success message if recipient was found and updated\n - Error if recipient not found or other issues occur","operationId":"edit_recipient_endpoint_editRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/invitePhotographer":{"post":{"summary":"Invite Photographer Endpoint","description":"Invites a photographer by generating a password, saving them to the database, and sending an email.\n\nExpects:\n - JSON with:\n - 'name': photographer's name\n - 'email': photographer's email\n - 'description': photographer's description\n - 'projectId': ID of the project to associate with\n\nReturns:\n - Success message with clerk_user_id if successful\n - Error if required fields are missing or other issues occur","operationId":"invite_photographer_endpoint_invitePhotographer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addPhotographer":{"post":{"summary":"Add Photographer Endpoint","description":"Adds a photographer to a project WITHOUT creating a login account or sending\nan email. Email is optional and can be filled in later (via editPhotographer)\nor when the photographer is invited (via invitePhotographer).\n\nExpects:\n - JSON with:\n - 'name': photographer's name (required)\n - 'email': photographer's email (optional)\n - 'description': photographer's description (optional)\n - 'projectId': ID of the project to associate with (required)\n\nReturns:\n - Success message with the new photographer id if successful\n - Error if required fields are missing or other issues occur","operationId":"add_photographer_endpoint_addPhotographer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addPhotographerToProjects":{"post":{"summary":"Add Photographer To Projects Endpoint","description":"Attach an EXISTING photographer to additional projects (link-only): no new\naccount, no email. Used by the All-Projects photographers panel.\n\nBody: { photographerId: str, projectIds: int[] }","operationId":"add_photographer_to_projects_endpoint_addPhotographerToProjects_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/inviteRecipient":{"post":{"summary":"Invite Recipient Endpoint","description":"Invites a recipient by generating a password, saving them to the database, and sending an email.\n\nExpects:\n - JSON with:\n - 'name': recipient's name\n - 'email': recipient's email\n - 'description': recipient's description\n - 'projectId': ID of the project to associate with\n\nReturns:\n - Success message with clerk_user_id if successful\n - Error if required fields are missing or other issues occur","operationId":"invite_recipient_endpoint_inviteRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shareImagesWithRecipient":{"post":{"summary":"Share Images With Recipient Endpoint","description":"Shares multiple images with a recipient by adding entries to the image_shares table.\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to share\n - 'recipientId': ID of the recipient to share with\n\nProcess:\n 1. Checks if images and recipient exist\n 2. Adds entries to image_shares table, ignoring duplicates\n\nReturns:\n - Success message with counts of shared images\n - Detailed results including successful and skipped operations","operationId":"share_images_with_recipient_endpoint_shareImagesWithRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/unshareImagesWithRecipient":{"post":{"summary":"Unshare Images With Recipient Endpoint","description":"Unshares multiple images from a recipient by removing entries from the image_recipients table.\n\nExpects:\n - JSON with:\n - 'imageIds': list of image IDs to unshare\n - 'recipientId': ID of the recipient to unshare from\n\nProcess:\n 1. Checks if recipient exists\n 2. Removes entries from image_recipients table\n\nReturns:\n - Success message with counts of unshared images\n - Detailed results including successful and skipped operations","operationId":"unshare_images_with_recipient_endpoint_unshareImagesWithRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getRecipientImages":{"get":{"summary":"Get Recipient Images Endpoint","description":"Retrieves all image IDs that a recipient has access to from the image_shares table.\n\nRequired Query Parameters:\n - recipientId: The ID of the recipient\n\nOptional Query Parameters:\n - projectId: Filter images by project ID\n\nReturns:\n JSON response with list of image IDs and count:\n - success: boolean indicating if the request was successful\n - count: number of images found\n - imageIds: list of image IDs the recipient has access to\n\nErrors:\n - 400 if recipientId is missing\n - 404 if recipient doesn't exist\n - 500 if database access fails","operationId":"get_recipient_images_endpoint_getRecipientImages_get","parameters":[{"name":"recipientId","in":"query","required":true,"schema":{"type":"string","title":"Recipientid"}},{"name":"projectId","in":"query","required":false,"schema":{"type":"string","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addRecipients":{"post":{"summary":"Add Recipients Endpoint","description":"API endpoint for adding recipients to a project.\n\nValidates request JSON, extracts the project ID and recipients data,\nthen calls the add_recipients function to process them.\n\nReturns:\n Flask response: JSON response with success message or error details","operationId":"add_recipients_endpoint_addRecipients_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sendToRecipient":{"post":{"summary":"Send To Recipient Endpoint","description":"API endpoint for sending emails to recipients.\n\nValidates user permissions, extracts request parameters, and calls\nthe send_to_recipient function with the necessary data.\n\nReturns:\n Flask response: JSON response with success message or error details","operationId":"send_to_recipient_endpoint_sendToRecipient_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getEffectivePermissions":{"get":{"summary":"Get Effective Permissions Endpoint","description":"Returns effective task-based permissions for a user within a project.\n\nFor normal users:\n- Start from role defaults for (project, role)\n- Apply per-user overrides if present\n\nNotes:\n - If user_id/role are omitted, they default to the authenticated user.\n - Non-super-admins can only request their own permissions.","operationId":"get_effective_permissions_endpoint_getEffectivePermissions_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"userId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Userid"}},{"name":"role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getEffectiveOrgPermissions":{"get":{"summary":"Get Effective Org Permissions Endpoint","description":"Org-wide effective permissions for a user — NO project needed.\n\nPermissions are per-organization-user now, so the app fetches this ONCE per\nsession (on login / reload) instead of once per project. Resolution:\nrole default → live-linked role preset → per-user org overrides, unioned\nacross the user's organizations. See get_effective_org_permissions_for_user.\n\n- userId/role default to the authenticated user.\n- Non-super-admins can only request their own permissions.","operationId":"get_effective_org_permissions_endpoint_getEffectiveOrgPermissions_get","parameters":[{"name":"userId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Userid"}},{"name":"role","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Role"}},{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/checkRouteAccess":{"get":{"summary":"Check Route Access Endpoint","description":"For middleware: returns { \"allowed\": true/false } for the current user and path.\nUsed to gate /faces, /personalized-tags, /photographers, /recipients by permissions.","operationId":"check_route_access_endpoint_checkRouteAccess_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Path e.g. /ProjectTitle/faces","title":"Path"},"description":"Path e.g. /ProjectTitle/faces"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/permission-presets":{"get":{"summary":"Admin List Permission Presets Endpoint","description":"List named permission presets for the given role for organization(s).\nPass organizationIds, or projectIds to infer orgs from projects (via organizers).\nRequires admin (admins table).","operationId":"admin_list_permission_presets_endpoint_admin_permission_presets_get","parameters":[{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}},{"name":"organizationIds","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated organization IDs (preferred)","default":"","title":"Organizationids"},"description":"Comma-separated organization IDs (preferred)"},{"name":"projectIds","in":"query","required":false,"schema":{"type":"string","description":"Comma-separated project IDs (orgs inferred for listing)","default":"","title":"Projectids"},"description":"Comma-separated project IDs (orgs inferred for listing)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/permissions/role":{"patch":{"summary":"Admin Patch Role Permissions Endpoint","description":"Super-admin endpoint.\nEdits role defaults (insert/delete) for a project, enforcing global locks.\n\nExpected body:\n{\n \"role\": \"photographer\",\n \"changes\": {\n \"sharelinks.create\": true,\n \"images.delete\": false\n }\n}","operationId":"admin_patch_role_permissions_endpoint_admin_permissions_role_patch","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/permissions/user":{"patch":{"summary":"Admin Patch User Permissions Endpoint","description":"Super-admin endpoint.\nEdits user-specific permissions (upsert) for a project, enforcing global locks.\n\nExpected body:\n{\n \"role\": \"photographer\",\n \"user_id\": \"user_target\",\n \"changes\": {\n \"sharelinks.create\": true,\n \"images.delete\": false\n }\n}","operationId":"admin_patch_user_permissions_endpoint_admin_permissions_user_patch","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Payload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/permissions/tasks":{"get":{"summary":"List Tasks Endpoint","description":"Super-admin endpoint.\nLists all permission tasks (category + task) for building UI structures.","operationId":"list_tasks_endpoint_admin_permissions_tasks_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/permissions/org":{"get":{"summary":"Admin Get Org Manager Grants Endpoint","description":"Admin endpoint.\nList an organization's organizers with whether each holds the\n'org.manage.organizers' permission.","operationId":"admin_get_org_manager_grants_endpoint_admin_permissions_org_get","parameters":[{"name":"organizationId","in":"query","required":true,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Admin Patch Org Manager Grant Endpoint","description":"Admin endpoint.\nGrant (allowed=true) or revoke (allowed=false) the 'org.manage.organizers'\npermission for a user within an organization.\n\nExpected body: { \"organizationId\": int, \"userId\": str, \"allowed\": bool }","operationId":"admin_patch_org_manager_grant_endpoint_admin_permissions_org_patch","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjects":{"get":{"summary":"Get Projects Endpoint","description":"Retrieves all projects associated with a specific event organizer, recipient, or photographer.\n\nQuery Parameters:\n eventOrganizerId (str): The ID of the event organizer (optional)\n recipientId (str): The ID of the recipient (optional)\n photographerId (str): The ID of the photographer (optional)\n\nNotes:\n - Exactly one of the ID parameters must be provided (not zero, not multiple)\n\nReturns:\n JSON response containing:\n - projects: List of projects with their metadata\n Each project contains:\n - id\n - title\n - start_date\n - end_date\n - status\n\nErrors:\n - 400 if none of the ID parameters is provided\n - 400 if more than one ID parameter is provided\n - 404 if the specified entity is not found\n - 500 if database access fails","operationId":"get_projects_endpoint_getProjects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/project-by-upload-token":{"get":{"summary":"Get Project By Upload Token Endpoint","description":"Resolve a project from its upload token for the current user.\n\n- Only event organizers, photographers, admins, and super admins may use this.\n- Recipients are not allowed to resolve upload links.\n- Also checks that the user is actually associated with the project\n (event_organizer_projects or photographer_projects) unless admin/super-admin.","operationId":"get_project_by_upload_token_endpoint_project_by_upload_token_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","description":"Project upload token (UUID)","title":"Token"},"description":"Project upload token (UUID)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/createUploadLink":{"post":{"summary":"Create Upload Link Endpoint","operationId":"create_upload_link_endpoint_createUploadLink_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadLinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getUploadLinks":{"get":{"summary":"Get Upload Links Endpoint","description":"Upload links for a project, scoped to what the caller is allowed to see.\n\nTwo capabilities (migration 028):\n * settings.manage.uploadLinks -> every link in the project (the timetable / manager view)\n * uploadLinks.viewAssigned -> ONLY the links assigned to them, read-only\n\nBefore this, any project member got every link — so a photographer could see the whole\nshooting schedule and everyone else's tokens.","operationId":"get_upload_links_endpoint_getUploadLinks_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateUploadLink":{"patch":{"summary":"Update Upload Link Endpoint","operationId":"update_upload_link_endpoint_updateUploadLink_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateUploadLinkRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteUploadLink":{"delete":{"summary":"Delete Upload Link Endpoint","operationId":"delete_upload_link_endpoint_deleteUploadLink_delete","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/upload-link-by-token":{"get":{"summary":"Upload Link By Token Endpoint","description":"Resolve a stored upload link by token for the current user. 404 if the token is\nnot a stored link (the frontend then falls back to the legacy query-string link).","operationId":"upload_link_by_token_endpoint_upload_link_by_token_get","parameters":[{"name":"token","in":"query","required":true,"schema":{"type":"string","description":"Stored upload-link token","title":"Token"},"description":"Stored upload-link token"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getRecipientProjects":{"get":{"summary":"Get Recipient Projects Endpoint","description":"Retrieves all projects associated with a specific recipient.\n\nQuery Parameters:\n recipientId (str): The ID of the recipient (required)\n\nReturns:\n JSON response containing:\n - projects: List of projects with their metadata\n Each project contains:\n - id\n - title\n - start_date\n - end_date\n - status\n\nErrors:\n - 400 if recipientId is missing\n - 404 if recipient is not found\n - 500 if database access fails","operationId":"get_recipient_projects_endpoint_getRecipientProjects_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/addProject":{"post":{"summary":"Add Project Endpoint","description":"Creates a new project and associates it with an event organizer.\n\nRequest Body:\n eventOrganizerId (str): The ID of the event organizer (required)\n title (str): The title of the project (required)\n startDate (str): The start date in ISO format (required)\n endDate (str): The end date in ISO format (required)\n\nReturns:\n JSON response with:\n - message: Success message\n - project: Created project details\n\nErrors:\n - 400 if any required parameter is missing or dates are invalid\n - 404 if event organizer is not found\n - 500 if database access fails","operationId":"add_project_endpoint_addProject_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/updateProject":{"put":{"summary":"Update Project Endpoint","description":"Updates project title, start date and end date.\nAccess is restricted to event organizers associated with the project.","operationId":"update_project_endpoint_updateProject_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/deleteProject":{"delete":{"summary":"Delete Project Endpoint","description":"Deletes a project and all associated data including images, folders, persons, and associations.\n\nQuery Parameters:\n projectId (int): The ID of the project to delete (required)\n \nReturns:\n JSON response with:\n - message: Success message\n - project_id: The deleted project ID\n \nErrors:\n - 400 if projectId is missing\n - 404 if project is not found\n - 500 if deletion fails","operationId":"delete_project_endpoint_deleteProject_delete","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectPersonalizedPrompt":{"put":{"summary":"Update Project Personalized Prompt Endpoint","description":"Updates the personalized prompt for a specific project.\n\nRequest Body:\n projectId (int): The ID of the project (required)\n personalizedPrompt (str): The personalized prompt to set (optional, can be null to clear it)\n\nReturns:\n JSON response with:\n - message: Success message\n - project: Updated project details including the new personalized prompt\n\nErrors:\n - 400 if projectId is missing\n - 404 if project is not found\n - 500 if database access fails","operationId":"update_project_personalized_prompt_endpoint_updateProjectPersonalizedPrompt_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectPersonalizedPrompt":{"get":{"summary":"Get Project Personalized Prompt Endpoint","description":"Retrieves the personalized prompt for a specific project.\n\nParameters:\n projectId (int): The ID of the project to get the personalized prompt for\n\nReturns:\n JSON response with:\n - project: Project details including id, title, and personalized_prompt\n\nErrors:\n - 400 if projectId is missing\n - 404 if project is not found\n - 500 if database access fails","operationId":"get_project_personalized_prompt_endpoint_getProjectPersonalizedPrompt_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectFilenamingConfig":{"put":{"summary":"Update Project Filenaming Config Endpoint","description":"Updates the filenaming configuration for a specific project.\n\nRequest Body:\n projectId (int): The ID of the project (required)\n titleTemplate (str | null): Template for image titles (optional)\n filenameTemplate (str | null): Template for filenames without extension (optional)\n\nThe configuration is stored as JSONB in the projects table and used when\ngenerating image titles (for display) and filenames for downloads.","operationId":"update_project_filenaming_config_endpoint_updateProjectFilenamingConfig_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/updateAllProjectsFilenamingConfig":{"put":{"summary":"Update All Projects Filenaming Config Endpoint","description":"Overwrites the filenaming configuration for MANY projects at once (the\n\"All Projects\" settings surface). For each project it writes the config and\nsynchronously re-titles that project's already-tagged images — so this can\ntake a while on large accounts. Per-project failures are collected, not fatal.\n\nRequest Body:\n projectIds (int[]): projects to overwrite (required)\n titleTemplate, filenameTemplate, copyrightMode, copyrightText (optional)","operationId":"update_all_projects_filenaming_config_endpoint_updateAllProjectsFilenamingConfig_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectFilenamingConfig":{"get":{"summary":"Get Project Filenaming Config Endpoint","description":"Retrieves the filenaming configuration for a specific project.\n\nParameters:\n projectId (int): The ID of the project to get the filenaming config for\n\nReturns:\n JSON response with:\n - project: Project details including id, title, and filenaming_config","operationId":"get_project_filenaming_config_endpoint_getProjectFilenamingConfig_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectPersonalizedTags":{"put":{"summary":"Update Project Personalized Tags Endpoint","description":"Updates the personalized tags for a specific project.\nDeletes existing tags for the project and adds new ones.\n\nRequest Body:\n projectId (int): The ID of the project (required)\n personalizedTags (dict): Dictionary with tags as keys and descriptions as values (required)\n\nReturns:\n JSON response with:\n - message: Success message\n - project: Updated project details including the new personalized tags\n\nErrors:\n - 400 if projectId is missing or duplicate tags found\n - 404 if project is not found\n - 500 if database access fails","operationId":"update_project_personalized_tags_endpoint_updateProjectPersonalizedTags_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectPersonalizedTags":{"get":{"summary":"Get Project Personalized Tags Endpoint","description":"Retrieves the personalized tags for a specific project.\n\nParameters:\n projectId (int): The ID of the project to get tags for\n\nReturns:\n JSON response with:\n - project: Project details including id, title, and personalized_tags dictionary\n\nErrors:\n - 400 if projectId is missing\n - 404 if project is not found\n - 500 if database access fails","operationId":"get_project_personalized_tags_endpoint_getProjectPersonalizedTags_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectCustomTagCategories":{"put":{"summary":"Update Project Custom Tag Categories Endpoint","description":"Replaces all custom tag categories and their default options for a project.\n\nRequest body:\n projectId (int, required)\n categories (list, required): each category:\n - name (str, required)\n - description (str, optional)\n - options (list[dict], optional) where each option has:\n - value (str, required)\n - label (str, optional)","operationId":"update_project_custom_tag_categories_endpoint_updateProjectCustomTagCategories_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/renameCustomTagOption":{"post":{"summary":"Rename Custom Tag Option Endpoint","description":"Renames one option of a custom tag category, everywhere its name is stored.\n\nBody: { projectId, categoryName, oldValue, newValue }\n\nSeparate from /updateProjectCustomTagCategories on purpose: that endpoint replaces the\nproject's categories wholesale, so a renamed option arrives as a deletion plus an\ninsertion and there is no way to tell it apart from someone genuinely swapping one tag\nfor another. A rename has to be stated to be carried out — see\nproject_operations.rename_custom_tag_option for what it touches.","operationId":"rename_custom_tag_option_endpoint_renameCustomTagOption_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectCustomTagCategories":{"get":{"summary":"Get Project Custom Tag Categories Endpoint","description":"Returns all custom tag categories and their default options for a project.","operationId":"get_project_custom_tag_categories_endpoint_getProjectCustomTagCategories_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"string","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectLockedTags":{"get":{"summary":"Get Project Locked Tags Endpoint","description":"Returns the list of locked tag values for the project (tags that exclude images from share links).","operationId":"get_project_locked_tags_endpoint_getProjectLockedTags_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectLockedTags":{"put":{"summary":"Update Project Locked Tags Endpoint","description":"Replaces the project's locked tags with the body's list. Body: { projectId: number, lockedTags: string[] }.\n\nGated on 'settings.manage.lockedTags' (migration 026). Before that this endpoint was gated\nonly by require_project_access, so ANY project member — a photographer included — could\nrewrite the locked-tag list and expose images the organizers had deliberately withheld.\nrequire_task_or_403 also enforces project membership, so it replaces that check.","operationId":"update_project_locked_tags_endpoint_updateProjectLockedTags_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/photographers/revokeAccess":{"post":{"summary":"Revoke Photographer Access Endpoint","description":"Stop a photographer signing in, while keeping every image credited to them.\n\nDeliberately NOT a delete: images.photographer_id points at this row, so removing it would\norphan their work or force reassigning it to someone else. See\nauxiliary/user_operations.revoke_photographer_access.","operationId":"revoke_photographer_access_endpoint_photographers_revokeAccess_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhotographerAccessRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/photographers/restoreAccess":{"post":{"summary":"Restore Photographer Access Endpoint","description":"Clear the revoked flag so the normal Invite flow can issue them a fresh login.\n\nThe old Clerk account is gone for good; this only makes the row invitable again.","operationId":"restore_photographer_access_endpoint_photographers_restoreAccess_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhotographerAccessRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/photographers":{"delete":{"summary":"Delete Photographer Completely Endpoint","description":"Delete a photographer from the database and Clerk. Refused if they own any images.\n\n409 with an explanation when they have images, pointing at revokeAccess (keeps attribution)\nor merge (moves it deliberately) instead.","operationId":"delete_photographer_completely_endpoint_photographers_delete","parameters":[{"name":"photographerId","in":"query","required":true,"schema":{"type":"string","title":"Photographerid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/photographers/merge/preview":{"post":{"summary":"Preview Photographer Merge Endpoint","description":"Dry run: what a merge would move, so the UI can state it before the user commits.","operationId":"preview_photographer_merge_endpoint_photographers_merge_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergePhotographersRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/photographers/merge":{"post":{"summary":"Merge Photographers Endpoint","description":"Fold duplicate photographer records into one.\n\nThe same person routinely appears twice — imported by a migration as a name-only record\nthat owns their historical images, then again as a real account once they sign in. The\nrecords look identical but share nothing, so locking one leaves the other's images\nshareable. See auxiliary/user_operations.merge_photographers.","operationId":"merge_photographers_endpoint_photographers_merge_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MergePhotographersRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectLockedPhotographers":{"get":{"summary":"Get Project Locked Photographers Endpoint","description":"Locked photographer ids (restriction reason 'photographer', migration 025).\n\nImages shot by these photographers are excluded from share links unless the link opts in —\nthis is what backs permanent licensing restrictions (e.g. agency images that media may use\nbut partners may not).\n\nSingle project -> {projectId, lockedPhotographers: [...]}.\nprojectIds[] -> additionally {locksByProject: {\"38\": [...], ...}} for the All-Projects\n photographers table, where one photographer can be locked in some of\n their projects and not others.","operationId":"get_project_locked_photographers_endpoint_getProjectLockedPhotographers_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/setPhotographerLock":{"post":{"summary":"Set Photographer Lock Endpoint","description":"Lock or unlock ONE photographer across several projects in a single call.\n\nThe All-Projects photographers table needs this: a photographer spans many projects, and\ndoing it with the per-project full-list replace would mean N read-modify-write round trips\nracing each other. This touches only the one photographer's rows, so concurrent edits to\nother photographers in the same project can't clobber each other either.\n\nAuthorised per project — the caller's projects are filtered to those where they actually\nhold settings.manage.lockedPhotographers, so an All-Projects click can't reach a project\nthey don't administer. Returns the projects actually changed.","operationId":"set_photographer_lock_endpoint_setPhotographerLock_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetPhotographerLockRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateProjectLockedPhotographers":{"put":{"summary":"Update Project Locked Photographers Endpoint","description":"Replaces the project's locked photographers. Body: { projectId: number, lockedPhotographers: string[] }.","operationId":"update_project_locked_photographers_endpoint_updateProjectLockedPhotographers_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectUploadLinkInfo":{"get":{"summary":"Get Project Upload Link Info Endpoint","description":"Returns upload_token and title for the project so the client can build upload links.\nGated on the 'images.upload' task (org-wide) — matching the sidebar entry\n(useCan('images.upload')) and the write gate — so anyone allowed to upload\n(photographers included), not just event organizers, can build a link.\nrequire_task_or_403 also enforces project membership.","operationId":"get_project_upload_link_info_endpoint_getProjectUploadLinkInfo_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getAllTags":{"get":{"summary":"List Tags","description":"Retrieves unique tags from the database. For photographer role, always filters by that photographer's images.\nIf trash=true, only returns tags from images in trash (deleted_at IS NOT NULL).\nAccepts projectIds[] for multi-project aggregation.","operationId":"list_tags_getAllTags_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"photographerId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"}},{"name":"folderName","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Foldername"}},{"name":"recipientId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recipientid"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"personId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Personid"}},{"name":"trash","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Trash"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteTag":{"post":{"summary":"Delete Tag Endpoint","description":"Deletes a tag from an image. Body must include imageId, tag, category, and projectId (for person category).","operationId":"delete_tag_endpoint_deleteTag_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/deleteTagBulk":{"post":{"summary":"Delete Tag Bulk Endpoint","description":"Deletes a tag from multiple images. Body must include imageIds, tag, category, and projectId.","operationId":"delete_tag_bulk_endpoint_deleteTagBulk_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/addTag":{"post":{"summary":"Add Tag Endpoint","description":"Adds a tag to an image.","operationId":"add_tag_endpoint_addTag_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/updateImageTitle":{"post":{"summary":"Update Image Title Endpoint","description":"Manually rename a single image's title. Locks it so file-naming-convention changes and the\ntagging pipeline no longer re-title it, and its download filename follows this title.","operationId":"update_image_title_endpoint_updateImageTitle_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/addTagBulk":{"post":{"summary":"Add Tag Bulk Endpoint","description":"Adds the same tag to multiple images.\n\nBody:\n{\n \"imageIds\": [1, 2, 3],\n \"tag\": \"VIP\",\n \"category\": \"highlights\",\n \"projectId\": 42\n}","operationId":"add_tag_bulk_endpoint_addTagBulk_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/updateTag":{"put":{"summary":"Update Tag Endpoint","description":"Updates a tag for an image.","operationId":"update_tag_endpoint_updateTag_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/updateTagBulk":{"put":{"summary":"Update Tag Bulk Endpoint","operationId":"update_tag_bulk_endpoint_updateTagBulk_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getTagsFromPrompt":{"post":{"summary":"Get Tags From Prompt Endpoint","description":"Gets relevant tags from a prompt using OpenAI.","operationId":"get_tags_from_prompt_endpoint_getTagsFromPrompt_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getTagsFromPromptAI":{"post":{"summary":"Get Tags From Prompt Ai Endpoint","description":"Gets relevant tags from a prompt using AWS Bedrock (Claude).","operationId":"get_tags_from_prompt_ai_endpoint_getTagsFromPromptAI_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/addPersonFace":{"post":{"summary":"Add Person Face Endpoint","description":"Endpoint for adding a person to the face recognition system.\nIf scanExistingFaces is \"true\", starts a background scan for matches in existing stored faces.\nIf bulk is \"true\", skips folder update, persons emit, and duplicate scan; call completeBulkFaceUpload when done.\n\nArgs:\n name: The person's name\n projectId: The project ID this person belongs to\n category: Category/type of person (default: \"person\")\n position: The person's position/role (optional)\n link: Link associated with the person (optional)\n faceImageId: Face image ID to associate with the person (used to fetch image from S3)\n scanExistingFaces: If \"true\", scan existing images for this person after registration\n bulk: If \"true\", do not run background tasks (folders, persons emit, duplicate scan); caller must call completeBulkFaceUpload at the end\n\nReturns:\n JSON response with success status and person details","operationId":"add_person_face_endpoint_addPersonFace_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_person_face_endpoint_addPersonFace_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/bulkAddPersonFaces":{"post":{"summary":"Bulk Add Person Faces Endpoint","description":"Add many faces in one request. Frontend should upload all images to S3 first (presigned URLs),\nthen send projectId, category, and faces: [ { faceImageId, name } ].\nBackend processes them (with limited concurrency), then runs folder update + persons emit + one scan.","operationId":"bulk_add_person_faces_endpoint_bulkAddPersonFaces_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/completeBulkFaceUpload":{"post":{"summary":"Complete Bulk Face Upload Endpoint","description":"Call once after a batch of addPersonFace(..., bulk=true) is done.\nRuns folder update, persons emit, and one project-wide face match scan; then returns.\nFrontend should call this after the last face is added in a bulk upload, then fetch faces/duplicates/suggestions once.","operationId":"complete_bulk_face_upload_endpoint_completeBulkFaceUpload_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/matchBulkFaceNames":{"post":{"summary":"Match Bulk Face Names Endpoint","description":"Preview step for bulk face upload: match each uploaded name against EXISTING\npeople (org-wide, accent/typo tolerant) WITHOUT writing anything to the DB.\n\nBody: { projectId, faces: [ { faceImageId, name } ] }\nReturns per-face candidates so the frontend can show a review list where the\nuser chooses, per match: update the existing person / skip / add as new.","operationId":"match_bulk_face_names_endpoint_matchBulkFaceNames_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/commitBulkFaceUpload":{"post":{"summary":"Commit Bulk Face Upload Endpoint","description":"Commit the reviewed bulk upload. Body:\n { projectId, category, actions: [ { faceImageId, name, action, personId? } ] }\nwhere action is \"update\" | \"new\" | \"skip\". Runs them with limited concurrency,\nthen updates folders and schedules one face-match scan.","operationId":"commit_bulk_face_upload_endpoint_commitBulkFaceUpload_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectPersons":{"get":{"summary":"Get Project Persons Endpoint","description":"Endpoint for retrieving all persons associated with a project.\nIf minimal=true, returns only person_id, name, category (no S3 presigned URLs) — fast for dropdowns/share links.\nOtherwise returns full person dicts with presigned face image URLs (can be slow on large projects).","operationId":"get_project_persons_endpoint_getProjectPersons_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"string","title":"Projectid"}},{"name":"minimal","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Minimal"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrgPersons":{"get":{"summary":"Get Org Persons Endpoint","description":"Org-global persons list (the faces model is org-wide). `projectIds[]` is the set of\nprojects the caller can access (used for auth + org resolution + the default membership\nscope). `filterProjectIds[]` optionally narrows to persons appearing in a chosen subset\n(the per-project / project-picker view). Each person includes member_project_ids (the\nprojects they appear in) and image_count.\n\nPaged for fast first paint: `limit`/`offset` return a stable window ordered by newest\nactivity (last_uploaded DESC). The client fetches pages and appends until a short page.","operationId":"get_org_persons_endpoint_getOrgPersons_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"filterProjectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Filterprojectids[]"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":150,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"name","title":"Sort"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectFaceCategories":{"get":{"summary":"Get Project Face Categories Endpoint","description":"Returns distinct face category labels for a project (from persons and project_face_categories).\nUsed for dropdowns when adding/editing faces. When category is null, UI shows \"user added\" or \"auto detected\" from creation_type.","operationId":"get_project_face_categories_endpoint_getProjectFaceCategories_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"string","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectAttendees":{"get":{"summary":"Get Project Attendees Endpoint","description":"Returns only attendees (category = 'Attendee' or 'Attendees'), joined with project_attendees\n(email, share_link, status) and image_count. Unlabeled/person are not shown in the list but\ncan be used in merge suggestions (getPotentialDuplicates / getFaceMatchSuggestions).\n\nReturns every attendee by default; `limit`/`offset` are opt-in and the response\ncarries `total`/`hasMore`.","operationId":"get_project_attendees_endpoint_getProjectAttendees_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/downloadAttendeeFacesZip":{"get":{"summary":"Download Attendee Faces Zip","description":"Stream a ZIP of all attendee face images for a project, named by person name.\n\nAssembled on disk and streamed, not held in memory. It used to read every face\nimage into RAM, build the archive in a BytesIO, and then copy the whole archive\nagain into the response body — three copies of the same bytes. Face images are\nthe full-size originals (~5MB each), so a project with a few hundred attendees\nexceeded the task's 2GB and took the container down with every other request on\nit. Now only one image is resident at a time.","operationId":"download_attendee_faces_zip_downloadAttendeeFacesZip_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/upsertProjectAttendee":{"post":{"summary":"Upsert Project Attendee Endpoint","description":"Create or update project_attendees row; create share link for person if missing.","operationId":"upsert_project_attendee_endpoint_upsertProjectAttendee_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertAttendeeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/setAttendeeEmailApproval":{"post":{"summary":"Set Attendee Email Approval Endpoint","description":"Set attendee share-email workflow status (pending or an approved* variant).\nAfter an email was sent (status sent), you can still change to pending or\napproved* to adjust workflow or send again via /sendAttendeeEmails.","operationId":"set_attendee_email_approval_endpoint_setAttendeeEmailApproval_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetAttendeeEmailApprovalRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectAttendeeEmailTemplate":{"get":{"summary":"Get Project Attendee Email Template Endpoint","description":"Returns the email template (subject, bodyHtml) for attendee share link emails.","operationId":"get_project_attendee_email_template_endpoint_getProjectAttendeeEmailTemplate_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/setProjectAttendeeEmailTemplate":{"put":{"summary":"Set Project Attendee Email Template Endpoint","description":"Save the email template into project_attendee_setup.","operationId":"set_project_attendee_email_template_endpoint_setProjectAttendeeEmailTemplate_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttendeeEmailTemplateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectAttendeeSetup":{"get":{"summary":"Get Project Attendee Setup Endpoint","description":"Returns auto_send_email and send_from_email for a project.","operationId":"get_project_attendee_setup_endpoint_getProjectAttendeeSetup_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/setProjectAttendeeSetup":{"put":{"summary":"Set Project Attendee Setup Endpoint","description":"Update auto_send_email and/or send_from_email on project_attendee_setup.","operationId":"set_project_attendee_setup_endpoint_setProjectAttendeeSetup_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttendeeSetupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sendAttendeeEmails":{"post":{"summary":"Send Attendee Emails Endpoint","description":"Send emails to attendees with their share link.\n- Attendee must have status in approved / approved-none / approved-Pavoot\n (or status sent/auto-sent when forceResend=true).\n- For persons with 0 images, zero_images_phrase must be provided.\n- On success: sets status to 'sent'.\n- On per-recipient failure: sets status to 'email-failed' and records last_email_error;\n continues to next recipient (returns partial success).","operationId":"send_attendee_emails_endpoint_sendAttendeeEmails_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendAttendeeEmailsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/attendee-registration-info/{token}":{"get":{"summary":"Attendee Registration Info Endpoint","description":"Public: returns project name and layout for the registration form. No auth required.","operationId":"attendee_registration_info_endpoint_attendee_registration_info__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getAttendeeRegistrationPageLayout":{"get":{"summary":"Get Attendee Registration Page Layout Endpoint","description":"Organiser: get the registration page layout for a project. Requires auth.","operationId":"get_attendee_registration_page_layout_endpoint_getAttendeeRegistrationPageLayout_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/setAttendeeRegistrationPageLayout":{"put":{"summary":"Set Attendee Registration Page Layout Endpoint","description":"Organiser: save a new registration page layout for a project. Requires manage_attendees permission.","operationId":"set_attendee_registration_page_layout_endpoint_setAttendeeRegistrationPageLayout_put","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/attendee-registration-presign-face":{"post":{"summary":"Attendee Registration Presign Face Endpoint","description":"Presigned PUT for the mandatory attendee profile photo (same S3 layout as dashboard).\nMember registration links require a signed-in Clerk user.","operationId":"attendee_registration_presign_face_endpoint_attendee_registration_presign_face_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttendeeRegistrationPresignRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/register-attendee":{"post":{"summary":"Register Attendee Endpoint","description":"Register via project registration link.\n- Public token: attendee registration only (mandatory face photo).\n- Member token: requires Clerk sign-in; attendee, startup, or both (face required when attendee is included).","operationId":"register_attendee_endpoint_register_attendee_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegisterAttendeeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getAttendeeRegistrationLink":{"get":{"summary":"Get Attendee Registration Link Endpoint","description":"Returns the public URL for the attendee registration form. Creates a token if none exists.\nRequires auth (same as manage-attendees).","operationId":"get_attendee_registration_link_endpoint_getAttendeeRegistrationLink_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deletePersons":{"delete":{"summary":"Delete Persons Endpoint","description":"Endpoint for deleting multiple persons from the system, including their database records,\nface images from S3, and faces from AWS Rekognition.\ncascadeAttendee=True also removes project_attendees and shared_links rows.","operationId":"delete_persons_endpoint_deletePersons_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeletePersonsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/editPerson":{"post":{"summary":"Edit Person Endpoint","description":"Endpoint for editing a person's information in the face recognition system.\n\nArgs:\n personId: The person's unique ID\n name: The person's name (optional)\n category: Category/type of person (optional)\n position: The person's position/role (optional)\n link: Link associated with the person (optional)\n faceImageId: New face image ID to update the face (optional)\n\nReturns:\n JSON response with success status and updated person details","operationId":"edit_person_endpoint_editPerson_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_edit_person_endpoint_editPerson_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addLogo":{"post":{"summary":"Add Logo Endpoint","description":"Endpoint for adding a new logo to a project.\n\nArgs:\n name: Logo/brand name\n projectId: Project ID\n category: Category (speaker, sponsor, etc.)\n logoImageId: S3 image ID for the logo\n image: S3 image ID (same as logoImageId)\n link: Optional link associated with the logo\n contactEmail: Optional contact email for the brand\n\nReturns:\n JSON response with success status and logo details","operationId":"add_logo_endpoint_addLogo_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_add_logo_endpoint_addLogo_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addBrand":{"post":{"summary":"Add Brand Endpoint","description":"Add a text-only brand (brands are ORG-GLOBAL; no logo image — the image never drove\ndetection). JSON body: {projectId, brandName, category?, keywords?[], contactEmail?, link?}.\n`keywords` are the text/OCR variants the AI matches; the brand name is auto-added as the\nfirst keyword. The brand's origin project is projectId; org is resolved from it.","operationId":"add_brand_endpoint_addBrand_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getProjectLogos":{"get":{"summary":"Get Project Logos Endpoint","description":"Endpoint for retrieving all logos for a project.\n\nArgs:\n projectId: The project ID\n excludeStartup: When true, rows with category \"startup\" are omitted.\n\nReturns:\n JSON response with list of logos","operationId":"get_project_logos_endpoint_getProjectLogos_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"string","title":"Projectid"}},{"name":"excludeStartup","in":"query","required":false,"schema":{"type":"boolean","description":"Omit logos with category startup (e.g. Brands page)","default":false,"title":"Excludestartup"},"description":"Omit logos with category startup (e.g. Brands page)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrgBrands":{"get":{"summary":"Get Org Brands Endpoint","description":"Org-global brands list (brands mirror the faces model). `projectIds[]` = projects the caller\ncan access (auth + org resolution + default membership scope). `filterProjectIds[]` optionally\nnarrows to brands appearing in a chosen subset. Each brand includes member_project_ids and\nimage_count.","operationId":"get_org_brands_endpoint_getOrgBrands_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"filterProjectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Filterprojectids[]"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":150,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"sort","in":"query","required":false,"schema":{"type":"string","default":"name","title":"Sort"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addBrandToProjects":{"post":{"summary":"Add Brand To Projects Endpoint","description":"Add explicit project memberships to a brand (badge-add / import). Body {logoId, projectIds[]}.","operationId":"add_brand_to_projects_endpoint_addBrandToProjects_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/removeBrandFromProject":{"post":{"summary":"Remove Brand From Project Endpoint","description":"Remove an EXPLICIT project membership from a brand. 409 if origin or photo-derived.","operationId":"remove_brand_from_project_endpoint_removeBrandFromProject_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/bulkAddBrands":{"post":{"summary":"Bulk Add Brands Endpoint","description":"Bulk create/merge brands from CSV/paste. Body {projectId, rows:[{brandName, category, keywords[]}]}.","operationId":"bulk_add_brands_endpoint_bulkAddBrands_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getOrgPotentialBrandDuplicates":{"get":{"summary":"Get Org Potential Brand Duplicates Endpoint","description":"Propose likely-duplicate brand groups (name/keyword incl. acronym/substring/token).","operationId":"get_org_potential_brand_duplicates_endpoint_getOrgPotentialBrandDuplicates_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"countOnly","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Countonly"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mergeBrands":{"post":{"summary":"Merge Brands Endpoint","description":"Merge >=2 brands into one org-global brand. Body {logo_ids[], new_name, project_id?, keep_logo_id?}.","operationId":"merge_brands_endpoint_mergeBrands_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/rejectBrandDuplicateGroup":{"post":{"summary":"Reject Brand Duplicate Group Endpoint","description":"Mark a brand duplicate group rejected (hidden). Body {project_id, logo_ids[]}.","operationId":"reject_brand_duplicate_group_endpoint_rejectBrandDuplicateGroup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/ignoreBrandDuplicateGroup":{"post":{"summary":"Ignore Brand Duplicate Group Endpoint","description":"Mark a brand duplicate group ignored (hidden). Body {project_id, logo_ids[]}.","operationId":"ignore_brand_duplicate_group_endpoint_ignoreBrandDuplicateGroup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/pushPersonToBrand":{"post":{"summary":"Push Person To Brand Endpoint","description":"Migration helper: convert a mislabeled PERSON (e.g. \"Mercedes\" wrongly tagged as a person)\ninto an org-global BRAND. For every image where the person appears, adds a brand tag with\nthe same name (so the images keep the association, just re-categorized person -> brand),\nregisters (or merges into) the org brand of that name (union of project memberships), then\ndeletes the person (cascading its face boxes + Rekognition entry). Body: {personId}.","operationId":"push_person_to_brand_endpoint_pushPersonToBrand_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/editLogo":{"post":{"summary":"Edit Logo Endpoint","description":"Endpoint for editing a logo's information.\n\nArgs:\n personId: The logo ID (frontend uses personId)\n name: New brand name (optional)\n category: When sent, updates category (empty -> brand). Omit to leave unchanged.\n link: When sent, updates link (empty clears). Omit to leave unchanged.\n contactEmail: When sent, updates contact email (empty clears). Omit to leave unchanged.\n\nReturns:\n JSON response with success status and updated logo details","operationId":"edit_logo_endpoint_editLogo_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_edit_logo_endpoint_editLogo_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteLogo":{"delete":{"summary":"Delete Logo Endpoint","description":"Delete brands, and the brand tags on their photos.\n\nBody, either shape:\n [logoId, ...] -> legacy, means scope=\"all\"\n {\"logoIds\": [...], \"scope\": \"all\"|\"project\",\n \"projectId\": }\n\nscope=\"project\" removes the brand from that ONE project: the tags on its photos, that\nproject's folder, and the project from the brand's membership. The brand survives elsewhere.\nscope=\"all\" removes the brand outright, everywhere.\n\nDeleting the tags is deliberate and unrecoverable — see delete_brand_scoped. The client is\nexpected to have shown brand_deletion_impact() first, which is what /brandDeletionImpact is\nfor; this endpoint does not assume it and simply does what it is told.","operationId":"delete_logo_endpoint_deleteLogo_delete","requestBody":{"content":{"application/json":{"schema":{"title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brandDeletionImpact":{"get":{"summary":"Brand Deletion Impact Endpoint","description":"What deleting these brands would destroy — for the confirmation dialog.\n\nRead-only. Gated the same way the delete is, so it cannot be used to probe brands in projects\nthe caller has no business seeing.","operationId":"brand_deletion_impact_endpoint_brandDeletionImpact_get","parameters":[{"name":"logoIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Logoids[]"}},{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/generateBrandFolders":{"post":{"summary":"Generate Brand Folders Endpoint","description":"Creates missing project_folders for all brands in the logos table (admin-only).\nUse this to repair folders if they are out of sync.","operationId":"generate_brand_folders_endpoint_generateBrandFolders_post","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addLogoTranscription":{"post":{"summary":"Add Logo Transcription Endpoint","operationId":"add_logo_transcription_endpoint_addLogoTranscription_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_logo_transcription_endpoint_addLogoTranscription_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteLogoTranscription":{"delete":{"summary":"Delete Logo Transcription Endpoint","operationId":"delete_logo_transcription_endpoint_deleteLogoTranscription_delete","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_logo_transcription_endpoint_deleteLogoTranscription_delete"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateLogoTranscription":{"put":{"summary":"Update Logo Transcription Endpoint","operationId":"update_logo_transcription_endpoint_updateLogoTranscription_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_logo_transcription_endpoint_updateLogoTranscription_put"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/trainLogo":{"post":{"summary":"Train Logo Endpoint","description":"Endpoint for queuing a logo training task to SQS.\n\nArgs:\n logoId: The logo ID to train\n projectId: The project ID\n\nReturns:\n JSON response with success status","operationId":"train_logo_endpoint_trainLogo_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_train_logo_endpoint_trainLogo_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/internal/logoTrainingStatus":{"post":{"summary":"Update Logo Training Status Endpoint","operationId":"update_logo_training_status_endpoint_internal_logoTrainingStatus_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/internal/logoInfo":{"get":{"summary":"Get Logo Info Endpoint","operationId":"get_logo_info_endpoint_internal_logoInfo_get","parameters":[{"name":"logoId","in":"query","required":true,"schema":{"type":"string","title":"Logoid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/changePersonCategory":{"put":{"summary":"Change Person Category Endpoint","description":"Change a person's creation type between 'user_added' and 'auto_detected'.\n\nArgs:\n personId: The person's unique ID\n newCategory: The new creation type ('user_added' or 'auto_detected')\n\nReturns:\n JSON response with success status and updated person details","operationId":"change_person_category_endpoint_changePersonCategory_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_change_person_category_endpoint_changePersonCategory_put"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getStorage":{"get":{"summary":"Get Storage Endpoint","description":"Returns used storage (GB) and limit (GB) for the relevant organization.\n\n- mode=event_organizer: use auth user's id as event_organizer_id, resolve to organization.\n- mode=photographer: require projectId, resolve one event_organizer from event_organizer_projects, then their organization.\n\nOnly event_organizer, photographer, and admin roles may call this; recipients are not allowed.","operationId":"get_storage_endpoint_getStorage_get","parameters":[{"name":"mode","in":"query","required":true,"schema":{"type":"string","description":"event_organizer or photographer","title":"Mode"},"description":"event_organizer or photographer"},{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Required when mode=photographer","title":"Projectid"},"description":"Required when mode=photographer"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectStorage":{"get":{"summary":"Get Project Storage Endpoint","description":"Returns storage breakdown for a project: normal (non-deleted) and trash (deleted) images.\n\nReturns:\n dict with:\n - normalGb: storage used by non-deleted images\n - trashGb: storage used by deleted images\n - totalGb: total storage (normal + trash)","operationId":"get_project_storage_endpoint_getProjectStorage_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","description":"Project ID","title":"Projectid"},"description":"Project ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getProjectOrganizationInfo":{"get":{"summary":"Get Project Organization Info Endpoint","description":"Returns the organization name, ID, and effective Rekognition collection ID for a project.\nUsed for client-side debugging to verify which collection faces are indexed into.","operationId":"get_project_organization_info_endpoint_getProjectOrganizationInfo_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","description":"Project ID","title":"Projectid"},"description":"Project ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrganizationLimitsAndUsage":{"get":{"summary":"Get Organization Limits And Usage Endpoint","description":"Returns organization limits and current usage: storage, share links, event organizers,\nphotographers, and upload (image tagging). For use on the project page header.\n\n- mode=event_organizer: use auth user's id, resolve to organization.\n- mode=photographer: require projectId, resolve one event_organizer from event_organizer_projects, then their organization.","operationId":"get_organization_limits_and_usage_endpoint_getOrganizationLimitsAndUsage_get","parameters":[{"name":"mode","in":"query","required":true,"schema":{"type":"string","description":"event_organizer or photographer","title":"Mode"},"description":"event_organizer or photographer"},{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Required when mode=photographer","title":"Projectid"},"description":"Required when mode=photographer"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getEventOrganizerImageTagging":{"get":{"summary":"Get Event Organizer Image Tagging Endpoint","description":"Returns the current number of tagged images and image tagging limit for an event organizer.\n\nQuery params:\n- eventOrganizerId: the event organizer id\n\nReturns:\n- eventOrganizerId: the event organizer id\n- currentTaggedImages: current number of images queued for tagging\n- imageTaggingLimit: the image tagging limit","operationId":"get_event_organizer_image_tagging_endpoint_getEventOrganizerImageTagging_get","parameters":[{"name":"eventOrganizerId","in":"query","required":true,"schema":{"type":"string","title":"Eventorganizerid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/checkUploadLimit":{"get":{"summary":"Check Upload Limit Endpoint","description":"Check if an upload would exceed the relevant organization's storage and image tagging limits.\n\nMode is derived from the authenticated user's role (not from a query param):\n- event_organizer: use auth user as event organizer; projectId is not used.\n- photographer: projectId is required; resolve event organizer from event_organizer_projects for that project.\n- admin: projectId is required; same as photographer (project's org limits).\n\nOnly event_organizer, photographer, and admin may call. Recipients cannot upload.","operationId":"check_upload_limit_endpoint_checkUploadLimit_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Required for photographer and admin; optional for event_organizer","title":"Projectid"},"description":"Required for photographer and admin; optional for event_organizer"},{"name":"uploadSizeMb","in":"query","required":true,"schema":{"type":"number","title":"Uploadsizemb"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getEventOrganizerName":{"get":{"summary":"Get Event Organizer Name Endpoint","description":"Returns the current user's event organizer name from the database, if they are an event organizer.\nUsed e.g. for the \"Regards\" field when inviting photographers.","operationId":"get_event_organizer_name_endpoint_getEventOrganizerName_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/isUserActive":{"get":{"summary":"Is User Active Endpoint","description":"Checks if a user is active (not expired).\n\nArgs:\n user_id: The user's ID\n role: The user's role ('event_organizer', 'photographer', or 'recipient')\n \nReturns:\n JSON response with 'is_active' boolean","operationId":"is_user_active_endpoint_isUserActive_get","parameters":[{"name":"user_id","in":"query","required":true,"schema":{"type":"string","title":"User Id"}},{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/insertFace":{"post":{"summary":"Insert Face","description":"Insert a detected face occurrence into image_faces table","operationId":"insert_face_insertFace_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FaceOccurrenceCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Insert Face Insertface Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getFaces":{"get":{"summary":"Get Faces Endpoint","description":"Retrieves all detected faces (bounding boxes and person IDs) for a given image.","operationId":"get_faces_endpoint_getFaces_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getTextExtraction":{"get":{"summary":"Get Text Extraction Endpoint","description":"Retrieves all text extraction results (bounding boxes and text) for a given image.","operationId":"get_text_extraction_endpoint_getTextExtraction_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/getPersonFaces":{"get":{"summary":"Get Person Faces Endpoint","description":"Returns faces for the given person. For photographer role, only returns faces from that photographer's images.","operationId":"get_person_faces_endpoint_getPersonFaces_get","parameters":[{"name":"personId","in":"query","required":true,"schema":{"type":"string","title":"Personid"}},{"name":"projectId","in":"query","required":true,"schema":{"type":"string","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/assignFace":{"put":{"summary":"Assign Face Endpoint","description":"Assign or rename a face/person based on 4 explicit scenarios:\n\n- single_new: only this face → create new person\n- single_existing: only this face → assign to existing person\n- all_new: rename this entire person to a new name\n- all_existing: merge this entire person into an existing person","operationId":"assign_face_endpoint_assignFace_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssignFaceRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/findDuplicatePersons":{"get":{"summary":"Find Duplicate Persons","description":"Find duplicate person names within a project.\nReturns a list of names that appear more than once, with counts and person_ids.","operationId":"find_duplicate_persons_findDuplicatePersons_get","parameters":[{"name":"project_id","in":"query","required":true,"schema":{"type":"integer","description":"Project ID to check for duplicate names","title":"Project Id"},"description":"Project ID to check for duplicate names"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteFace":{"delete":{"summary":"Delete Face Endpoint","description":"Deletes a face from an image.\nModes:\n- \"box\": Delete the face bounding box completely\n- \"name\": Keep the box but reset the person name to \"?\"","operationId":"delete_face_endpoint_deleteFace_delete","parameters":[{"name":"faceId","in":"query","required":true,"schema":{"type":"string","title":"Faceid"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"box","title":"Mode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrphanedPersons":{"get":{"summary":"Get Orphaned Persons Endpoint","description":"Retrieves all orphaned persons (persons with no face references) for a project.","operationId":"get_orphaned_persons_endpoint_getOrphanedPersons_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getPotentialDuplicates":{"get":{"summary":"Get Potential Duplicates Endpoint","description":"Retrieves potential duplicate persons based on name similarity for a project.","operationId":"get_potential_duplicates_endpoint_getPotentialDuplicates_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrgOrphanedPersons":{"get":{"summary":"Get Org Orphaned Persons Endpoint","description":"Org-wide orphaned persons (faces are org-global). Org resolved from projectIds[0].","operationId":"get_org_orphaned_persons_endpoint_getOrgOrphanedPersons_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrgPotentialDuplicates":{"get":{"summary":"Get Org Potential Duplicates Endpoint","description":"Org-wide name-duplicate suggestions. Mirrors /getPotentialDuplicates but scoped by\norganization (all org persons). Crop URLs use each person's origin project_id.\n\nWhen countOnly is set, the (still-required) name-similarity pass runs but per-person\nS3 presigned crop URLs are skipped and only `{success, count}` is returned — cheap enough\nfor a background badge fetch on the faces page.","operationId":"get_org_potential_duplicates_endpoint_getOrgPotentialDuplicates_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"countOnly","in":"query","required":false,"schema":{"type":"boolean","description":"Return only the group count (skips S3 crop URLs) — used for the /faces badge.","default":false,"title":"Countonly"},"description":"Return only the group count (skips S3 crop URLs) — used for the /faces badge."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mergePersons":{"post":{"summary":"Merge Persons Endpoint","description":"Merges multiple persons into a single person.","operationId":"merge_persons_endpoint_mergePersons_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Merge Data"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/rejectNameDuplicateGroup":{"post":{"summary":"Reject Name Duplicate Group Endpoint","description":"Set name-duplicate suggestion status to rejected (same as face_match_suggestions).","operationId":"reject_name_duplicate_group_endpoint_rejectNameDuplicateGroup_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ignoreNameDuplicateGroup":{"post":{"summary":"Ignore Name Duplicate Group Endpoint","description":"Set name-duplicate suggestion status to ignored (same as face_match_suggestions).","operationId":"ignore_name_duplicate_group_endpoint_ignoreNameDuplicateGroup_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scanExistingFacesForPerson":{"post":{"summary":"Scan Existing Faces For Person Endpoint","description":"Starts a background job to scan existing stored faces for matches to the given person.\nUsed after registering a new person (if checkbox enabled) or via manual \"Search for duplicate faces\" button.\nReturns immediately; scan runs asynchronously.","operationId":"scan_existing_faces_for_person_endpoint_scanExistingFacesForPerson_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scanUnknownFacesForMatches":{"post":{"summary":"Scan Unknown Faces For Matches Endpoint","description":"Scans all persons with name '?' (unknown) and finds Rekognition matches to named persons.\nCreates face_match_suggestions so user can approve merging unknown into known (giving unknown a name).\nRuns in background; returns immediately.","operationId":"scan_unknown_faces_for_matches_endpoint_scanUnknownFacesForMatches_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scanAllFacesForMatches":{"post":{"summary":"Scan All Faces For Matches Endpoint","description":"Scans all persons with a face_id and finds Rekognition matches to other persons.\nSearch includes all images (labeled and unlabeled); no exclusion of folder/tagged images.\nCreates face_match_suggestions so user can approve merging duplicate faces (any pair).\nRuns in background; returns immediately.","operationId":"scan_all_faces_for_matches_endpoint_scanAllFacesForMatches_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getFaceMatchSuggestions":{"get":{"summary":"Get Face Match Suggestions Endpoint","description":"Returns face match suggestions for the project (for review/approve/reject UI).","operationId":"get_face_match_suggestions_endpoint_getFaceMatchSuggestions_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","description":"pending | rejected | approved | ignored | all","default":"pending","title":"Status Filter"},"description":"pending | rejected | approved | ignored | all"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/scanOrgFacesForMatches":{"post":{"summary":"Scan Org Faces For Matches Endpoint","description":"Org-wide duplicate scan: proposes merges between the same real person registered\nseparately across the org's projects. Writes pending face_match_suggestions only —\nnever merges automatically. Runs in the background; returns 202 immediately.","operationId":"scan_org_faces_for_matches_endpoint_scanOrgFacesForMatches_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getOrgFaceMatchSuggestions":{"get":{"summary":"Get Org Face Match Suggestions Endpoint","description":"Org-wide face match suggestions (cross-project duplicates). Face crop + sample URLs are\nbuilt from each person's ORIGIN project prefix, so cross-project crops resolve correctly.","operationId":"get_org_face_match_suggestions_endpoint_getOrgFaceMatchSuggestions_get","parameters":[{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"status_filter","in":"query","required":false,"schema":{"type":"string","description":"pending | rejected | approved | ignored | all","default":"pending","title":"Status Filter"},"description":"pending | rejected | approved | ignored | all"},{"name":"countOnly","in":"query","required":false,"schema":{"type":"boolean","description":"Return only the suggestion count (cheap COUNT, no crop/sample URLs) — used for the /faces badge.","default":false,"title":"Countonly"},"description":"Return only the suggestion count (cheap COUNT, no crop/sample URLs) — used for the /faces badge."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/approveFaceMatchSuggestion":{"post":{"summary":"Approve Face Match Suggestion Endpoint","description":"Approve a face match suggestion: merge candidate person into reference person\n(reassign all image_faces from candidate to reference, delete candidate person and their Rekognition face).\nOptional chosen_name: set the reference person's name to this after merge (e.g. user-selected name).\n\nProcess: (1) DB transaction: reassign image_faces, delete suggestion and candidate person, update name/folder.\n(2) Rekognition: delete candidate face from collection. (3) Emits (person.folders, persons.updated,\nface_match_suggestions.updated) run in a background task so the response returns immediately; previously\nget_project_persons (which built presigned URLs for every person) ran inline and could take many seconds on large projects.","operationId":"approve_face_match_suggestion_endpoint_approveFaceMatchSuggestion_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/rejectFaceMatchSuggestion":{"post":{"summary":"Reject Face Match Suggestion Endpoint","description":"Mark suggestion as rejected so it does not appear again.","operationId":"reject_face_match_suggestion_endpoint_rejectFaceMatchSuggestion_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/ignoreFaceMatchSuggestion":{"post":{"summary":"Ignore Face Match Suggestion Endpoint","description":"Mark suggestion as ignored (user chose not to merge but not explicitly reject).","operationId":"ignore_face_match_suggestion_endpoint_ignoreFaceMatchSuggestion_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getPersons":{"get":{"summary":"Get Persons Endpoint","description":"Retrieves persons for a project.\n\nReturns every person by default, as it always has; `limit`/`offset` are opt-in and\nthe response carries `total`/`hasMore` so a caller can page when it wants to.","operationId":"get_persons_endpoint_getPersons_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getPersonFolders":{"get":{"summary":"Get Person Folders Endpoint","description":"Fetches person folders based on image_faces data.\nOnly returns folders with >0 images and handles duplicate names.","operationId":"get_person_folders_endpoint_getPersonFolders_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/createShareLink":{"post":{"summary":"Create Share Link","operationId":"create_share_link_createShareLink_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getShares":{"get":{"summary":"Get Shares","operationId":"get_shares_getShares_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","default":25,"title":"Pagesize"}},{"name":"sortBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"created_desc","title":"Sortby"}},{"name":"search","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search"}},{"name":"category","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},{"name":"type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Type"}},{"name":"createdBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Createdby"}},{"name":"light","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Light"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/updateShare":{"patch":{"summary":"Update Share","operationId":"update_share_updateShare_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews":{"get":{"summary":"List Reviews Endpoint","description":"Reviews overview: one row per share link with a review enabled.\n\nThe top level of the review surface. Flags take effect the moment a recipient sets them, so\nthe team's actual question is \"where do my reviews stand\" — which are open, who responded,\nhow much came back — rather than a wall of every rejected image.","operationId":"list_reviews_endpoint_reviews_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews/flags":{"get":{"summary":"List Review Flags Endpoint","description":"Active do-not-publish flags with provenance, for the Review page.\n\nScope by share link (the jump from the share editor) or by project(s). All-Projects mode\npasses projectIds[] the same way /getShares does; the set is then narrowed to the projects\nwhere the caller actually holds sharelinks.review.manage, so a union can never surface\nflags from a project they can't manage.","operationId":"list_review_flags_endpoint_reviews_flags_get","parameters":[{"name":"projectId","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"}},{"name":"projectIds[]","in":"query","required":false,"schema":{"type":"array","items":{"type":"integer"},"default":[],"title":"Projectids[]"}},{"name":"shareId","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Shareid"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Pagesize"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews/flags/clear":{"post":{"summary":"Clear Review Flags Endpoint","description":"\"Approve anyway\": clear flags so the images become visible again.\n\nAuthorised per flag: a caller may only clear flags on images in projects where they hold\nsharelinks.review.manage, so a cross-project Review page can't be used to clear someone\nelse's flags by id. Sets cleared_at rather than deleting, keeping the decision history.","operationId":"clear_review_flags_endpoint_reviews_flags_clear_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClearReviewFlagsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews/close":{"post":{"summary":"Close Review Endpoint","description":"Stop the recipient flagging on a link.\n\nThis is the manual lock the client asked for instead of a deadline — management can take\ndays, and the review ends when the team says so. Closing does NOT break the link: viewing\nand downloads keep working, only the flag tool disappears.","operationId":"close_review_endpoint_reviews_close_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewLifecycleRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/reviews/reopen":{"post":{"summary":"Reopen Review Endpoint","description":"Reopen a closed review so the recipient can flag again.","operationId":"reopen_review_endpoint_reviews_reopen_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewLifecycleRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/deleteShare":{"delete":{"summary":"Delete Share","operationId":"delete_share_deleteShare_delete","parameters":[{"name":"id","in":"query","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/getShare/{id}/manage":{"get":{"summary":"Get Share Manage","description":"Authed single-fetch of a share link with everything the full-page editor needs.","operationId":"get_share_manage_getShare__id__manage_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shares/{id}/images":{"get":{"summary":"Get Share Content Images","description":"Paginated content of a share link (the editor's right-pane grid): filename + timestamp + thumbnail.","operationId":"get_share_content_images_shares__id__images_get","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1,"title":"Page"}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","default":40,"title":"Pagesize"}},{"name":"sortBy","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"newest","title":"Sortby"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shares/{id}/snapshot":{"post":{"summary":"Snapshot Share","description":"Freeze a scoped (auto-updating) link into a static one: materialize the current visible\nset into image_ids, then null the scope and clear include/exclude. Stops auto-updates.","operationId":"snapshot_share_shares__id__snapshot_post","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shares/create":{"post":{"summary":"Create Hybrid Share","description":"Create a combinable link in one call: folders/people scope (auto-updating) AND/OR\nmanually-selected images. Scope requires a concrete projectId; explicit-only images may\nbe cross-project (representative project is stored, like /createShareLink).","operationId":"create_hybrid_share_shares_create_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateHybridShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shares/preview":{"post":{"summary":"Preview Share","description":"Live preview for the create/edit builder: resolves the exact set of images a link WOULD\ncontain (scope resolved within its project + individual images cross-project), returning the\ntotal count and a handful of thumbnails. No link is created.","operationId":"preview_share_shares_preview_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SharePreviewRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/addImagesToShare":{"post":{"summary":"Add Images To Share","operationId":"add_images_to_share_addImagesToShare_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddImagesToShareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/shares/generate":{"post":{"summary":"Generate Share Links","description":"Generates one or multiple share links based on person IDs and folder names.\n\nLogic:\n- Person images: images where image_faces.person_id matches\n- folderNames: tag values (uncategorized folders, brands, custom options — not only project_folders).\n Images: tagged with that name AND \"Highlights\" (general). Locked tags on images are excluded\n on the share page/download unless unlocked for that link (sharelink_unlocked_tags).\n- Final set: personMedia ∪ tagMedia (deduplicated)\n\nIf mode=\"per_person\": creates one share per personId with label=person.name\nIf mode=\"all_in_one\": creates one share with all selected persons + folders\nIf no people and customTagLinkMode=\"per_option\" with 2+ custom tag options selected:\none share per option; each share includes the same folders/brands plus that option.\nLabels use labelStrategyCustomFolder (e.g. category_option → \"Category - Option\").","operationId":"generate_share_links_shares_generate_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateShareLinksRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/isAdmin":{"get":{"summary":"Admin Is Admin","operationId":"admin_is_admin_admin_isAdmin_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/me":{"get":{"summary":"Get Me","description":"Resolve the authenticated Clerk user's membership in THIS app.\n\nClerk is shared across multiple Pavoot apps, so a valid Clerk session does\nNOT imply the user belongs here. The frontend uses this to gate the app\nshell: a signed-in user with no membership is signed out rather than being\ndropped into (and shown cached data from) an app they don't belong to.\n\nMembership is derived from this app's database only — never from the\n(cross-app) Clerk public_metadata role.","operationId":"get_me_me_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/event-organizers":{"get":{"summary":"Admin Event Organizers","operationId":"admin_event_organizers_admin_event_organizers_get","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string","default":"","title":"Query"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/projects":{"get":{"summary":"Admin Projects","operationId":"admin_projects_admin_projects_get","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string","default":"","title":"Query"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/projects/{project_id}/set-primary-organizer":{"patch":{"summary":"Admin Set Primary Organizer","operationId":"admin_set_primary_organizer_admin_projects__project_id__set_primary_organizer_patch","parameters":[{"name":"project_id","in":"path","required":true,"schema":{"type":"integer","title":"Project Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/photographers":{"get":{"summary":"Admin Photographers","description":"List photographers that are NOT event organizers.\nOnly returns photographers that exist in photographers table\nbut NOT in event_organizers table.","operationId":"admin_photographers_admin_photographers_get","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string","default":"","title":"Query"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/delete-photographer":{"delete":{"summary":"Admin Delete Photographer Endpoint","description":"Delete a photographer completely.\nThis removes:\n- Entries from photographer_projects table\n- Entry from photographers table\n- Clerk user account\n\nNote: Only deletes photographers that are NOT event organizers.\nEvent organizers should be deleted via delete-organizer endpoint.\n\nQuery Parameters:\n photographerId (str): The Clerk user ID of the photographer to delete (required)","operationId":"admin_delete_photographer_endpoint_admin_delete_photographer_delete","parameters":[{"name":"photographerId","in":"query","required":true,"schema":{"type":"string","description":"The Clerk user ID of the photographer to delete","title":"Photographerid"},"description":"The Clerk user ID of the photographer to delete"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/recipients":{"get":{"summary":"Admin Recipients","description":"List recipients that are NOT event organizers or photographers.\nOnly returns recipients that exist in recipients table\nbut NOT in event_organizers or photographers tables.","operationId":"admin_recipients_admin_recipients_get","parameters":[{"name":"query","in":"query","required":false,"schema":{"type":"string","default":"","title":"Query"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/delete-recipient":{"delete":{"summary":"Admin Delete Recipient Endpoint","description":"Delete a recipient completely.\nThis removes:\n- Entries from recipient_projects table\n- Entry from recipients table\n- Clerk user account\n\nNote: Only deletes recipients that are NOT event organizers or photographers.\nEvent organizers should be deleted via delete-organizer endpoint.\nPhotographers should be deleted via delete-photographer endpoint.\n\nQuery Parameters:\n recipientId (str): The Clerk user ID of the recipient to delete (required)","operationId":"admin_delete_recipient_endpoint_admin_delete_recipient_delete","parameters":[{"name":"recipientId","in":"query","required":true,"schema":{"type":"string","description":"The Clerk user ID of the recipient to delete","title":"Recipientid"},"description":"The Clerk user ID of the recipient to delete"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations":{"get":{"summary":"Admin Organizations","description":"List organizations with their limits and attached organizers.","operationId":"admin_organizations_admin_organizations_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Admin Create Organization","description":"Create an organization with a name, storage, and image tagging limits.\nAutomatically creates a dedicated Rekognition collection for the org.","operationId":"admin_create_organization_admin_organizations_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/create-organizer":{"post":{"summary":"Admin Create Organizer Endpoint","operationId":"admin_create_organizer_endpoint_admin_create_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/delete-organizer":{"delete":{"summary":"Admin Delete Organizer Endpoint","description":"Delete an event organizer completely.\nThis removes:\n- Entries from event_organizer_projects table\n- Entries from photographer_projects table\n- Entry from organization_event_organizers table (if any)\n- Entry from event_organizers table\n- Entry from photographers table\n- Clerk user account\n\nQuery Parameters:\n eventOrganizerId (str): The Clerk user ID of the event organizer to delete (required)","operationId":"admin_delete_organizer_endpoint_admin_delete_organizer_delete","parameters":[{"name":"eventOrganizerId","in":"query","required":true,"schema":{"type":"string","description":"The Clerk user ID of the event organizer to delete","title":"Eventorganizerid"},"description":"The Clerk user ID of the event organizer to delete"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}":{"patch":{"summary":"Admin Update Organization","description":"Update an organization's name and limits.","operationId":"admin_update_organization_admin_organizations__organization_id__patch","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Admin Delete Organization","description":"Delete an organization. Event organizer mappings are removed via ON DELETE CASCADE.","operationId":"admin_delete_organization_admin_organizations__organization_id__delete","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/create-rekognition-collection":{"post":{"summary":"Admin Create Org Rekognition Collection","description":"Create a new Rekognition collection for this organization and save its ID to the DB.\nAuto-generates the collection ID as 'pavoot-{env}-{org-name-slug}' where env comes\nfrom the request body (dev/staging/prod, detected client-side from the browser hostname).\nReturns an error if the org already has a custom collection set.\nMigrates existing faces from the org's projects into the new collection as a background task.","operationId":"admin_create_org_rekognition_collection_admin_organizations__organization_id__create_rekognition_collection_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCollectionBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/collection-faces":{"get":{"summary":"Admin Get Org Collection Faces","description":"List all faces in the Rekognition collection used by this organization.\nUses the org's custom collection if set, otherwise the global default.\nPaginates through the entire collection and returns face count + face list.","operationId":"admin_get_org_collection_faces_admin_organizations__organization_id__collection_faces_get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/missing-faces":{"get":{"summary":"Admin Get Org Missing Faces","description":"Returns persons in the org's projects who have a face_image_id but are NOT yet indexed\nin the org's custom Rekognition collection. Used to identify faces that need migration.\nRequires the org to have a custom collection (rekognition_collection_id not null).","operationId":"admin_get_org_missing_faces_admin_organizations__organization_id__missing_faces_get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/migrate-missing-faces":{"post":{"summary":"Admin Migrate Missing Faces","description":"Re-indexes into the org's custom collection all persons who have a face_image_id\nbut are not yet indexed there. Starts in background; poll migration-progress for updates.\nDoes NOT remove faces from the default collection (safe, non-destructive).","operationId":"admin_migrate_missing_faces_admin_organizations__organization_id__migrate_missing_faces_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/migration-progress":{"get":{"summary":"Admin Migration Progress","description":"Returns the current migration progress for an org (populated by migrate-missing-faces).","operationId":"admin_migration_progress_admin_organizations__organization_id__migration_progress_get","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/add-organizer":{"post":{"summary":"Admin Add Organizer To Organization","description":"Assign an event organizer to an organization.","operationId":"admin_add_organizer_to_organization_admin_organizations__organization_id__add_organizer_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/organizations/{organization_id}/remove-organizer":{"post":{"summary":"Admin Remove Organizer From Organization","description":"Remove an event organizer from an organization.","operationId":"admin_remove_organizer_from_organization_admin_organizations__organization_id__remove_organizer_post","parameters":[{"name":"organization_id","in":"path","required":true,"schema":{"type":"integer","title":"Organization Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/assign-organizer":{"post":{"summary":"Admin Assign Organizer Endpoint","operationId":"admin_assign_organizer_endpoint_admin_assign_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/can-manage-organizers":{"get":{"summary":"Org Can Manage Organizers Endpoint","description":"Lightweight gate for the frontend: does the caller hold the manage-organizers permission?","operationId":"org_can_manage_organizers_endpoint_org_can_manage_organizers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/org/branding":{"get":{"summary":"Org Branding Get Endpoint","description":"Current share-link branding for the caller's org (or any org for super-admin).","operationId":"org_branding_get_endpoint_org_branding_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Org Branding Set Endpoint","description":"Set the org's share-link branding.\n\n- Upload ``file`` to replace the logo (old S3 object deleted best-effort).\n- Pass ``removeLogo=true`` to clear the logo.\n- ``logoLinkUrl`` (when the field is present) sets the click-through URL; an\n empty value clears it. Omit the field entirely to leave it unchanged.","operationId":"org_branding_set_endpoint_org_branding_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_org_branding_set_endpoint_org_branding_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/event-organizers":{"get":{"summary":"Org Event Organizers Endpoint","description":"List the event organizers in an organization (own org, or any org for super-admin).","operationId":"org_event_organizers_endpoint_org_event_organizers_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/photographers":{"get":{"summary":"Org Photographers Endpoint","description":"List all photographers appearing on any project in the organization (org-wide).\nPowers the permissions console's people list alongside organizers.","operationId":"org_photographers_endpoint_org_photographers_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/managers":{"get":{"summary":"Org Managers Endpoint","description":"List the org's organizers with whether each is an org-manager (holds the\norg.manage.organizers grant). An org-manager can see and change these for their\nown org; a super-admin can target any org via organizationId.","operationId":"org_managers_endpoint_org_managers_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/managers/set":{"post":{"summary":"Org Managers Set Endpoint","description":"Grant or revoke org-manager status for a member of the caller's org.\n\nGuard: never remove the LAST remaining org-manager (that would lock the whole\norganization out of managing itself).","operationId":"org_managers_set_endpoint_org_managers_set_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/projects":{"get":{"summary":"Org Projects Endpoint","description":"List the projects belonging to an organization (own org, or any org for super-admin).","operationId":"org_projects_endpoint_org_projects_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/create-organizer":{"post":{"summary":"Org Create Organizer Endpoint","description":"Create an organizer pinned to the caller's org. Org cannot be chosen by the client.","operationId":"org_create_organizer_endpoint_org_create_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/update-organizer":{"patch":{"summary":"Org Update Organizer Endpoint","description":"Update name/description of an organizer that belongs to the caller's org.","operationId":"org_update_organizer_endpoint_org_update_organizer_patch","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/assign-organizer":{"post":{"summary":"Org Assign Organizer Endpoint","description":"Assign an in-org organizer to one or more in-org projects.","operationId":"org_assign_organizer_endpoint_org_assign_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/unassign-organizer":{"post":{"summary":"Org Unassign Organizer Endpoint","description":"Remove an in-org organizer from one or more in-org projects.","operationId":"org_unassign_organizer_endpoint_org_unassign_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/remove-organizer":{"post":{"summary":"Org Remove Organizer Endpoint","description":"Remove an organizer from the caller's organization: revokes all project\naccess and the org membership, but keeps the underlying account (reversible\nby re-adding). Does NOT delete the Clerk user.","operationId":"org_remove_organizer_endpoint_org_remove_organizer_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/tasks":{"get":{"summary":"Org Permissions Tasks Endpoint","operationId":"org_permissions_tasks_endpoint_org_permissions_tasks_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/user-matrix":{"get":{"summary":"Org Permissions User Matrix Endpoint","description":"Org-wide per-user permission matrix (role defaults + org-level overrides).","operationId":"org_permissions_user_matrix_endpoint_org_permissions_user_matrix_get","parameters":[{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}},{"name":"userId","in":"query","required":true,"schema":{"type":"string","title":"Userid"}},{"name":"projectId","in":"query","required":false,"schema":{"type":"integer","title":"Projectid"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}},{"name":"mode","in":"query","required":false,"schema":{"type":"string","default":"edit","title":"Mode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/user":{"patch":{"summary":"Org Permissions Patch User Endpoint","description":"Set org-wide per-user permission overrides (applies across the org's projects).","operationId":"org_permissions_patch_user_endpoint_org_permissions_user_patch","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/search-members":{"get":{"summary":"Org Permissions Search Members Endpoint","operationId":"org_permissions_search_members_endpoint_org_permissions_search_members_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}},{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/role-matrix":{"get":{"summary":"Org Permissions Role Matrix Endpoint","description":"A role's default permissions on a project — used to pre-fill a NEW role\nfrom the current defaults for that role (what's active for everyone today).","operationId":"org_permissions_role_matrix_endpoint_org_permissions_role_matrix_get","parameters":[{"name":"projectId","in":"query","required":true,"schema":{"type":"integer","title":"Projectid"}},{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permission-presets":{"get":{"summary":"Org List Permission Presets Endpoint","operationId":"org_list_permission_presets_endpoint_org_permission_presets_get","parameters":[{"name":"role","in":"query","required":true,"schema":{"type":"string","title":"Role"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Org Create Permission Preset Endpoint","operationId":"org_create_permission_preset_endpoint_org_permission_presets_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permission-presets/{preset_id}":{"get":{"summary":"Org Get Permission Preset Endpoint","description":"A single preset's full effective map, for pre-loading the role editor. Org-scoped.","operationId":"org_get_permission_preset_endpoint_org_permission_presets__preset_id__get","parameters":[{"name":"preset_id","in":"path","required":true,"schema":{"type":"integer","title":"Preset Id"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Org Update Permission Preset Endpoint","description":"Edit a role IN PLACE (keeps its id, so linked members stay linked and pick up\nthe change live).","operationId":"org_update_permission_preset_endpoint_org_permission_presets__preset_id__patch","parameters":[{"name":"preset_id","in":"path","required":true,"schema":{"type":"integer","title":"Preset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Org Delete Permission Preset Endpoint","operationId":"org_delete_permission_preset_endpoint_org_permission_presets__preset_id__delete","parameters":[{"name":"preset_id","in":"path","required":true,"schema":{"type":"integer","title":"Preset Id"}},{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permission-presets/set-default":{"post":{"summary":"Org Set Default Preset Endpoint","description":"Star a role (preset) as the org's default for its role type — auto-selected\nwhen adding members. presetId 0 → the built-in Default (clears any starred preset).","operationId":"org_set_default_preset_endpoint_org_permission_presets_set_default_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permission-presets/apply":{"post":{"summary":"Org Apply Permission Preset Endpoint","operationId":"org_apply_permission_preset_endpoint_org_permission_presets_apply_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/role-assignments":{"get":{"summary":"Org Permissions Role Assignments Endpoint","description":"Which role (preset) each member currently has — for color-coding the list.","operationId":"org_permissions_role_assignments_endpoint_org_permissions_role_assignments_get","parameters":[{"name":"organizationId","in":"query","required":false,"schema":{"type":"integer","title":"Organizationid"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/org/permissions/assign-role":{"post":{"summary":"Org Permissions Assign Role Endpoint","description":"Assign a role (preset) to a member: apply the preset across every project the\nmember belongs to in this org, then record the assignment for the UI.","operationId":"org_permissions_assign_role_endpoint_org_permissions_assign_role_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/admins":{"get":{"summary":"Admin List Admins Endpoint","operationId":"admin_list_admins_endpoint_admin_admins_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/admin/admins/add":{"post":{"summary":"Admin Add Admin Endpoint","operationId":"admin_add_admin_endpoint_admin_admins_add_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/admin/admins/remove":{"post":{"summary":"Admin Remove Admin Endpoint","operationId":"admin_remove_admin_endpoint_admin_admins_remove_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"summary":"Home","operationId":"home__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AbortMultipartUploadRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"key":{"type":"string","title":"Key"},"uploadId":{"type":"string","title":"Uploadid"}},"type":"object","required":["projectId","key","uploadId"],"title":"AbortMultipartUploadRequest"},"AddImagesRequest":{"properties":{"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"projectId":{"type":"integer","title":"Projectid"},"photographerId":{"type":"string","title":"Photographerid"},"folderName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Foldername"},"presetBrandTags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Presetbrandtags"},"presetPersonalizedTags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Presetpersonalizedtags"},"presetPersonTags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Presetpersontags"},"presetGeneralTags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Presetgeneraltags"},"presetCustomCategoryTags":{"anyOf":[{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object"},{"type":"null"}],"title":"Presetcustomcategorytags"},"uploadLinkToken":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Uploadlinktoken"}},"type":"object","required":["imageIds","projectId","photographerId"],"title":"AddImagesRequest"},"AddImagesToShareRequest":{"properties":{"shareId":{"type":"string","title":"Shareid"},"newImageIds":{"items":{"type":"string"},"type":"array","title":"Newimageids"}},"type":"object","required":["shareId","newImageIds"],"title":"AddImagesToShareRequest"},"AssignFaceRequest":{"properties":{"faceId":{"type":"string","title":"Faceid"},"newName":{"type":"string","title":"Newname"},"renameMode":{"type":"string","enum":["single_new","single_existing","all_new","all_existing"],"title":"Renamemode"},"targetPersonId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Targetpersonid"}},"type":"object","required":["faceId","newName","renameMode"],"title":"AssignFaceRequest"},"AttendeeEmailTemplateRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"subject":{"type":"string","title":"Subject"},"bodyText":{"type":"string","title":"Bodytext"}},"type":"object","required":["projectId","subject","bodyText"],"title":"AttendeeEmailTemplateRequest"},"AttendeeRegistrationPresignRequest":{"properties":{"token":{"type":"string","title":"Token"},"files":{"items":{"$ref":"#/components/schemas/FileInfo"},"type":"array","title":"Files"}},"type":"object","required":["token","files"],"title":"AttendeeRegistrationPresignRequest","description":"Presign one face photo upload for attendee self-registration (same S3 layout as dashboard)."},"AttendeeSetupRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"autoSendEmail":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Autosendemail"},"senderEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Senderemail"},"sendFromEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sendfromemail"},"subject":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subject"},"bodyHtml":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bodyhtml"},"defaultShareFolderNames":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Defaultsharefoldernames"}},"type":"object","required":["projectId"],"title":"AttendeeSetupRequest"},"BBox":{"properties":{"top":{"type":"integer","title":"Top"},"left":{"type":"integer","title":"Left"},"width":{"type":"integer","title":"Width"},"height":{"type":"integer","title":"Height"}},"type":"object","required":["top","left","width","height"],"title":"BBox"},"Body_add_logo_endpoint_addLogo_post":{"properties":{"name":{"type":"string","title":"Name"},"projectId":{"type":"string","title":"Projectid"},"category":{"type":"string","title":"Category","default":"speaker"},"logoImageId":{"type":"string","title":"Logoimageid"},"image":{"type":"string","title":"Image"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contactemail"}},"type":"object","required":["name","projectId","logoImageId","image"],"title":"Body_add_logo_endpoint_addLogo_post"},"Body_add_logo_transcription_endpoint_addLogoTranscription_post":{"properties":{"logoId":{"type":"string","title":"Logoid"},"transcription":{"type":"string","title":"Transcription"}},"type":"object","required":["logoId","transcription"],"title":"Body_add_logo_transcription_endpoint_addLogoTranscription_post"},"Body_add_person_face_endpoint_addPersonFace_post":{"properties":{"name":{"type":"string","title":"Name"},"projectId":{"type":"string","title":"Projectid"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"position":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Position"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"faceImageId":{"type":"string","title":"Faceimageid"},"scanExistingFaces":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scanexistingfaces","default":"false"},"bulk":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bulk","default":"false"}},"type":"object","required":["name","projectId","faceImageId"],"title":"Body_add_person_face_endpoint_addPersonFace_post"},"Body_change_person_category_endpoint_changePersonCategory_put":{"properties":{"personId":{"type":"string","title":"Personid"},"newCategory":{"type":"string","title":"Newcategory"}},"type":"object","required":["personId","newCategory"],"title":"Body_change_person_category_endpoint_changePersonCategory_put"},"Body_delete_logo_transcription_endpoint_deleteLogoTranscription_delete":{"properties":{"logoId":{"type":"string","title":"Logoid"},"transcription":{"type":"string","title":"Transcription"}},"type":"object","required":["logoId","transcription"],"title":"Body_delete_logo_transcription_endpoint_deleteLogoTranscription_delete"},"Body_edit_logo_endpoint_editLogo_post":{"properties":{"personId":{"type":"string","title":"Personid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"contactEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contactemail"}},"type":"object","required":["personId"],"title":"Body_edit_logo_endpoint_editLogo_post"},"Body_edit_person_endpoint_editPerson_post":{"properties":{"personId":{"type":"string","title":"Personid"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"position":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Position"},"link":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link"},"faceImageId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Faceimageid"}},"type":"object","required":["personId"],"title":"Body_edit_person_endpoint_editPerson_post"},"Body_org_branding_set_endpoint_org_branding_post":{"properties":{"file":{"anyOf":[{"type":"string","format":"binary"},{"type":"null"}],"title":"File"},"logoLinkUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logolinkurl"},"removeLogo":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Removelogo"},"organizationId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Organizationid"}},"type":"object","title":"Body_org_branding_set_endpoint_org_branding_post"},"Body_train_logo_endpoint_trainLogo_post":{"properties":{"logoId":{"type":"string","title":"Logoid"},"projectId":{"type":"integer","title":"Projectid"}},"type":"object","required":["logoId","projectId"],"title":"Body_train_logo_endpoint_trainLogo_post"},"Body_update_logo_transcription_endpoint_updateLogoTranscription_put":{"properties":{"logoId":{"type":"string","title":"Logoid"},"oldTranscription":{"type":"string","title":"Oldtranscription"},"newTranscription":{"type":"string","title":"Newtranscription"}},"type":"object","required":["logoId","oldTranscription","newTranscription"],"title":"Body_update_logo_transcription_endpoint_updateLogoTranscription_put"},"ClearReviewFlagsRequest":{"properties":{"flagIds":{"items":{"type":"string"},"type":"array","title":"Flagids"}},"type":"object","required":["flagIds"],"title":"ClearReviewFlagsRequest"},"CompleteMultipartUploadRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"key":{"type":"string","title":"Key"},"uploadId":{"type":"string","title":"Uploadid"},"parts":{"items":{"$ref":"#/components/schemas/CompletedPart"},"type":"array","title":"Parts"}},"type":"object","required":["projectId","key","uploadId","parts"],"title":"CompleteMultipartUploadRequest"},"CompletedPart":{"properties":{"partNumber":{"type":"integer","title":"Partnumber"},"etag":{"type":"string","title":"Etag"}},"type":"object","required":["partNumber","etag"],"title":"CompletedPart"},"CountsRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"}},"type":"object","required":["projectId"],"title":"CountsRequest"},"CreateCollectionBody":{"properties":{"env":{"type":"string","title":"Env","default":"dev"}},"type":"object","title":"CreateCollectionBody"},"CreateHybridShareRequest":{"properties":{"projectId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids","default":[]},"personIds":{"items":{"type":"string"},"type":"array","title":"Personids","default":[]},"folderNames":{"items":{"type":"string"},"type":"array","title":"Foldernames","default":[]},"mode":{"anyOf":[{"type":"string","enum":["per_person","all_in_one"]},{"type":"null"}],"title":"Mode"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"includedLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Includedlabel"},"expiresInDays":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expiresindays"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"creatorDisplay":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creatordisplay"}},"type":"object","title":"CreateHybridShareRequest"},"CreateMultipartUploadRequest":{"properties":{"files":{"items":{"$ref":"#/components/schemas/MultipartFileInfo"},"type":"array","title":"Files"},"projectId":{"type":"integer","title":"Projectid"},"folderName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Foldername"},"photographerId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"},"fileType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filetype"}},"type":"object","required":["files","projectId"],"title":"CreateMultipartUploadRequest"},"CreateShareRequest":{"properties":{"projectId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"expiresInDays":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expiresindays"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"creatorDisplay":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creatordisplay"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"}},"type":"object","required":["imageIds"],"title":"CreateShareRequest"},"CreateUploadLinkRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"photographerId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"presetTags":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Presettags"},"locked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Locked","default":false},"startsAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startsat"},"endsAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endsat"}},"type":"object","required":["projectId"],"title":"CreateUploadLinkRequest"},"DeleteImagesRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"}},"type":"object","required":["projectId","imageIds"],"title":"DeleteImagesRequest"},"DeletePersonsRequest":{"properties":{"personIds":{"items":{"type":"string"},"type":"array","title":"Personids"},"cascadeAttendee":{"type":"boolean","title":"Cascadeattendee","default":false}},"type":"object","required":["personIds"],"title":"DeletePersonsRequest"},"FaceOccurrenceCreate":{"properties":{"image_id":{"type":"string","title":"Image Id"},"bbox":{"$ref":"#/components/schemas/BBox"},"person_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person Id"}},"type":"object","required":["image_id","bbox"],"title":"FaceOccurrenceCreate"},"FileInfo":{"properties":{"extension":{"type":"string","title":"Extension"},"contentType":{"type":"string","title":"Contenttype"}},"type":"object","required":["extension","contentType"],"title":"FileInfo"},"FolderRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"folderName":{"type":"string","title":"Foldername"}},"type":"object","required":["projectId","folderName"],"title":"FolderRequest"},"GeneratePresignedUrlsRequest":{"properties":{"files":{"items":{"$ref":"#/components/schemas/FileInfo"},"type":"array","title":"Files"},"projectId":{"type":"integer","title":"Projectid"},"folderName":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Foldername"},"photographerId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"},"fileType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filetype"}},"type":"object","required":["files","projectId"],"title":"GeneratePresignedUrlsRequest"},"GenerateShareLinksRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"personIds":{"items":{"type":"string"},"type":"array","title":"Personids","default":[]},"mode":{"type":"string","enum":["per_person","all_in_one"],"title":"Mode","default":"per_person"},"folderNames":{"items":{"type":"string"},"type":"array","title":"Foldernames","default":[]},"expiresInDays":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expiresindays"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"creatorDisplay":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creatordisplay"},"labelStrategyPeople":{"anyOf":[{"type":"string","enum":["name_only","category_name","name_category"]},{"type":"null"}],"title":"Labelstrategypeople","default":"name_only"},"labelStrategyBrands":{"anyOf":[{"type":"string","enum":["name_only","brand_prefix"]},{"type":"null"}],"title":"Labelstrategybrands","default":"name_only"},"labelStrategyCustomFolder":{"anyOf":[{"type":"string","enum":["name_only","category_option"]},{"type":"null"}],"title":"Labelstrategycustomfolder","default":"name_only"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"linkLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Linklabel"},"customTagLinkMode":{"anyOf":[{"type":"string","enum":["combined","per_option"]},{"type":"null"}],"title":"Customtaglinkmode","default":"combined"}},"type":"object","required":["projectId"],"title":"GenerateShareLinksRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"MergePhotographersRequest":{"properties":{"targetId":{"type":"string","title":"Targetid"},"sourceIds":{"items":{"type":"string"},"type":"array","title":"Sourceids"},"keepEmail":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Keepemail"}},"type":"object","required":["targetId","sourceIds"],"title":"MergePhotographersRequest"},"ModifyFolderImagesRequest":{"properties":{"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"folderName":{"type":"string","title":"Foldername"},"projectId":{"type":"integer","title":"Projectid"}},"type":"object","required":["imageIds","folderName","projectId"],"title":"ModifyFolderImagesRequest"},"MultipartFileInfo":{"properties":{"contentType":{"type":"string","title":"Contenttype"},"size":{"type":"integer","title":"Size"}},"type":"object","required":["contentType","size"],"title":"MultipartFileInfo"},"PersonUpdatedRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"person":{"additionalProperties":true,"type":"object","title":"Person"}},"type":"object","required":["projectId","person"],"title":"PersonUpdatedRequest"},"PhotographerAccessRequest":{"properties":{"photographerId":{"type":"string","title":"Photographerid"}},"type":"object","required":["photographerId"],"title":"PhotographerAccessRequest"},"RegisterAttendeeRequest":{"properties":{"token":{"type":"string","title":"Token"},"registration_type":{"type":"string","enum":["attendee","attendee_startup","startup"],"title":"Registration Type","default":"attendee"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"startup_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startup Name"},"startup_contact_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startup Contact Email"},"use_same_email_for_startup":{"type":"boolean","title":"Use Same Email For Startup","default":false},"face_image_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Face Image Id"}},"type":"object","required":["token"],"title":"RegisterAttendeeRequest"},"RestoreImagesRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"}},"type":"object","required":["projectId","imageIds"],"title":"RestoreImagesRequest"},"RetryTaggingRequest":{"properties":{"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"steps":{"items":{"type":"string"},"type":"array","title":"Steps"}},"type":"object","required":["imageIds","steps"],"title":"RetryTaggingRequest"},"ReviewLifecycleRequest":{"properties":{"shareId":{"type":"string","title":"Shareid"}},"type":"object","required":["shareId"],"title":"ReviewLifecycleRequest"},"SendAttendeeEmailsRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"personIds":{"items":{"type":"string"},"type":"array","title":"Personids"},"zeroImagesConfirmation":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zeroimagesconfirmation"},"subjectOverride":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subjectoverride"},"bodyTextOverride":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bodytextoverride"},"forceResend":{"type":"boolean","title":"Forceresend","default":false}},"type":"object","required":["projectId","personIds"],"title":"SendAttendeeEmailsRequest"},"SetAttendeeEmailApprovalRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"personId":{"type":"string","title":"Personid"},"status":{"type":"string","enum":["pending","approved","approved-none","approved-Pavoot"],"title":"Status"}},"type":"object","required":["projectId","personId","status"],"title":"SetAttendeeEmailApprovalRequest","description":"Set share-email readiness. Any of approved / approved-none / approved-Pavoot allows send."},"SetPhotographerLockRequest":{"properties":{"photographerId":{"type":"string","title":"Photographerid"},"projectIds":{"items":{"type":"integer"},"type":"array","title":"Projectids"},"locked":{"type":"boolean","title":"Locked"}},"type":"object","required":["photographerId","projectIds","locked"],"title":"SetPhotographerLockRequest"},"SharePreviewRequest":{"properties":{"projectId":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids","default":[]},"personIds":{"items":{"type":"string"},"type":"array","title":"Personids","default":[]},"folderNames":{"items":{"type":"string"},"type":"array","title":"Foldernames","default":[]}},"type":"object","title":"SharePreviewRequest"},"TaggingStepRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"imageId":{"type":"string","title":"Imageid"},"step":{"type":"string","title":"Step"}},"type":"object","required":["projectId","imageId","step"],"title":"TaggingStepRequest"},"UpdateFolderNameRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"oldFolderName":{"type":"string","title":"Oldfoldername"},"newFolderName":{"type":"string","title":"Newfoldername"}},"type":"object","required":["projectId","oldFolderName","newFolderName"],"title":"UpdateFolderNameRequest"},"UpdateImagesPhotographerRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"photographerId":{"type":"string","title":"Photographerid"}},"type":"object","required":["projectId","imageIds","photographerId"],"title":"UpdateImagesPhotographerRequest"},"UpdateShareRequest":{"properties":{"id":{"type":"string","title":"Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"expiresInDays":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expiresindays"},"personIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Personids"},"folderNames":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Foldernames"},"mode":{"anyOf":[{"type":"string","enum":["per_person","all_in_one"]},{"type":"null"}],"title":"Mode"},"category":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Category"},"unlockedTags":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Unlockedtags"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"includedLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Includedlabel"},"imageIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Imageids"},"includedImageIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Includedimageids"},"excludedImageIds":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Excludedimageids"},"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password"},"removePassword":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Removepassword"},"showLockedTags":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showlockedtags"},"showLockedPhotographers":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showlockedphotographers"},"showFlagged":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Showflagged"},"unlockedPhotographers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Unlockedphotographers"},"reviewEnabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Reviewenabled"},"reviewInstructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reviewinstructions"}},"type":"object","required":["id"],"title":"UpdateShareRequest"},"UpdateUploadLinkRequest":{"properties":{"id":{"type":"string","title":"Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"photographerId":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Photographerid"},"location":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Location"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"},"presetTags":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Presettags"},"locked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Locked"},"startsAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Startsat"},"endsAt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endsat"},"revoked":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Revoked"}},"type":"object","required":["id"],"title":"UpdateUploadLinkRequest"},"UpsertAttendeeRequest":{"properties":{"projectId":{"type":"integer","title":"Projectid"},"personId":{"type":"string","title":"Personid"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"}},"type":"object","required":["projectId","personId"],"title":"UpsertAttendeeRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"ZipDownloadRequest":{"properties":{"imageIds":{"items":{"type":"string"},"type":"array","title":"Imageids"},"projectId":{"type":"integer","title":"Projectid"},"size":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Size","default":"original"}},"type":"object","required":["imageIds","projectId"],"title":"ZipDownloadRequest"}}}}