{ "swagger": "2.0", "info": { "description": "Bringing group travel plans to life", "title": "Toggo API", "contact": {}, "version": "1.0" }, "host": "localhost:8000", "basePath": "/", "paths": { "/api/v1/comments": { "post": { "description": "Creates a new comment", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "comments" ], "summary": "Create a comment", "operationId": "createComment", "parameters": [ { "description": "Create comment request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateCommentRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.Comment" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/comments/{commentID}": { "delete": { "description": "Deletes a comment by ID", "tags": [ "comments" ], "summary": "Delete a comment", "operationId": "deleteComment", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates an existing comment by ID", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "comments" ], "summary": "Update a comment", "operationId": "updateComment", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true }, { "description": "Update comment request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateCommentRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.Comment" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/comments/{commentID}/reactions": { "get": { "description": "Retrieves aggregated emoji reactions for a comment", "produces": [ "application/json" ], "tags": [ "comment-reactions" ], "summary": "Get reactions summary for a comment", "operationId": "getCommentReactionsSummary", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.CommentReactionsSummaryResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Adds an emoji reaction to a comment", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "comment-reactions" ], "summary": "Add a reaction to a comment", "operationId": "addCommentReaction", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true }, { "description": "Create reaction request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateCommentReactionRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.CommentReaction" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Removes the current user's emoji reaction from a comment", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "comment-reactions" ], "summary": "Remove a reaction from a comment", "operationId": "removeCommentReaction", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true }, { "description": "Delete reaction request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.DeleteCommentReactionRequest" } } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/comments/{commentID}/reactions/{emoji}/users": { "get": { "description": "Retrieves users who reacted with a specific emoji on a comment", "produces": [ "application/json" ], "tags": [ "comment-reactions" ], "summary": "Get users who reacted with an emoji", "operationId": "getCommentReactionUsers", "parameters": [ { "type": "string", "description": "Comment ID", "name": "commentID", "in": "path", "required": true }, { "type": "string", "description": "Emoji (URL-encoded)", "name": "emoji", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.CommentReactionUsersResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/files/confirm": { "post": { "description": "Verifies the file exists in S3 and marks the upload as confirmed in DB", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Confirm upload", "operationId": "confirmUpload", "parameters": [ { "description": "Confirm upload request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.ConfirmUploadRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ConfirmUploadResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/files/health": { "get": { "description": "Verifies connectivity to the configured S3 bucket", "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Check S3 connection", "operationId": "checkS3Health", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.S3HealthCheckResponse" } }, "503": { "description": "Service Unavailable", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/files/upload": { "post": { "description": "Generates presigned PUT URLs for uploading files and creates pending records in DB", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Create upload URLs", "operationId": "createUploadURLs", "parameters": [ { "description": "Upload URL request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UploadURLRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.UploadURLResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/files/{imageId}": { "get": { "description": "Retrieves presigned URLs for all sizes of an image", "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Get all sizes of a file", "operationId": "getFileAllSizes", "parameters": [ { "type": "string", "description": "Image ID (UUID)", "name": "imageId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.GetFileAllSizesResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes all size variants of an image from S3 and the database", "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Delete image", "operationId": "deleteImage", "parameters": [ { "type": "string", "description": "Image ID (UUID)", "name": "imageId", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/files/{imageId}/{size}": { "get": { "description": "Retrieves a presigned URL for downloading a specific file size", "produces": [ "application/json" ], "tags": [ "files" ], "summary": "Get file by ID and size", "operationId": "getFile", "parameters": [ { "type": "string", "description": "Image ID (UUID)", "name": "imageId", "in": "path", "required": true }, { "type": "string", "description": "Image size (large, medium, small)", "name": "size", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.GetFileResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/memberships": { "post": { "description": "Adds a user as a member of a trip", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Add member to trip", "operationId": "addMember", "parameters": [ { "description": "Create membership request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateMembershipRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.Membership" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/notifications/send": { "post": { "description": "Sends a push notification to a single user", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "notifications" ], "summary": "Send notification to user", "operationId": "sendNotification", "parameters": [ { "description": "Notification request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.SendNotificationRequest" } } ], "responses": { "200": { "description": "OK" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/notifications/send-bulk": { "post": { "description": "Sends push notifications to multiple users", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "notifications" ], "summary": "Send bulk notifications", "operationId": "sendBulkNotification", "parameters": [ { "description": "Bulk notification request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.SendBulkNotificationRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.NotificationResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/search/places/details": { "post": { "security": [ { "BearerAuth": [] } ], "description": "Retrieves detailed information about a specific place using Google Maps Places API. Accepts either a place_id (from typeahead results) or input text for direct search. Returns address, coordinates, photos, ratings, opening hours, and more.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "places" ], "summary": "Get detailed information about a place", "operationId": "getPlaceDetails", "parameters": [ { "description": "Place details request (provide either place_id or input)", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.PlaceDetailsRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PlaceDetailsResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/search/places/health": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Checks if Google Maps API is connected and accessible", "produces": [ "application/json" ], "tags": [ "places" ], "summary": "Google Maps health check", "operationId": "googleMapsHealth", "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": true } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "additionalProperties": true } } } } }, "/api/v1/search/places/typeahead": { "get": { "security": [ { "BearerAuth": [] } ], "description": "Quick typeahead/autocomplete endpoint for real-time place search as users type. Returns a list of place predictions with place IDs that can be used to fetch detailed information.", "produces": [ "application/json" ], "tags": [ "places" ], "summary": "Typeahead search for places", "operationId": "typeaheadPlaces", "parameters": [ { "type": "string", "description": "Search query (e.g., 'Eiffel Tower', 'Paris')", "name": "q", "in": "query", "required": true }, { "type": "integer", "description": "Maximum number of results (default: 5, max: 20)", "name": "limit", "in": "query" }, { "type": "string", "description": "Language code (e.g., 'en', 'fr', 'es')", "name": "language", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PlacesSearchResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/search/trips": { "get": { "description": "Full-text search over trips the authenticated user is a member of. Ordered by relevance then recency.", "produces": [ "application/json" ], "tags": [ "search" ], "summary": "Search trips", "operationId": "searchTrips", "parameters": [ { "type": "string", "description": "Search query (1-255 chars)", "name": "q", "in": "query", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "integer", "description": "Pagination offset (default 0)", "name": "offset", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.SearchTripsResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/search/trips/{tripID}/activities": { "get": { "description": "Full-text search over activities within a specific trip. Ordered by relevance then recency.", "produces": [ "application/json" ], "tags": [ "search" ], "summary": "Search activities in a trip", "operationId": "searchActivities", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Search query (1-255 chars)", "name": "q", "in": "query", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "integer", "description": "Pagination offset (default 0)", "name": "offset", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.SearchActivitiesResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/search/trips/{tripID}/members": { "get": { "description": "Full-text search over members of a specific trip, matching on name and username.", "produces": [ "application/json" ], "tags": [ "search" ], "summary": "Search trip members", "operationId": "searchTripMembers", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Search query (1-255 chars)", "name": "q", "in": "query", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "integer", "description": "Pagination offset (default 0)", "name": "offset", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.SearchMembersResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trip-invites/{code}/join": { "post": { "description": "Adds the authenticated user to a trip using an invite code", "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Join trip by invite code", "operationId": "joinTripByInvite", "parameters": [ { "type": "string", "description": "Invite code", "name": "code", "in": "path", "required": true } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.Membership" } }, "400": { "description": "Invalid or expired invite code", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips": { "get": { "description": "Retrieves trips with cursor-based pagination. Use limit and cursor query params.", "produces": [ "application/json" ], "tags": [ "trips" ], "summary": "Get all trips", "operationId": "getAllTrips", "parameters": [ { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor from previous response next_cursor for next page", "name": "cursor", "in": "query" }, { "type": "string", "description": "Only include trips where end_date is before this RFC3339 timestamp", "name": "end_date_before", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.TripCursorPageResult" } }, "400": { "description": "Invalid cursor", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates a new trip for the authenticated user", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "trips" ], "summary": "Create a trip", "operationId": "createTrip", "parameters": [ { "description": "Create trip request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateTripRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.Trip" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}": { "get": { "description": "Retrieves a trip by ID", "produces": [ "application/json" ], "tags": [ "trips" ], "summary": "Get a trip", "operationId": "getTrip", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.TripAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes a trip by ID", "tags": [ "trips" ], "summary": "Delete a trip", "operationId": "deleteTrip", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates an existing trip by ID", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "trips" ], "summary": "Update a trip", "operationId": "updateTrip", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Update trip request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateTripRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.Trip" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities": { "get": { "description": "Retrieves paginated activities for a trip, optionally filtered by category, time of day, and/or date", "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Get activities by trip", "operationId": "getActivitiesByTripID", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Filter by category name", "name": "category", "in": "query" }, { "type": "string", "description": "Filter by time of day (morning, afternoon, evening)", "name": "time_of_day", "in": "query" }, { "type": "string", "description": "Filter by calendar date (YYYY-MM-DD); activity must have a date range containing this day", "name": "date", "in": "query" }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ActivityCursorPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates a new activity for a trip", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Create activity", "operationId": "createActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Create activity request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateActivityRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.Activity" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/parse-link": { "post": { "description": "Fetches a URL and extracts structured activity fields (name, description, thumbnail) for form autofill. Supports Airbnb, Booking.com, TikTok, Instagram, and generic travel blog URLs.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Parse link into activity data", "operationId": "parseActivityLink", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "URL to parse", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.ParseLinkRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ParsedActivityData" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/{activityID}": { "get": { "description": "Retrieves a specific activity", "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Get activity by ID", "operationId": "getActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ActivityAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "put": { "description": "Updates an existing activity", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Update activity", "operationId": "updateActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "description": "Update activity request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateActivityRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.Activity" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes an activity", "tags": [ "activities" ], "summary": "Delete activity", "operationId": "deleteActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/{activityID}/categories": { "get": { "description": "Retrieves categories for an activity with pagination", "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Get activity categories", "operationId": "getActivityCategories", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ActivityCategoriesPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/{activityID}/categories/{categoryName}": { "put": { "description": "Adds a category to an activity (idempotent)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Add category to activity", "operationId": "addCategoryToActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "type": "string", "description": "Category Name", "name": "categoryName", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.AddCategoryResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Removes a category from an activity", "tags": [ "activities" ], "summary": "Remove category from activity", "operationId": "removeCategoryFromActivity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "type": "string", "description": "Category Name", "name": "categoryName", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/{activityID}/rsvp": { "post": { "description": "Allows a user to RSVP to a specific activity within a trip.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "RSVP to activity", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "description": "RSVP request payload", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.ActivityRSVPRequestPayload" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ActivityRSVPAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activities/{activityID}/rsvps": { "get": { "description": "Returns paginated RSVPs for a specific activity within a trip, optionally filtered by RSVP status.", "produces": [ "application/json" ], "tags": [ "activities" ], "summary": "Get activity RSVPs", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Activity ID", "name": "activityID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" }, { "type": "string", "description": "Filter by RSVP status", "name": "status", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.ActivityRSVPsPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activity": { "get": { "description": "Returns all unread events in the caller's trip feed. Events persist until explicitly dismissed via the mark-read endpoint.", "produces": [ "application/json" ], "tags": [ "activity-feed" ], "summary": "Get trip activity feed", "operationId": "getTripActivityFeed", "parameters": [ { "type": "string", "description": "Trip ID (UUID)", "name": "tripID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "array", "items": { "$ref": "#/definitions/realtime.Event" } } }, "400": { "description": "Invalid trip ID", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activity/unread-count": { "get": { "description": "Returns the number of events in the caller's trip feed that have not yet been marked as read.", "produces": [ "application/json" ], "tags": [ "activity-feed" ], "summary": "Get unread activity count", "operationId": "getUnreadActivityCount", "parameters": [ { "type": "string", "description": "Trip ID (UUID)", "name": "tripID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/realtime.UnreadCountResponse" } }, "400": { "description": "Invalid trip ID", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/activity/{eventID}": { "delete": { "description": "Removes a specific event from the caller's trip activity feed.", "tags": [ "activity-feed" ], "summary": "Mark activity event as read", "operationId": "markActivityEventRead", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Event ID", "name": "eventID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/categories": { "get": { "description": "Retrieves all categories for a trip", "produces": [ "application/json" ], "tags": [ "categories" ], "summary": "Get categories by trip", "operationId": "getCategoriesByTripID", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "boolean", "description": "Include hidden categories (admin only)", "name": "include_hidden", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.CategoryListResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates a new custom category for a trip (any trip member)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "categories" ], "summary": "Create category", "operationId": "createCategory", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Category details", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateCategoryRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.CategoryAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/categories/{name}": { "delete": { "description": "Deletes a custom category from a trip (admin only, cannot delete default categories)", "tags": [ "categories" ], "summary": "Delete category", "operationId": "deleteCategory", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Category name", "name": "name", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/categories/{name}/hide": { "put": { "description": "Hides a category from all members (admin only)", "tags": [ "categories" ], "summary": "Hide category", "operationId": "hideCategory", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Category name", "name": "name", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/categories/{name}/show": { "put": { "description": "Makes a previously hidden category visible again (admin only)", "tags": [ "categories" ], "summary": "Show category", "operationId": "showCategory", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Category name", "name": "name", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/invites": { "post": { "description": "Creates a shareable invite for the trip. Caller must be a trip member.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "trips" ], "summary": "Create a trip invite", "operationId": "createTripInvite", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Optional expires_at; default 7 days", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateTripInviteRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.TripInviteAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/memberships": { "get": { "description": "Retrieves all members of a trip", "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Get trip members", "operationId": "getTripMembers", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.MembershipCursorPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/memberships/{userID}": { "get": { "description": "Retrieves the membership for a user in a trip", "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Get membership", "operationId": "getMembership", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.MembershipAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Removes a user from a trip", "tags": [ "memberships" ], "summary": "Remove member from trip", "operationId": "removeMember", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates a membership", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Update membership", "operationId": "updateMembership", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true }, { "description": "Update membership request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateMembershipRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.Membership" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/memberships/{userID}/demote": { "post": { "description": "Demotes an admin to regular member role", "tags": [ "memberships" ], "summary": "Demote admin to member", "operationId": "demoteFromAdmin", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/memberships/{userID}/notification-preferences": { "patch": { "description": "Updates the notification preferences for a membership (self only)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "memberships" ], "summary": "Update notification preferences", "operationId": "updateMembershipNotificationPreferences", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true }, { "description": "Notification preferences", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateNotificationPreferencesRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.Membership" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/memberships/{userID}/promote": { "post": { "description": "Promotes a member to admin role", "tags": [ "memberships" ], "summary": "Promote member to admin", "operationId": "promoteToAdmin", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": { "type": "string" } } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/pitches": { "get": { "description": "Returns pitches for the trip with cursor-based pagination", "produces": [ "application/json" ], "tags": [ "pitches" ], "summary": "Get all pitches for a trip", "operationId": "listPitches", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor from previous response next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PitchCursorPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates a new pitch for the trip and returns a presigned URL to upload the audio file.\nOptionally supply up to 5 confirmed image IDs (image_ids) in the request. The response includes images with presigned medium_url for each image.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "pitches" ], "summary": "Create a pitch", "operationId": "createPitch", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Create pitch request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreatePitchRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.CreatePitchResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/pitches/{pitchID}": { "get": { "description": "Returns a single pitch with presigned URLs for the audio file and associated images (medium_url for each image)", "produces": [ "application/json" ], "tags": [ "pitches" ], "summary": "Get a pitch by ID", "operationId": "getPitch", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Pitch ID", "name": "pitchID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PitchAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes a pitch by ID", "tags": [ "pitches" ], "summary": "Delete a pitch", "operationId": "deletePitch", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Pitch ID", "name": "pitchID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates pitch metadata (title, description, duration).\nWhen image_ids is omitted from the request, existing image associations remain unchanged.\nWhen image_ids is an empty array, all image associations are removed.\nWhen image_ids is a non-empty array, the provided IDs are added to existing associations (additive, not replacement).\nThe response includes images with presigned medium_url for each image.", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "pitches" ], "summary": "Update a pitch", "operationId": "updatePitch", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Pitch ID", "name": "pitchID", "in": "path", "required": true }, { "description": "Update pitch request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdatePitchRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PitchAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/pitches/{pitchID}/confirm-upload": { "post": { "description": "Verifies that the audio file was successfully uploaded to S3 and notifies trip members.\nMust be called by the pitch creator after the presigned PUT upload completes.", "tags": [ "pitches" ], "summary": "Confirm pitch audio upload", "operationId": "confirmPitchUpload", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Pitch ID", "name": "pitchID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls": { "post": { "description": "Creates a new ranking poll with initial options", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Create a rank poll", "operationId": "createRankPoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Create rank poll request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreatePollRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.RankPollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}": { "get": { "description": "Retrieves a rank poll with Borda count scores and user's personal ranking", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get rank poll results", "operationId": "getRankPollResults", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.RankPollResultsResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes a rank poll and all associated options and rankings", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Delete a rank poll", "operationId": "deleteRankPoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.RankPollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates poll metadata (question, deadline)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Update a rank poll", "operationId": "updateRankPoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Update rank poll request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdatePollWithCategoriesRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.RankPollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}/options": { "post": { "description": "Adds an option to a rank poll (only if no rankings exist yet)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Add a rank poll option", "operationId": "addRankPollOption", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Create option request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreatePollOptionRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}/options/{optionId}": { "delete": { "description": "Removes an option from a rank poll (only if no rankings exist yet)", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Delete a rank poll option", "operationId": "deleteRankPollOption", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "type": "string", "description": "Option ID", "name": "optionId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}/options/{optionId}/ranks/{rankPosition}/voters": { "get": { "description": "Returns who ranked an option at a specific rank position", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get voters for a ranked choice", "operationId": "getRankChoiceVoters", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "type": "string", "description": "Option ID", "name": "optionId", "in": "path", "required": true }, { "type": "integer", "description": "Rank position (1-3)", "name": "rankPosition", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.RankChoiceVotersResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}/rank": { "post": { "description": "Submits or replaces the user's full ranking for a poll", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Submit ranking", "operationId": "submitRanking", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Submit ranking request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.SubmitRankingRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": true } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/rank-polls/{pollId}/voters": { "get": { "description": "Returns who has voted vs who hasn't for a rank poll", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get poll voters", "operationId": "getRankPollVoters", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollVotersResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/tabs": { "get": { "description": "Retrieves all visible categories for a trip ordered by position", "produces": [ "application/json" ], "tags": [ "categories" ], "summary": "Get trip tabs", "operationId": "getTripTabs", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.TabListResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/tabs/reorder": { "put": { "description": "Updates the position of visible categories for a trip", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "categories" ], "summary": "Reorder trip tabs", "operationId": "reorderTripTabs", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Reorder request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateCategoryTabOrderRequest" } } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls": { "get": { "description": "Retrieves all polls for a trip with cursor-based pagination", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get polls for a trip", "operationId": "getPollsByTripID", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollCursorPageResult" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates a new poll with initial options", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Create a poll", "operationId": "createPoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "description": "Create poll request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreatePollRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.PollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}": { "get": { "description": "Retrieves a poll with vote counts and the caller's votes", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get poll results", "operationId": "getPoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes a poll and all associated options and votes, returns the deleted poll", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Delete a poll", "operationId": "deletePoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates poll metadata (question, deadline)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Update a poll", "operationId": "updatePoll", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Update poll request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdatePollWithCategoriesRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}/options": { "post": { "description": "Adds an option to a poll (only if no votes exist yet)", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Add a poll option", "operationId": "addPollOption", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Create option request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreatePollOptionRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}/options/{optionId}": { "delete": { "description": "Removes an option from a poll and returns the deleted option", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Delete a poll option", "operationId": "deletePollOption", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "type": "string", "description": "Option ID", "name": "optionId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}/options/{optionId}/voters": { "get": { "description": "Returns all users who voted for a specific option in a vote poll", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get option voters", "operationId": "getVoteOptionVoters", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "type": "string", "description": "Option ID", "name": "optionId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.OptionVotersResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}/vote": { "post": { "description": "Casts or replaces the user's vote(s) on a poll", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Cast a vote", "operationId": "castVote", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true }, { "description": "Vote request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CastVoteRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollAPIResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/vote-polls/{pollId}/voters": { "get": { "description": "Returns who has voted vs who hasn't for a vote poll", "produces": [ "application/json" ], "tags": [ "polls" ], "summary": "Get vote poll voters", "operationId": "getVotePollVoters", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Poll ID", "name": "pollId", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PollVotersResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "403": { "description": "Forbidden", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/trips/{tripID}/{entityType}/{entityID}/comments": { "get": { "description": "Retrieves paginated comments for a trip entity", "produces": [ "application/json" ], "tags": [ "comments" ], "summary": "Get comments", "operationId": "getPaginatedComments", "parameters": [ { "type": "string", "description": "Trip ID", "name": "tripID", "in": "path", "required": true }, { "type": "string", "description": "Entity type (activity, pitch)", "name": "entityType", "in": "path", "required": true }, { "type": "string", "description": "Entity ID", "name": "entityID", "in": "path", "required": true }, { "type": "integer", "description": "Max items per page (default 20, max 100)", "name": "limit", "in": "query" }, { "type": "string", "description": "Opaque cursor returned in next_cursor", "name": "cursor", "in": "query" } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.PaginatedCommentsResponse" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/users": { "post": { "description": "Creates a new user with the provided payload", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "users" ], "summary": "Create a new user", "operationId": "createUser", "parameters": [ { "description": "Create user request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateUserRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.User" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/users/me": { "get": { "description": "Retrieves the authenticated user (from JWT claims)", "produces": [ "application/json" ], "tags": [ "users" ], "summary": "Get current user", "operationId": "getCurrentUser", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.User" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/users/me/notification-preferences": { "get": { "description": "Retrieves the notification preferences for the authenticated user", "produces": [ "application/json" ], "tags": [ "notification-preferences" ], "summary": "Get notification preferences", "operationId": "getNotificationPreferences", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.NotificationPreferences" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "post": { "description": "Creates notification preferences for the authenticated user", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "notification-preferences" ], "summary": "Create notification preferences", "operationId": "createNotificationPreferences", "parameters": [ { "description": "Create notification preferences request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.CreateNotificationPreferencesRequest" } } ], "responses": { "201": { "description": "Created", "schema": { "$ref": "#/definitions/models.NotificationPreferences" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "409": { "description": "Conflict", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes notification preferences for the authenticated user", "tags": [ "notification-preferences" ], "summary": "Delete notification preferences", "operationId": "deleteNotificationPreferences", "responses": { "204": { "description": "No Content" }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates notification preferences for the authenticated user", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "notification-preferences" ], "summary": "Update notification preferences", "operationId": "updateNotificationPreferences", "parameters": [ { "description": "Update notification preferences request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateUserNotificationPreferencesRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.NotificationPreferences" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/users/me/notification-preferences/default": { "post": { "description": "Returns existing preferences or creates default preferences for the authenticated user", "produces": [ "application/json" ], "tags": [ "notification-preferences" ], "summary": "Get or create default notification preferences", "operationId": "getOrCreateDefaultNotificationPreferences", "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.NotificationPreferences" } }, "401": { "description": "Unauthorized", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/api/v1/users/{userID}": { "get": { "description": "Retrieves a user by ID", "produces": [ "application/json" ], "tags": [ "users" ], "summary": "Get a user", "operationId": "getUser", "parameters": [ { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.User" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "delete": { "description": "Deletes a user by ID", "tags": [ "users" ], "summary": "Delete a user", "operationId": "deleteUser", "parameters": [ { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true } ], "responses": { "204": { "description": "No Content" }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } }, "patch": { "description": "Updates an existing user by ID", "consumes": [ "application/json" ], "produces": [ "application/json" ], "tags": [ "users" ], "summary": "Update a user", "operationId": "updateUser", "parameters": [ { "type": "string", "description": "User ID", "name": "userID", "in": "path", "required": true }, { "description": "Update user request", "name": "request", "in": "body", "required": true, "schema": { "$ref": "#/definitions/models.UpdateUserRequest" } } ], "responses": { "200": { "description": "OK", "schema": { "$ref": "#/definitions/models.User" } }, "400": { "description": "Bad Request", "schema": { "$ref": "#/definitions/errs.APIError" } }, "404": { "description": "Not Found", "schema": { "$ref": "#/definitions/errs.APIError" } }, "422": { "description": "Unprocessable Entity", "schema": { "$ref": "#/definitions/errs.APIError" } }, "500": { "description": "Internal Server Error", "schema": { "$ref": "#/definitions/errs.APIError" } } } } }, "/healthcheck": { "get": { "description": "Returns OK if the server is running and database is healthy", "produces": [ "application/json" ], "tags": [ "example" ], "summary": "Healthcheck endpoint", "operationId": "healthcheck", "responses": { "200": { "description": "OK", "schema": { "type": "object", "additionalProperties": true } }, "500": { "description": "Internal Server Error", "schema": { "type": "object", "additionalProperties": true } } } } } }, "definitions": { "errs.APIError": { "type": "object", "properties": { "message": {}, "statusCode": { "type": "integer" } } }, "models.Activity": { "type": "object", "properties": { "created_at": { "type": "string" }, "dates": { "type": "array", "items": { "$ref": "#/definitions/models.DateRange" } }, "description": { "type": "string" }, "estimated_price": { "type": "number" }, "id": { "type": "string" }, "location_lat": { "type": "number" }, "location_lng": { "type": "number" }, "location_name": { "type": "string" }, "media_url": { "type": "string" }, "name": { "type": "string" }, "proposed_by": { "type": "string" }, "thumbnail_url": { "type": "string" }, "time_of_day": { "$ref": "#/definitions/models.ActivityTimeOfDay" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" } } }, "models.ActivityAPIResponse": { "type": "object", "properties": { "category_names": { "type": "array", "items": { "type": "string" } }, "comment_count": { "type": "integer" }, "comment_previews": { "type": "array", "items": { "$ref": "#/definitions/models.CommenterPreview" } }, "created_at": { "type": "string" }, "dates": { "type": "array", "items": { "$ref": "#/definitions/models.DateRange" } }, "description": { "type": "string" }, "estimated_price": { "type": "number" }, "going_count": { "type": "integer" }, "going_users": { "type": "array", "items": { "$ref": "#/definitions/models.ActivityGoingUserResponse" } }, "id": { "type": "string" }, "image_ids": { "type": "array", "items": { "$ref": "#/definitions/models.ActivityImageResponse" } }, "location_lat": { "type": "number" }, "location_lng": { "type": "number" }, "location_name": { "type": "string" }, "media_url": { "type": "string" }, "name": { "type": "string" }, "proposed_by": { "type": "string" }, "proposer_name": { "type": "string" }, "proposer_picture_url": { "type": "string" }, "proposer_username": { "type": "string" }, "thumbnail_url": { "type": "string" }, "time_of_day": { "$ref": "#/definitions/models.ActivityTimeOfDay" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" } } }, "models.ActivityCategoriesPageResult": { "type": "object", "properties": { "categories": { "type": "array", "items": { "type": "string" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.ActivityCursorPageResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.ActivityAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.ActivityGoingUserResponse": { "type": "object", "properties": { "name": { "type": "string" }, "profile_picture_url": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.ActivityImageResponse": { "type": "object", "properties": { "image_id": { "type": "string" }, "image_url": { "type": "string" } } }, "models.ActivityRSVPAPIResponse": { "type": "object", "properties": { "activity_id": { "type": "string" }, "created_at": { "type": "string" }, "name": { "type": "string" }, "profile_picture_url": { "type": "string" }, "status": { "$ref": "#/definitions/models.RSVPStatus" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.ActivityRSVPRequestPayload": { "type": "object", "properties": { "status": { "$ref": "#/definitions/models.RSVPStatus" } } }, "models.ActivityRSVPsPageResult": { "type": "object", "properties": { "limit": { "type": "integer" }, "next_cursor": { "type": "string" }, "rsvps": { "type": "array", "items": { "$ref": "#/definitions/models.ActivityRSVPAPIResponse" } } } }, "models.ActivityTimeOfDay": { "type": "string", "enum": [ "morning", "afternoon", "evening" ], "x-enum-varnames": [ "ActivityTimeOfDayMorning", "ActivityTimeOfDayAfternoon", "ActivityTimeOfDayEvening" ] }, "models.AddCategoryResponse": { "type": "object", "properties": { "message": { "type": "string", "example": "Category added successfully" } } }, "models.AddressComponent": { "type": "object", "properties": { "long_name": { "type": "string" }, "short_name": { "type": "string" }, "types": { "type": "array", "items": { "type": "string" } } } }, "models.Bounds": { "type": "object", "properties": { "northeast": { "$ref": "#/definitions/models.LatLng" }, "southwest": { "$ref": "#/definitions/models.LatLng" } } }, "models.CastVoteRequest": { "type": "object", "properties": { "option_ids": { "type": "array", "items": { "type": "string" } } } }, "models.CategoryAPIResponse": { "type": "object", "properties": { "created_at": { "type": "string" }, "icon": { "type": "string" }, "is_default": { "type": "boolean" }, "is_hidden": { "description": "only present for admins", "type": "boolean" }, "label": { "type": "string" }, "name": { "type": "string" }, "position": { "type": "integer" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" } } }, "models.CategoryListResponse": { "type": "object", "properties": { "categories": { "type": "array", "items": { "$ref": "#/definitions/models.CategoryAPIResponse" } } } }, "models.CategoryTabOrder": { "type": "object", "required": [ "name" ], "properties": { "name": { "type": "string", "minLength": 1 }, "position": { "type": "integer", "minimum": 0 } } }, "models.Comment": { "type": "object", "properties": { "content": { "type": "string" }, "created_at": { "type": "string" }, "entity_id": { "type": "string" }, "entity_type": { "$ref": "#/definitions/models.EntityType" }, "id": { "type": "string" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" } } }, "models.CommentAPIResponse": { "type": "object", "properties": { "content": { "type": "string" }, "created_at": { "type": "string" }, "entity_id": { "type": "string" }, "entity_type": { "$ref": "#/definitions/models.EntityType" }, "id": { "type": "string" }, "name": { "type": "string" }, "profile_picture_url": { "description": "pointer since some users don't have their avatar set", "type": "string" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.CommentReaction": { "type": "object", "properties": { "comment_id": { "type": "string" }, "created_at": { "type": "string" }, "emoji": { "type": "string" }, "id": { "type": "string" }, "user_id": { "type": "string" } } }, "models.CommentReactionSummary": { "type": "object", "properties": { "count": { "type": "integer" }, "emoji": { "type": "string" }, "reacted_by_me": { "type": "boolean" } } }, "models.CommentReactionUser": { "type": "object", "properties": { "name": { "type": "string" }, "profile_picture_url": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.CommentReactionUsersResponse": { "type": "object", "properties": { "comment_id": { "type": "string" }, "emoji": { "type": "string" }, "users": { "type": "array", "items": { "$ref": "#/definitions/models.CommentReactionUser" } } } }, "models.CommentReactionsSummaryResponse": { "type": "object", "properties": { "comment_id": { "type": "string" }, "reactions": { "type": "array", "items": { "$ref": "#/definitions/models.CommentReactionSummary" } } } }, "models.CommenterPreview": { "type": "object", "properties": { "name": { "type": "string" }, "profile_picture_url": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.ConfirmUploadRequest": { "type": "object", "required": [ "imageId" ], "properties": { "imageId": { "type": "string" }, "size": { "description": "Optional: if nil, confirm all sizes", "allOf": [ { "$ref": "#/definitions/models.ImageSize" } ] } } }, "models.ConfirmUploadResponse": { "type": "object", "properties": { "confirmed": { "type": "integer" }, "imageId": { "type": "string" }, "status": { "type": "string" } } }, "models.CreateActivityRequest": { "type": "object", "required": [ "name" ], "properties": { "category_names": { "type": "array", "maxItems": 10, "items": { "type": "string" } }, "dates": { "type": "array", "maxItems": 20, "items": { "$ref": "#/definitions/models.DateRange" } }, "description": { "type": "string" }, "estimated_price": { "type": "number", "minimum": 0 }, "image_ids": { "type": "array", "maxItems": 5, "items": { "type": "string" } }, "location_lat": { "type": "number", "maximum": 90, "minimum": -90 }, "location_lng": { "type": "number", "maximum": 180, "minimum": -180 }, "location_name": { "type": "string", "maxLength": 500, "minLength": 1 }, "media_url": { "type": "string" }, "name": { "type": "string", "maxLength": 255, "minLength": 1 }, "thumbnail_url": { "type": "string" }, "time_of_day": { "enum": [ "morning", "afternoon", "evening" ], "allOf": [ { "$ref": "#/definitions/models.ActivityTimeOfDay" } ] }, "trip_id": { "type": "string" } } }, "models.CreateCategoryRequest": { "type": "object", "required": [ "label", "name", "trip_id" ], "properties": { "icon": { "type": "string", "maxLength": 255 }, "label": { "type": "string", "maxLength": 255, "minLength": 1 }, "name": { "type": "string", "maxLength": 255, "minLength": 1 }, "trip_id": { "type": "string" } } }, "models.CreateCommentReactionRequest": { "type": "object", "required": [ "emoji" ], "properties": { "emoji": { "type": "string", "minLength": 1 } } }, "models.CreateCommentRequest": { "type": "object", "required": [ "content", "entity_id", "entity_type", "trip_id" ], "properties": { "content": { "type": "string", "minLength": 1 }, "entity_id": { "type": "string" }, "entity_type": { "enum": [ "activity", "pitch" ], "allOf": [ { "$ref": "#/definitions/models.EntityType" } ] }, "trip_id": { "type": "string" } } }, "models.CreateMembershipRequest": { "type": "object", "required": [ "budget_max", "budget_min", "trip_id", "user_id" ], "properties": { "budget_max": { "type": "integer", "minimum": 0 }, "budget_min": { "type": "integer", "minimum": 0 }, "is_admin": { "type": "boolean" }, "trip_id": { "type": "string" }, "user_id": { "type": "string" } } }, "models.CreateNotificationPreferencesRequest": { "type": "object", "properties": { "deadline_reminders": { "type": "boolean" }, "finalized_decisions": { "type": "boolean" }, "push_enabled": { "type": "boolean" }, "trip_activity": { "type": "boolean" }, "upcoming_trip": { "type": "boolean" }, "voting_reminders": { "type": "boolean" } } }, "models.CreatePitchRequest": { "type": "object", "required": [ "content_length", "content_type", "title" ], "properties": { "content_length": { "type": "integer", "minimum": 1 }, "content_type": { "type": "string", "minLength": 1 }, "description": { "type": "string" }, "image_ids": { "type": "array", "maxItems": 5, "items": { "type": "string" } }, "title": { "type": "string", "minLength": 1 } } }, "models.CreatePitchResponse": { "type": "object", "properties": { "expires_at": { "type": "string" }, "pitch": { "$ref": "#/definitions/models.PitchAPIResponse" }, "upload_url": { "type": "string" } } }, "models.CreatePollOptionRequest": { "type": "object", "required": [ "name", "option_type" ], "properties": { "entity_id": { "type": "string" }, "entity_type": { "type": "string" }, "name": { "type": "string" }, "option_type": { "enum": [ "entity", "custom" ], "allOf": [ { "$ref": "#/definitions/models.OptionType" } ] } } }, "models.CreatePollRequest": { "type": "object", "required": [ "poll_type", "question" ], "properties": { "categories": { "type": "array", "items": { "type": "string" } }, "deadline": { "type": "string" }, "is_anonymous": { "type": "boolean" }, "options": { "type": "array", "items": { "$ref": "#/definitions/models.CreatePollOptionRequest" } }, "poll_type": { "enum": [ "single", "multi", "rank" ], "allOf": [ { "$ref": "#/definitions/models.PollType" } ] }, "question": { "type": "string" }, "should_notify_members": { "type": "boolean" } } }, "models.CreateTripInviteRequest": { "type": "object", "properties": { "expires_at": { "type": "string" } } }, "models.CreateTripRequest": { "type": "object", "required": [ "budget_max", "budget_min", "name" ], "properties": { "budget_max": { "type": "integer", "minimum": 0 }, "budget_min": { "type": "integer", "minimum": 0 }, "cover_image_id": { "type": "string" }, "currency": { "type": "string" }, "end_date": { "type": "string", "format": "date-time" }, "name": { "type": "string", "minLength": 1 }, "pitch_deadline": { "type": "string" }, "start_date": { "type": "string", "format": "date-time" } } }, "models.CreateUserRequest": { "type": "object", "required": [ "name", "phone_number", "username" ], "properties": { "name": { "type": "string", "minLength": 1 }, "phone_number": { "type": "string" }, "username": { "type": "string" } } }, "models.DateRange": { "type": "object", "properties": { "end": { "description": "ISO 8601 date format (YYYY-MM-DD)", "type": "string", "format": "date", "example": "2024-01-05" }, "start": { "description": "ISO 8601 date format (YYYY-MM-DD)", "type": "string", "format": "date", "example": "2024-01-01" } } }, "models.DayTime": { "type": "object", "properties": { "day": { "type": "integer" }, "time": { "type": "string" } } }, "models.DeleteCommentReactionRequest": { "type": "object", "required": [ "emoji" ], "properties": { "emoji": { "type": "string", "minLength": 1 } } }, "models.EntityType": { "type": "string", "enum": [ "activity", "pitch" ], "x-enum-varnames": [ "ActivityEntity", "PitchEntity" ] }, "models.GetFileAllSizesResponse": { "type": "object", "properties": { "files": { "type": "array", "items": { "$ref": "#/definitions/models.GetFileResponse" } }, "imageId": { "type": "string" } } }, "models.GetFileResponse": { "type": "object", "properties": { "contentType": { "type": "string" }, "imageId": { "type": "string" }, "size": { "$ref": "#/definitions/models.ImageSize" }, "url": { "type": "string" } } }, "models.ImageSize": { "type": "string", "enum": [ "large", "medium", "small" ], "x-enum-varnames": [ "ImageSizeLarge", "ImageSizeMedium", "ImageSizeSmall" ] }, "models.LatLng": { "type": "object", "properties": { "lat": { "type": "number" }, "lng": { "type": "number" } } }, "models.LinkType": { "type": "string", "enum": [ "airbnb", "booking_com", "tiktok", "instagram", "generic" ], "x-enum-varnames": [ "LinkTypeAirbnb", "LinkTypeBookingCom", "LinkTypeTikTok", "LinkTypeInstagram", "LinkTypeGeneric" ] }, "models.MatchedSubstring": { "type": "object", "properties": { "length": { "type": "integer" }, "offset": { "type": "integer" } } }, "models.Membership": { "type": "object", "properties": { "availability": { "type": "object", "additionalProperties": true }, "budget_max": { "type": "integer" }, "budget_min": { "type": "integer" }, "created_at": { "type": "string" }, "is_admin": { "type": "boolean" }, "notify_new_comments": { "type": "boolean" }, "notify_new_pitches": { "type": "boolean" }, "notify_new_polls": { "type": "boolean" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" } } }, "models.MembershipAPIResponse": { "type": "object", "properties": { "availability": { "type": "object", "additionalProperties": true }, "budget_max": { "type": "integer" }, "budget_min": { "type": "integer" }, "created_at": { "type": "string" }, "is_admin": { "type": "boolean" }, "name": { "type": "string" }, "notify_new_comments": { "type": "boolean" }, "notify_new_pitches": { "type": "boolean" }, "notify_new_polls": { "type": "boolean" }, "profile_picture_url": { "type": "string" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.MembershipCursorPageResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.MembershipAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.NotificationError": { "type": "object", "properties": { "message": { "type": "string" }, "token": { "type": "string" }, "user_id": { "type": "string" } } }, "models.NotificationPreferences": { "type": "object", "properties": { "created_at": { "type": "string" }, "deadline_reminders": { "type": "boolean" }, "finalized_decisions": { "type": "boolean" }, "push_enabled": { "type": "boolean" }, "trip_activity": { "type": "boolean" }, "upcoming_trip": { "type": "boolean" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" }, "voting_reminders": { "type": "boolean" } } }, "models.NotificationResponse": { "type": "object", "properties": { "errors": { "type": "array", "items": { "$ref": "#/definitions/models.NotificationError" } }, "failure_count": { "type": "integer" }, "success_count": { "type": "integer" } } }, "models.OpeningHours": { "type": "object", "properties": { "open_now": { "type": "boolean" }, "periods": { "type": "array", "items": { "$ref": "#/definitions/models.Period" } }, "weekday_text": { "type": "array", "items": { "type": "string" } } } }, "models.OptionType": { "type": "string", "enum": [ "entity", "custom" ], "x-enum-varnames": [ "OptionTypeEntity", "OptionTypeCustom" ] }, "models.OptionVotersResponse": { "type": "object", "properties": { "option_id": { "type": "string" }, "option_name": { "type": "string" }, "poll_id": { "type": "string" }, "total_voters": { "type": "integer" }, "voters": { "type": "array", "items": { "$ref": "#/definitions/models.VoterInfo" } } } }, "models.OptionWithScore": { "type": "object", "properties": { "average_rank": { "type": "number" }, "borda_score": { "type": "integer" }, "entity_id": { "type": "string" }, "entity_type": { "type": "string" }, "name": { "type": "string" }, "option_id": { "type": "string" }, "option_type": { "$ref": "#/definitions/models.OptionType" }, "rank_breakdown": { "type": "object", "additionalProperties": { "type": "integer" } }, "vote_count": { "type": "integer" } } }, "models.PaginatedCommentsResponse": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.CommentAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.ParseLinkRequest": { "type": "object", "required": [ "url" ], "properties": { "url": { "type": "string" } } }, "models.ParsedActivityData": { "type": "object", "properties": { "category_suggestions": { "type": "array", "items": { "type": "string" } }, "description": { "type": "string" }, "media_url": { "type": "string" }, "name": { "type": "string" }, "source_type": { "$ref": "#/definitions/models.LinkType" }, "source_url": { "type": "string" }, "thumbnail_url": { "type": "string" } } }, "models.Period": { "type": "object", "properties": { "close": { "$ref": "#/definitions/models.DayTime" }, "open": { "$ref": "#/definitions/models.DayTime" } } }, "models.PitchAPIResponse": { "type": "object", "properties": { "audio_url": { "type": "string" }, "comment_count": { "type": "integer" }, "comment_previews": { "type": "array", "items": { "$ref": "#/definitions/models.CommenterPreview" } }, "created_at": { "type": "string" }, "description": { "type": "string" }, "duration": { "type": "integer" }, "id": { "type": "string" }, "images": { "type": "array", "items": { "$ref": "#/definitions/models.PitchImageInfo" } }, "links": { "type": "array", "items": { "$ref": "#/definitions/models.PitchLink" } }, "name": { "type": "string" }, "profile_picture_url": { "type": "string" }, "title": { "type": "string" }, "trip_id": { "type": "string" }, "updated_at": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" } } }, "models.PitchCursorPageResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.PitchAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.PitchImageInfo": { "type": "object", "properties": { "id": { "type": "string" }, "medium_url": { "type": "string" } } }, "models.PitchLink": { "type": "object", "properties": { "added_by": { "type": "string" }, "created_at": { "type": "string" }, "description": { "type": "string" }, "domain": { "type": "string" }, "id": { "type": "string" }, "pitch_id": { "type": "string" }, "thumbnail_url": { "type": "string" }, "title": { "type": "string" }, "url": { "type": "string" } } }, "models.PlaceDetailsRequest": { "type": "object", "properties": { "fields": { "description": "Fields specifies which fields to return (optional)\nIf not specified, returns all available fields", "type": "array", "items": { "type": "string" } }, "input": { "description": "Input is the text to search for if PlaceID is not provided\nExample: \"Eiffel Tower\", \"Paris, France\"", "type": "string" }, "language": { "description": "Language is the language code for the results (optional)", "type": "string" }, "place_id": { "description": "PlaceID is the unique identifier for the place (from typeahead results)", "type": "string" } } }, "models.PlaceDetailsResponse": { "type": "object", "properties": { "address_components": { "type": "array", "items": { "$ref": "#/definitions/models.AddressComponent" } }, "formatted_address": { "description": "Address information", "type": "string" }, "formatted_phone_number": { "description": "Contact information", "type": "string" }, "geometry": { "description": "Location coordinates", "allOf": [ { "$ref": "#/definitions/models.PlaceGeometry" } ] }, "icon": { "type": "string" }, "international_phone_number": { "type": "string" }, "name": { "type": "string" }, "opening_hours": { "description": "Business information", "allOf": [ { "$ref": "#/definitions/models.OpeningHours" } ] }, "photos": { "description": "Photos", "type": "array", "items": { "$ref": "#/definitions/models.PlacePhoto" } }, "place_id": { "type": "string" }, "price_level": { "type": "integer" }, "rating": { "description": "Ratings and reviews", "type": "number" }, "types": { "description": "Place types", "type": "array", "items": { "type": "string" } }, "user_ratings_total": { "type": "integer" }, "utc_offset": { "description": "Additional information", "type": "integer" }, "vicinity": { "type": "string" }, "website": { "type": "string" } } }, "models.PlaceGeometry": { "type": "object", "properties": { "location": { "$ref": "#/definitions/models.LatLng" }, "viewport": { "$ref": "#/definitions/models.Bounds" } } }, "models.PlacePhoto": { "type": "object", "properties": { "height": { "type": "integer" }, "html_attributions": { "type": "array", "items": { "type": "string" } }, "photo_reference": { "type": "string" }, "photo_url": { "description": "PhotoURL is a generated URL to fetch the photo (optional, generated by backend)", "type": "string" }, "width": { "type": "integer" } } }, "models.PlacePrediction": { "type": "object", "properties": { "description": { "description": "Description is the human-readable name for this place", "type": "string" }, "main_text": { "description": "StructuredFormatting contains the main text and secondary text", "type": "string" }, "matched_substrings": { "description": "MatchedSubstrings indicates which parts of the description match the input", "type": "array", "items": { "$ref": "#/definitions/models.MatchedSubstring" } }, "place_id": { "description": "PlaceID is the unique identifier for this place", "type": "string" }, "secondary_text": { "type": "string" }, "types": { "type": "array", "items": { "type": "string" } } } }, "models.PlacesSearchResponse": { "type": "object", "properties": { "predictions": { "type": "array", "items": { "$ref": "#/definitions/models.PlacePrediction" } }, "status": { "type": "string" } } }, "models.PollAPIResponse": { "type": "object", "properties": { "categories": { "type": "array", "items": { "type": "string" } }, "created_at": { "type": "string" }, "created_by": { "type": "string" }, "deadline": { "type": "string" }, "id": { "type": "string" }, "is_anonymous": { "type": "boolean" }, "options": { "type": "array", "items": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "poll_type": { "$ref": "#/definitions/models.PollType" }, "question": { "type": "string" }, "should_notify_members": { "type": "boolean" }, "trip_id": { "type": "string" } } }, "models.PollCursorPageResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.PollAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.PollOptionAPIResponse": { "type": "object", "properties": { "entity_id": { "type": "string" }, "entity_type": { "type": "string" }, "id": { "type": "string" }, "name": { "type": "string" }, "option_type": { "$ref": "#/definitions/models.OptionType" }, "vote_count": { "type": "integer" }, "voted": { "type": "boolean" } } }, "models.PollType": { "type": "string", "enum": [ "single", "multi", "rank" ], "x-enum-varnames": [ "PollTypeSingle", "PollTypeMulti", "PollTypeRank" ] }, "models.PollVotersResponse": { "type": "object", "properties": { "poll_id": { "type": "string" }, "total_members": { "type": "integer" }, "total_voters": { "type": "integer" }, "voters": { "type": "array", "items": { "$ref": "#/definitions/models.VoterInfo" } } } }, "models.RSVPStatus": { "type": "string", "enum": [ "yes", "maybe", "no" ], "x-enum-varnames": [ "RSVPStatusGoing", "RSVPStatusMaybe", "RSVPStatusNotGoing" ] }, "models.RankChoiceVotersResponse": { "type": "object", "properties": { "option_id": { "type": "string" }, "poll_id": { "type": "string" }, "rank_position": { "type": "integer" }, "total_voters": { "type": "integer" }, "voters": { "type": "array", "items": { "$ref": "#/definitions/models.VoterInfo" } } } }, "models.RankPollAPIResponse": { "type": "object", "properties": { "categories": { "type": "array", "items": { "type": "string" } }, "created_at": { "type": "string" }, "created_by": { "type": "string" }, "deadline": { "type": "string" }, "id": { "type": "string" }, "is_anonymous": { "type": "boolean" }, "options": { "type": "array", "items": { "$ref": "#/definitions/models.PollOptionAPIResponse" } }, "poll_type": { "$ref": "#/definitions/models.PollType" }, "question": { "type": "string" }, "should_notify_members": { "type": "boolean" }, "trip_id": { "type": "string" } } }, "models.RankPollResultsResponse": { "type": "object", "properties": { "all_options": { "type": "array", "items": { "$ref": "#/definitions/models.OptionWithScore" } }, "created_at": { "type": "string" }, "created_by": { "type": "string" }, "deadline": { "type": "string" }, "poll_id": { "type": "string" }, "poll_type": { "$ref": "#/definitions/models.PollType" }, "question": { "type": "string" }, "top_3": { "type": "array", "items": { "$ref": "#/definitions/models.OptionWithScore" } }, "total_members": { "type": "integer" }, "total_voters": { "type": "integer" }, "user_has_voted": { "type": "boolean" }, "user_ranking": { "type": "array", "items": { "$ref": "#/definitions/models.UserRankingItem" } } } }, "models.RankingItem": { "type": "object", "required": [ "option_id", "rank" ], "properties": { "option_id": { "type": "string" }, "rank": { "type": "integer" } } }, "models.S3HealthCheckResponse": { "type": "object", "properties": { "bucketName": { "type": "string" }, "error": { "description": "Error contains the underlying error message when status is \"unhealthy\"", "type": "string" }, "region": { "type": "string" }, "status": { "type": "string" } } }, "models.SearchActivitiesResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.ActivityAPIResponse" } }, "limit": { "type": "integer" }, "offset": { "type": "integer" }, "total": { "type": "integer" } } }, "models.SearchMembersResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.MembershipAPIResponse" } }, "limit": { "type": "integer" }, "offset": { "type": "integer" }, "total": { "type": "integer" } } }, "models.SearchTripsResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.TripAPIResponse" } }, "limit": { "type": "integer" }, "offset": { "type": "integer" }, "total": { "type": "integer" } } }, "models.SendBulkNotificationRequest": { "type": "object", "required": [ "body", "title", "user_ids" ], "properties": { "body": { "type": "string", "maxLength": 500, "minLength": 1 }, "data": { "type": "object", "additionalProperties": true }, "title": { "type": "string", "maxLength": 100, "minLength": 1 }, "user_ids": { "type": "array", "maxItems": 1000, "minItems": 1, "items": { "type": "string" } } } }, "models.SendNotificationRequest": { "type": "object", "required": [ "body", "title", "user_id" ], "properties": { "body": { "type": "string", "maxLength": 500, "minLength": 1 }, "data": { "type": "object", "additionalProperties": true }, "title": { "type": "string", "maxLength": 100, "minLength": 1 }, "user_id": { "type": "string" } } }, "models.SizedUploadURL": { "type": "object", "properties": { "size": { "$ref": "#/definitions/models.ImageSize" }, "url": { "type": "string" } } }, "models.SubmitRankingRequest": { "type": "object", "required": [ "rankings" ], "properties": { "rankings": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/models.RankingItem" } } } }, "models.TabListResponse": { "type": "object", "properties": { "tabs": { "type": "array", "items": { "$ref": "#/definitions/models.CategoryAPIResponse" } } } }, "models.Trip": { "type": "object", "properties": { "budget_max": { "type": "integer" }, "budget_min": { "type": "integer" }, "cover_image_id": { "type": "string" }, "created_at": { "type": "string" }, "currency": { "type": "string" }, "end_date": { "type": "string" }, "id": { "type": "string" }, "location": { "type": "string" }, "name": { "type": "string" }, "pitch_deadline": { "type": "string" }, "rank_poll_id": { "type": "string" }, "start_date": { "type": "string" }, "updated_at": { "type": "string" } } }, "models.TripAPIResponse": { "type": "object", "properties": { "budget_max": { "type": "integer" }, "budget_min": { "type": "integer" }, "cover_image_url": { "type": "string" }, "created_at": { "type": "string" }, "currency": { "type": "string" }, "end_date": { "type": "string", "format": "date-time" }, "id": { "type": "string" }, "location": { "type": "string" }, "member_count": { "type": "integer" }, "member_previews": { "type": "array", "items": { "$ref": "#/definitions/models.CommenterPreview" } }, "name": { "type": "string" }, "pitch_deadline": { "type": "string" }, "rank_poll_id": { "type": "string" }, "start_date": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string" } } }, "models.TripCursorPageResult": { "type": "object", "properties": { "items": { "type": "array", "items": { "$ref": "#/definitions/models.TripAPIResponse" } }, "limit": { "type": "integer" }, "next_cursor": { "type": "string" } } }, "models.TripInviteAPIResponse": { "type": "object", "properties": { "code": { "type": "string" }, "created_at": { "type": "string" }, "created_by": { "type": "string" }, "expires_at": { "type": "string" }, "id": { "type": "string" }, "is_revoked": { "type": "boolean" }, "join_url": { "type": "string" }, "trip_id": { "type": "string" } } }, "models.UpdateActivityRequest": { "type": "object", "properties": { "dates": { "description": "Max 20 date ranges", "type": "array", "maxItems": 20, "items": { "$ref": "#/definitions/models.DateRange" } }, "description": { "type": "string" }, "estimated_price": { "type": "number", "minimum": 0 }, "image_ids": { "type": "array", "maxItems": 5, "items": { "type": "string" } }, "location_lat": { "type": "number", "maximum": 90, "minimum": -90 }, "location_lng": { "type": "number", "maximum": 180, "minimum": -180 }, "location_name": { "type": "string", "maxLength": 500, "minLength": 1 }, "media_url": { "type": "string" }, "name": { "type": "string", "maxLength": 255, "minLength": 1 }, "thumbnail_url": { "type": "string" }, "time_of_day": { "enum": [ "morning", "afternoon", "evening" ], "allOf": [ { "$ref": "#/definitions/models.ActivityTimeOfDay" } ] } } }, "models.UpdateCategoryTabOrderRequest": { "type": "object", "required": [ "tabs" ], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/models.CategoryTabOrder" } } } }, "models.UpdateCommentRequest": { "type": "object", "required": [ "content" ], "properties": { "content": { "type": "string", "minLength": 1 } } }, "models.UpdateMembershipRequest": { "type": "object", "properties": { "budget_max": { "type": "integer", "minimum": 0 }, "budget_min": { "type": "integer", "minimum": 0 }, "is_admin": { "type": "boolean" } } }, "models.UpdateNotificationPreferencesRequest": { "type": "object", "properties": { "notify_new_comments": { "type": "boolean" }, "notify_new_pitches": { "type": "boolean" }, "notify_new_polls": { "type": "boolean" } } }, "models.UpdatePitchRequest": { "type": "object", "properties": { "description": { "type": "string" }, "duration": { "type": "integer", "minimum": 0 }, "image_ids": { "description": "ImageIDs, when non-nil, fully replaces the pitch's image associations.\nPass an empty slice to remove all images; omit the field to leave images unchanged.", "type": "array", "maxItems": 5, "items": { "type": "string" } }, "title": { "type": "string", "minLength": 1 } } }, "models.UpdatePollWithCategoriesRequest": { "type": "object", "properties": { "categories": { "type": "array", "items": { "type": "string" } }, "deadline": { "type": "string" }, "is_anonymous": { "type": "boolean" }, "question": { "type": "string" } } }, "models.UpdateTripRequest": { "type": "object", "properties": { "budget_max": { "type": "integer" }, "budget_min": { "type": "integer" }, "cover_image_id": { "type": "string" }, "currency": { "type": "string" }, "end_date": { "type": "string", "format": "date-time" }, "location": { "type": "string" }, "name": { "type": "string" }, "pitch_deadline": { "type": "string" }, "start_date": { "type": "string", "format": "date-time" } } }, "models.UpdateUserNotificationPreferencesRequest": { "type": "object", "properties": { "deadline_reminders": { "type": "boolean" }, "finalized_decisions": { "type": "boolean" }, "push_enabled": { "type": "boolean" }, "trip_activity": { "type": "boolean" }, "upcoming_trip": { "type": "boolean" }, "voting_reminders": { "type": "boolean" } } }, "models.UpdateUserRequest": { "type": "object", "properties": { "apple_maps_enabled": { "type": "boolean" }, "device_token": { "type": "string", "maxLength": 200 }, "google_maps_enabled": { "type": "boolean" }, "name": { "type": "string", "minLength": 1 }, "phone_number": { "type": "string" }, "profile_picture": { "type": "string" }, "timezone": { "type": "string" }, "username": { "type": "string" } } }, "models.UploadURLRequest": { "type": "object", "required": [ "contentType", "fileKey", "sizes" ], "properties": { "contentType": { "type": "string", "minLength": 1 }, "fileKey": { "type": "string", "minLength": 1 }, "sizes": { "type": "array", "maxItems": 3, "minItems": 1, "items": { "$ref": "#/definitions/models.ImageSize" } } } }, "models.UploadURLResponse": { "type": "object", "properties": { "expiresAt": { "type": "string" }, "fileKey": { "type": "string" }, "imageId": { "type": "string" }, "uploadUrls": { "type": "array", "items": { "$ref": "#/definitions/models.SizedUploadURL" } } } }, "models.User": { "type": "object", "properties": { "apple_maps_enabled": { "type": "boolean" }, "created_at": { "type": "string" }, "device_token": { "type": "string" }, "device_token_updated_at": { "type": "string" }, "google_maps_enabled": { "type": "boolean" }, "id": { "type": "string" }, "name": { "type": "string" }, "phone_number": { "type": "string" }, "profile_picture": { "type": "string" }, "timezone": { "type": "string" }, "updated_at": { "type": "string" }, "username": { "type": "string" } } }, "models.UserRankingItem": { "type": "object", "properties": { "option_id": { "type": "string" }, "option_name": { "type": "string" }, "rank_position": { "type": "integer" } } }, "models.VoterInfo": { "type": "object", "properties": { "has_voted": { "type": "boolean" }, "name": { "type": "string" }, "user_id": { "type": "string" }, "username": { "type": "string" }, "voted_at": { "type": "string" } } }, "realtime.Event": { "type": "object", "properties": { "actor_id": { "type": "string" }, "actor_name": { "type": "string" }, "data": { "type": "object" }, "entity_id": { "type": "string" }, "id": { "type": "string" }, "timestamp": { "type": "string" }, "topic": { "type": "string" }, "trip_id": { "type": "string" } } }, "realtime.UnreadCountResponse": { "type": "object", "properties": { "unread_count": { "type": "integer" } } } } }