# Looking API Reference > **Complete REST API documentation for the Looking backend** This document provides detailed information about all API endpoints, including request/response formats, authentication requirements, and error codes. --- ## πŸ“‹ Table of Contents - [Base URL](#base-url) - [Authentication](#authentication) - [Common Response Codes](#common-response-codes) - [Authentication Endpoints](#authentication-endpoints) - [Profile Endpoints](#profile-endpoints) - [User Endpoints](#user-endpoints) - [Geocache Endpoints](#geocache-endpoints) - [Error Handling](#error-handling) --- ## 🌐 Base URL **Development**: `http://localhost:3069` **Production**: `https://api.pfosi.mifi.dev` All endpoints are prefixed with the base URL. --- ## πŸ” Authentication Most endpoints require JWT authentication via the `Authorization` header. ### Header Format ``` Authorization: Bearer ``` ### Permission Levels | Permission | Description | | ---------- | ----------------------------------- | | **view** | Read-only access to profiles | | **add** | Create new profiles | | **edit** | Modify existing profiles | | **update** | Update profile details | | **delete** | Remove profiles | | **manage** | Approve submissions, manage content | | **super** | Full admin access, user management | ### Obtaining a Token Use the `/auth/login` endpoint (see [Authentication Endpoints](#authentication-endpoints)). --- ## πŸ“Š Common Response Codes | Code | Status | Description | | ------- | --------------------- | ----------------------------- | | **200** | OK | Request successful | | **201** | Created | Resource created successfully | | **400** | Bad Request | Invalid request data | | **401** | Unauthorized | Missing or invalid token | | **403** | Forbidden | Insufficient permissions | | **404** | Not Found | Resource not found | | **500** | Internal Server Error | Server error | --- ## πŸ”‘ Authentication Endpoints ### POST `/auth/login` Authenticate user and receive JWT token. **Request:** ```json POST /auth/login Content-Type: application/json { "username": "admin", "password": "password123" } ``` **Success Response (200):** ```json { "status": 200, "authorized": true, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "user": { "id": "507f1f77bcf86cd799439011", "username": "admin", "name": { "first": "John", "last": "Doe" }, "email": "admin@example.com", "can": ["add", "edit", "delete", "manage", "super", "update", "view"] } } ``` **Failure Response (401):** ```json { "status": 401, "authorized": false, "message": "Invalid username or password" } ``` --- ### POST `/auth/logout` Logout user (client-side token removal, no server-side action needed). **Request:** ```json POST /auth/logout Authorization: Bearer ``` **Response (200):** ```json { "message": "Logged out successfully" } ``` --- ### GET `/auth/session` Validate existing JWT token and get user info. **Request:** ``` GET /auth/session Authorization: Bearer ``` **Success Response (200):** ```json { "valid": true, "decoded": { "uid": "507f1f77bcf86cd799439011", "username": "admin", "can": ["add", "edit", "delete", "manage", "super", "update", "view"], "iat": 1640000000, "exp": 1640003600 } } ``` **Failure Response (401):** ```json { "valid": false, "message": "Token expired or invalid" } ``` --- ### POST `/auth/session` Create anonymous session token (limited permissions). **Request:** ```json POST /auth/session ``` **Response (200):** ```json { "status": 200, "authorized": false, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." } ``` --- ### PUT `/auth/session` Refresh existing JWT token (extend expiration). **Request:** ``` PUT /auth/session Authorization: Bearer ``` **Response (200):** ```json { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expiresIn": "15m" } ``` --- ### POST `/auth/reset` Request password reset email. **Request:** ```json POST /auth/reset Content-Type: application/json { "username": "admin" } ``` **Response (200):** ```json { "message": "Password reset email sent", "email": "ad***@example.com" } ``` --- ### GET `/auth/reset/:id/:token` Verify password reset token validity. **Request:** ``` GET /auth/reset/507f1f77bcf86cd799439011/abc123def456 ``` **Response (200):** ```json { "valid": true, "userId": "507f1f77bcf86cd799439011", "expires": "2024-01-15T12:00:00Z" } ``` --- ### PUT `/auth/reset/:id/:token` Reset password with valid token. **Request:** ```json PUT /auth/reset/507f1f77bcf86cd799439011/abc123def456 Content-Type: application/json { "password": "newPassword123", "confirmPassword": "newPassword123" } ``` **Response (200):** ```json { "message": "Password updated successfully", "success": true } ``` --- ## πŸ‘€ Profile Endpoints ### GET `/profiles` Get all approved profiles. **Request:** ``` GET /profiles ``` **Response (200):** ```json [ { "_id": "507f1f77bcf86cd799439011", "order": 1, "details": { "name": "John", "age": 28, "location": "San Francisco, CA", "about": "User's story about dating...", "pic": { "thumb": "profile/john_thumbnail.png", "detail": "profile/john_detail.png" }, "position": ["Top", "Versatile"], "looking": ["Dates", "Friends"], "tribes": ["Geek", "Jock"], "ethnos": ["White", "Latino"] }, "messages": [ { "_id": "507f191e810c19729de860ea", "text": "What brought you to dating apps?", "isUser": false, "timestamp": "2024-01-15T10:30:00Z" }, { "_id": "507f191e810c19729de860eb", "text": "I moved to a new city...", "isUser": true, "timestamp": "2024-01-15T10:32:00Z" } ], "submitted": true, "approved": true } ] ``` --- ### GET `/profiles/submitted` Get all submitted (pending approval) profiles. **Authentication**: Required (`view` permission) **Request:** ``` GET /profiles/submitted Authorization: Bearer ``` **Response (200):** ```json [ { "_id": "507f1f77bcf86cd799439012", "details": { ... }, "submitted": true, "approved": false } ] ``` --- ### GET `/profiles/verified` Alias for approved profiles. **Request:** ``` GET /profiles/verified ``` **Response**: Same as `GET /profiles` --- ### GET `/profiles/:id` Get single profile by ID. **Request:** ``` GET /profiles/507f1f77bcf86cd799439011 ``` **Response (200):** ```json { "_id": "507f1f77bcf86cd799439011", "order": 1, "details": { ... }, "messages": [ ... ], "submitted": true, "approved": true } ``` **Error (404):** ```json { "message": "Profile not found" } ``` --- ### POST `/profiles` Create new profile. **Authentication**: Required (`add` permission) **Request:** ```json POST /profiles Authorization: Bearer Content-Type: application/json { "order": 10, "details": { "name": "Alex", "age": 25, "location": "New York, NY", "about": "My story...", "pic": { "thumb": "data:image/png;base64,iVBORw0KG...", // Base64 or path "detail": "data:image/png;base64,iVBORw0KG..." } }, "messages": [ { "text": "Question text", "isUser": false } ], "submitted": true, "approved": false } ``` **Response (201):** ```json { "_id": "507f1f77bcf86cd799439013", "message": "Profile created successfully", "profile": { ... } } ``` --- ### PUT `/profiles/:id` Update existing profile. **Authentication**: Required (`update` permission) **Request:** ```json PUT /profiles/507f1f77bcf86cd799439011 Authorization: Bearer Content-Type: application/json { "details": { "about": "Updated story..." } } ``` **Response (200):** ```json { "message": "Profile updated successfully", "profile": { ... } } ``` --- ### DELETE `/profiles/:id` Delete profile by ID. **Authentication**: Required (`delete` permission) **Request:** ``` DELETE /profiles/507f1f77bcf86cd799439011 Authorization: Bearer ``` **Response (200):** ```json { "message": "Profile deleted successfully", "id": "507f1f77bcf86cd799439011" } ``` --- ### GET `/profiles/approve/:id` Approve submitted profile. **Authentication**: Required (`manage` permission) **Request:** ``` GET /profiles/approve/507f1f77bcf86cd799439012 Authorization: Bearer ``` **Response (200):** ```json { "message": "Profile approved", "profile": { "_id": "507f1f77bcf86cd799439012", "approved": true } } ``` --- ### POST `/profiles/submission` Submit new profile (public endpoint, no auth required). **Request:** ```json POST /profiles/submission Content-Type: application/json { "details": { "name": "Anonymous", "age": 30, "location": "Los Angeles, CA", "about": "My dating story...", "pic": { "thumb": "data:image/png;base64,...", "detail": "data:image/png;base64,..." } }, "messages": [ { "text": "Tell us your story", "isUser": false }, { "text": "I've been using apps for 3 years...", "isUser": true } ] } ``` **Response (200):** ```json { "message": "Story submitted successfully. It will be reviewed before publishing.", "profile": { "_id": "507f1f77bcf86cd799439014", "submitted": true, "approved": false } } ``` --- ### GET `/profiles/find/:limit?/:skip?/:min?/:max?/:pos?/:lkng?/:tribes?/:ethnos?` Advanced profile search with filters. **Authentication**: Required (`view` permission) **Parameters:** - `limit` - Number of results (default: all) - `skip` - Number to skip for pagination - `min` - Minimum age - `max` - Maximum age - `pos` - Position filter (pipe-separated: "Top|Bottom|Versatile") - `lkng` - Looking for filter (pipe-separated: "Dates|Friends|Relationship") - `tribes` - Tribes filter (pipe-separated: "Geek|Jock|Bear|Otter") - `ethnos` - Ethnicity filter (pipe-separated: "White|Black|Latino|Asian") **Request:** ``` GET /profiles/find/10/0/25/35/Top|Versatile/Dates|Friends/Geek/null Authorization: Bearer ``` **Response (200):** ```json [ { "_id": "507f1f77bcf86cd799439011", "details": { "age": 28, "position": ["Top", "Versatile"], "looking": ["Dates", "Friends"], "tribes": ["Geek"] } } ] ``` --- ### GET `/profiles/list/:limit?/:skip?/:min?/:max?/:pos?/:lkng?/:tribes?/:ethnos?` List profiles with minimal data (name, thumbnail only). **Authentication**: Required (`view` permission) **Response (200):** ```json [ { "_id": "507f1f77bcf86cd799439011", "order": 1, "details": { "name": "John", "pic": { "thumb": "profile/john_thumbnail.png" } } } ] ``` --- ### PUT `/profiles/:profileId/message/:messageId` Update specific message in profile thread. **Authentication**: Required (`update` permission) **Request:** ```json PUT /profiles/507f1f77bcf86cd799439011/message/507f191e810c19729de860ea Authorization: Bearer Content-Type: application/json { "text": "Updated question text", "image": "data:image/png;base64,..." } ``` **Response (200):** ```json { "message": "Message updated successfully", "profile": { ... } } ``` --- ## πŸ‘₯ User Endpoints ### GET `/users` Get all users. **Authentication**: Required (`super` permission) **Request:** ``` GET /users Authorization: Bearer ``` **Response (200):** ```json [ { "_id": "507f1f77bcf86cd799439011", "username": "admin", "name": { "first": "John", "last": "Doe" }, "email": "admin@example.com", "can": ["add", "edit", "delete", "manage", "super", "update", "view"], "forceReset": false } ] ``` --- ### GET `/users/:id` Get user by ID. **Authentication**: Required (`super` permission) **Response (200):** ```json { "_id": "507f1f77bcf86cd799439011", "username": "admin", "name": { "first": "John", "last": "Doe" }, "email": "admin@example.com", "can": ["super"] } ``` --- ### POST `/users` Create new user. **Authentication**: Required (`super` permission) **Request:** ```json POST /users Authorization: Bearer Content-Type: application/json { "username": "newuser", "password": "password123", "confirmPassword": "password123", "name": { "first": "Jane", "last": "Smith" }, "email": "jane@example.com", "can": ["view", "add"] } ``` **Response (201):** ```json { "message": "User created successfully", "user": { "_id": "507f1f77bcf86cd799439015", "username": "newuser" } } ``` --- ### PUT `/users/:id` Update user information. **Authentication**: Required (`super` permission or own user) **Request:** ```json PUT /users/507f1f77bcf86cd799439011 Authorization: Bearer Content-Type: application/json { "name": { "first": "John", "last": "Updated" }, "email": "newemail@example.com", "password": "newPassword123", "confirmPassword": "newPassword123", "currentPassword": "oldPassword123" } ``` **Response (200):** ```json { "message": "User updated successfully", "user": { ... } } ``` --- ### DELETE `/users/:id` Delete user. **Authentication**: Required (`super` permission) **Request:** ``` DELETE /users/507f1f77bcf86cd799439011 Authorization: Bearer ``` **Response (200):** ```json { "message": "User deleted successfully" } ``` --- ## πŸ—ΊοΈ Geocache Endpoints ### GET `/geocache/populate/:field` Populate geocache for a specific field (e.g., location). **Authentication**: Required (`manageAppPreferences` permission) **Request:** ``` GET /geocache/populate/location Authorization: Bearer ``` **Response (200):** ```json { "message": "Geocache populated", "count": 42, "results": [ { "key": "San Francisco, CA", "formatted": "San Francisco, California, USA", "loc": { "type": "Point", "coordinates": [-122.4194, 37.7749] } } ] } ``` --- ### PUT `/geocache/:id` Update geocache entry. **Authentication**: Required (`manageAppPreferences` permission) **Request:** ```json PUT /geocache/507f1f77bcf86cd799439011 Authorization: Bearer Content-Type: application/json { "key": "New York, NY", "formatted": "New York, New York, USA", "loc": { "type": "Point", "coordinates": [-74.0060, 40.7128] } } ``` **Response (200):** ```json { "message": "Geocache updated", "geocache": { ... } } ``` --- ## ⚠️ Error Handling ### Error Response Format All errors follow this structure: ```json { "message": "Human-readable error message", "err": { "code": "ERROR_CODE", "details": "Additional error information" } } ``` ### Common Error Messages | Error | Code | Cause | | ---------------------------------------------- | ---- | ------------------------------ | | **User not authorized to perform this action** | 403 | Missing required permission | | **Token expired or invalid** | 401 | JWT validation failed | | **Profile not found** | 404 | Invalid profile ID | | **Invalid username or password** | 401 | Login failed | | **Could not update profile** | 500 | Database error during update | | **There was an error processing the image** | 500 | Image upload/processing failed | | **No profile id or data specified** | 500 | Missing required request data | ### Authentication Errors **Missing Token:** ```json { "message": "No authorization token provided", "err": null } ``` **Invalid Token:** ```json { "message": "User not authorized to perform this action", "err": { "name": "JsonWebTokenError", "message": "invalid signature" } } ``` **Expired Token:** ```json { "message": "User not authorized to perform this action", "err": { "name": "TokenExpiredError", "message": "jwt expired", "expiredAt": "2024-01-15T12:00:00Z" } } ``` ### Validation Errors **Password Mismatch:** ```json { "success": false, "message": "There was an error saving the updated password." } ``` **Duplicate Username:** ```json { "message": "There was a duplicate key error", "err": { "code": 11000, "keyPattern": { "username": 1 } } } ``` --- ## πŸ“š Related Documentation - **[Backend README](README.md)** - Server setup and development - **[Database Schema](SCHEMA.md)** - MongoDB collection schemas - **[Environment Variables](.env.example)** - Configuration - **[Root README](../README.md)** - Project overview - **[Deployment Guide](../DEPLOYMENT.md)** - Production deployment --- **Need Help?** Check the backend [troubleshooting section](README.md#troubleshooting) for common API issues.