# BachelorGirl API Documentation

## Professional API Reference for Frontend & Mobile Developers

---

## 1. API OVERVIEW

### API Name
**BachelorGirl Services API**

### Description
A comprehensive REST API for a service booking platform that connects service providers (business owners) with customers. The platform supports real-time bookings, payments, reviews, messaging, and subscription management.

### Version
**v1.0.0**

### Base URL
- **Development**: `http://localhost:8000/api`
- **Staging**: `https://staging.bachelorgirl.com/api`
- **Production**: `https://api.bachelorgirl.com/api`

### Response Format
All responses are in **JSON** format with a consistent structure.

### Technology Stack
- **Backend**: Laravel 11
- **Authentication**: JWT (JSON Web Tokens)
- **Payment Gateway**: Stripe
- **Database**: MySQL/PostgreSQL
- **Real-time Features**: Laravel Reverb
- **Real-time Chat**: WebSocket-based messaging

---

## 2. ENVIRONMENT URLS

### Development Environment
```
Base URL: http://localhost:8000/api
WebSocket: ws://localhost:8080
Purpose: Local development and testing
Auth Guard: jwt/api
```

### Staging Environment
```
Base URL: https://staging.bachelorgirl.com/api
WebSocket: wss://staging.bachelorgirl.com:8080
Purpose: Pre-production testing
Auth Guard: jwt/api
```

### Production Environment
```
Base URL: https://api.bachelorgirl.com/api
WebSocket: wss://api.bachelorgirl.com:8080
Purpose: Live application
Auth Guard: jwt/api
Security: HTTPS enforced
```

---

## 3. AUTHENTICATION

### Authentication Type
**JWT (JSON Web Tokens) with Bearer Token Scheme**

The API uses industry-standard JWT authentication. Every protected endpoint requires a valid JWT token in the Authorization header.

### How to Login

#### Step 1: Register a New User

**Create Customer Account:**
```http
POST /customer/register
```

**Request Body:**
```json
{
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!"
}
```

**Create Business Owner Account:**
```http
POST /owner/register
```

**Request Body:**
```json
{
  "name": "Jane Service Provider",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!",
  "category_id": 1
}
```

**Response (200 - Success):**
```json
{
  "success": true,
  "message": "Registered. Please verify your email.",
  "data": [],
  "code": 200
}
```

After registration, an OTP (One-Time Password) is sent to the registered email.

#### Step 2: Verify OTP (if email verification is enabled)

#### Step 3: Login

**Your First Login:**
```http
POST /login
```

**Request Body:**
```json
{
  "email": "john@example.com",
  "password": "SecurePass123!"
}
```

**Response (200 - Success):**
```json
{
  "success": true,
  "message": "Login successful",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    },
    "role": "user"
  },
  "code": 200
}
```

### How to Store Token

#### Frontend Recommendations (React/Vue/Angular)

**Using LocalStorage** (Simple, but less secure):
```javascript
// After successful login
const response = await axios.post('/login', credentials);
const token = response.data.data.token.access_token;
localStorage.setItem('authToken', token);
localStorage.setItem('tokenType', 'Bearer');

// Later requests
axios.defaults.headers.common['Authorization'] = 
  `Bearer ${localStorage.getItem('authToken')}`;
```

**Using SessionStorage** (Cleared when tab closes):
```javascript
sessionStorage.setItem('authToken', token);
sessionStorage.setItem('tokenExpiry', expiryTime); // Unix timestamp
```

**Using Redux/Vuex** (Recommended for React/Vue):
```javascript
// In Redux slice or Vuex store
store.dispatch('auth/setToken', {
  access_token: token.access_token,
  token_type: token.token_type,
  expires_in: token.expires_in,
  expires_at: Date.now() + (token.expires_in * 1000)
});
```

**Best Practice - Token Refresh Strategy:**
```javascript
// Store expiry time
const expiresAt = Date.now() + (response.data.data.token.expires_in * 1000);
localStorage.setItem('tokenExpiresAt', expiresAt);

// Check before each request
if (Date.now() >= expiresAt - 60000) { // Refresh 1 minute before expiry
  await refreshToken();
}
```

#### Flutter/Mobile Recommendations

**Using Flutter Secure Storage:**
```dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:dio/dio.dart';

final storage = FlutterSecureStorage();

// After successful login
Future<void> saveToken(String accessToken, int expiresIn) async {
  await storage.write(
    key: 'access_token',
    value: accessToken,
  );
  
  final expiresAt = DateTime.now().add(Duration(seconds: expiresIn));
  await storage.write(
    key: 'token_expires_at',
    value: expiresAt.toIso8601String(),
  );
}

// Retrieve token for requests
Future<String?> getToken() async {
  return await storage.read(key: 'access_token');
}

// Add to Dio interceptor
dio.interceptors.add(
  InterceptorsWrapper(
    onRequest: (options, handler) async {
      final token = await getToken();
      if (token != null) {
        options.headers['Authorization'] = 'Bearer $token';
      }
      return handler.next(options);
    },
  ),
);
```

### How to Send Token in Headers

**Standard Authorization Header:**
```http
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

**cURL Example:**
```bash
curl -X GET "https://api.bachelorgirl.com/api/profile" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json"
```

**JavaScript/Axios Example:**
```javascript
const api = axios.create({
  baseURL: 'https://api.bachelorgirl.com/api',
  headers: {
    'Authorization': `Bearer ${localStorage.getItem('authToken')}`,
    'Content-Type': 'application/json',
    'Accept': 'application/json'
  }
});
```

**Flutter/Dio Example:**
```dart
final options = BaseOptions(
  baseUrl: 'https://api.bachelorgirl.com/api',
  headers: {
    'Authorization': 'Bearer $token',
    'Content-Type': 'application/json',
  },
);
```

### Token Expiration Behavior

**Token Lifetime:**
- **Duration**: 7 days (604,800 seconds)
- **Format**: JWT (JSON Web Token)
- **Signature Algorithm**: HS256 (HMAC SHA-256)

**What Happens When Token Expires:**
1. API returns `401 Unauthorized` status
2. Response body contains error message: `"Token is Expired"`
3. Client must refresh the token or ask user to login again

**Response When Token Expired:**
```json
{
  "status": false,
  "message": "Token is Expired",
  "data": [],
  "code": 401
}
```

### Refresh Token

To get a new token before/after expiration:

```http
POST /refresh
Authorization: Bearer YOUR_CURRENT_TOKEN
```

**Response (200 - Success):**
```json
{
  "success": true,
  "message": "Token refreshed",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    }
  },
  "code": 200
}
```

### Unauthorized Response Format

**When authentication fails:**

```json
{
  "status": false,
  "message": "Invalid email or password",
  "data": [],
  "code": 401
}
```

**When token is invalid:**
```json
{
  "status": false,
  "message": "Token is Invalid",
  "data": [],
  "code": 401
}
```

**When token is missing:**
```json
{
  "status": false,
  "message": "Unauthorised",
  "data": [],
  "code": 401
}
```

---

## 4. GLOBAL HEADERS

All API requests should include the following headers (except where noted as optional):

### Required Headers

**Content-Type**
```
Content-Type: application/json
```
Specifies request body format. Use `multipart/form-data` for file uploads.

**Accept**
```
Accept: application/json
```
Specifies expected response format.

**Authorization** (For Protected Endpoints)
```
Authorization: Bearer {JWT_TOKEN}
```
Required for all endpoints marked with `Authentication Required: Yes`

### Example Complete Headers

```http
GET /profile HTTP/1.1
Host: api.bachelorgirl.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
Accept: application/json
User-Agent: MyApp/1.0 (iOS 15.0)
```

### Custom Headers (Optional)

**Device Identifier** (For tracking):
```
X-Device-ID: unique-device-identifier
```

**API Version** (For versioning):
```
X-API-Version: v1
```

**Client Type** (For analytics):
```
X-Client-Type: mobile-ios | mobile-android | web
```

---

## 5. STANDARD RESPONSE STRUCTURE

### Success Response Format

All successful API responses follow this consistent structure:

```json
{
  "success": true,
  "message": "Operation completed successfully",
  "data": {},
  "code": 200
}
```

**Field Explanation:**

| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Always `true` for successful responses |
| `message` | string | Human-readable success message |
| `data` | object/array | The actual response data (varies by endpoint) |
| `code` | integer | HTTP status code (200, 201, etc.) |

### Error Response Format

All error responses follow this structure:

```json
{
  "status": false,
  "message": "Error message describing what went wrong",
  "data": [],
  "code": 400
}
```

**Field Explanation:**

| Field | Type | Description |
|-------|------|-------------|
| `status` | boolean | Always `false` for error responses |
| `message` | string | Human-readable error message |
| `data` | array/object | Error details or empty array |
| `code` | integer | HTTP status code (400, 401, 404, 500, etc.) |

### Validation Error Format

When request validation fails (HTTP 422):

```json
{
  "status": false,
  "message": "Validation failed",
  "data": {
    "email": [
      "The email field is required.",
      "The email must be a valid email address."
    ],
    "phone": [
      "The phone field is required."
    ]
  },
  "code": 422
}
```

### Pagination Response Format

For endpoints that return paginated data:

```json
{
  "success": true,
  "message": "Data fetched successfully",
  "data": {
    "items": [
      {
        "id": 1,
        "name": "Service 1",
        "price": 50
      },
      {
        "id": 2,
        "name": "Service 2",
        "price": 75
      }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 15,
      "total": 100,
      "last_page": 7,
      "from": 1,
      "to": 15
    }
  },
  "code": 200
}
```

**Pagination Fields:**

| Field | Type | Description |
|-------|------|-------------|
| `current_page` | integer | Current page number (1-indexed) |
| `per_page` | integer | Items per page |
| `total` | integer | Total number of items |
| `last_page` | integer | Last page number |
| `from` | integer | First item number on current page |
| `to` | integer | Last item number on current page |

### List Response with Meta Format

For collection responses with metadata:

```json
{
  "success": true,
  "message": "Bookings retrieved successfully",
  "data": {
    "total_booking": 45,
    "bookings": [
      {
        "id": 1,
        "date": "2024-02-15",
        "time": "10:00 AM",
        "status": "confirmed",
        "total": 150.00
      }
    ]
  },
  "code": 200
}
```

---

## 6. HTTP STATUS CODES USED

The API uses standard HTTP status codes to indicate the outcome of requests:

### 200 OK
**When**: Request succeeded, response contains data
**Use Case**: Successful GET, POST, PUT requests
```json
{
  "success": true,
  "message": "Data retrieved successfully",
  "data": {...},
  "code": 200
}
```

### 201 Created
**When**: A new resource was successfully created
**Use Case**: After POST requests that create records (user, booking, etc.)
```json
{
  "success": true,
  "message": "Booking created successfully",
  "data": {
    "id": 123,
    "status": "pending"
  },
  "code": 201
}
```

### 400 Bad Request
**When**: Request has invalid syntax or parameters
**Use Case**: Missing required fields, invalid data types, malformed JSON
```json
{
  "status": false,
  "message": "Invalid request parameters",
  "data": {
    "error": "Missing required field: email"
  },
  "code": 400
}
```

**Common Scenarios:**
- Missing required query parameters
- Invalid format for dates, numbers, etc.
- Malformed JSON in request body

### 401 Unauthorized
**When**: User authentication failed or token is invalid
**Use Case**: Missing token, invalid token, expired token
```json
{
  "status": false,
  "message": "Token is Expired",
  "data": [],
  "code": 401
}
```

**Common Scenarios:**
- No Authorization header provided
- Invalid email/password during login
- JWT token is expired
- JWT token is malformed

### 403 Forbidden
**When**: User is authenticated but doesn't have permission
**Use Case**: User trying to access another user's data, insufficient permissions
```json
{
  "status": false,
  "message": "You cannot access this resource",
  "data": [],
  "code": 403
}
```

**Common Scenarios:**
- Customer trying to access owner-only endpoints
- User trying to modify another user's profile
- Account is inactive/suspended

### 404 Not Found
**When**: Requested resource doesn't exist
**Use Case**: Booking not found, User not found, Service not found
```json
{
  "status": false,
  "message": "Service not found",
  "data": [],
  "code": 404
}
```

**Common Scenarios:**
- Invalid user ID in URL
- Service that doesn't exist
- Booking that was already deleted

### 422 Unprocessable Entity
**When**: Request validation failed (Laravel validation)
**Use Case**: Invalid email, password too weak, unique constraint violation
```json
{
  "status": false,
  "message": "Validation failed",
  "data": {
    "email": ["Email already exists"],
    "password": ["Password must be at least 8 characters"]
  },
  "code": 422
}
```

**Common Scenarios:**
- Duplicate email registration
- Email not valid format
- Phone number already exists
- Password doesn't meet strength requirements

### 429 Too Many Requests
**When**: Rate limit exceeded
**Use Case**: User sending too many requests in short time
```json
{
  "status": false,
  "message": "Please wait 1 minute",
  "data": [],
  "code": 429
}
```

### 500 Internal Server Error
**When**: Server error occurred
**Use Case**: Unhandled exception, database error, stripe error
```json
{
  "status": false,
  "message": "Registration failed",
  "data": [],
  "code": 500
}
```

**Common Scenarios:**
- Database connection error
- Stripe payment processing failed
- Unexpected server exception
- Email sending failed

---

## 7. FULL ENDPOINT DOCUMENTATION

### Auth Endpoints

#### Register as Customer

**Endpoint:** `POST /customer/register`

**Description:** Create a new customer account. After registration, an OTP is sent to the provided email for verification.

**Authentication Required:** No

**Middleware Applied:** None (public endpoint)

**Request Headers:**
```http
Content-Type: application/json
Accept: application/json
```

**Request Body:**
```json
{
  "name": "John Doe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!"
}
```

**Request Field Details:**

| Field | Type | Required | Description | Validation Rules |
|-------|------|----------|-------------|------------------|
| `name` | string | Yes | Full name | Max 255 characters |
| `email` | string | Yes | Email address | Valid email format, must be unique |
| `phone` | string | Yes | Phone number | Must be unique |
| `password` | string | Yes | Password | Min 8 chars, must contain letters, numbers, symbols |
| `password_confirmation` | string | Yes | Confirm password | Must match `password` field |

**Example Request:**
```bash
curl -X POST "https://api.bachelorgirl.com/api/customer/register" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Smith",
    "email": "jane.smith@example.com",
    "phone": "+1-555-0123",
    "password": "MySecurePass123!",
    "password_confirmation": "MySecurePass123!"
  }'
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Registered. Please verify your email.",
  "data": [],
  "code": 200
}
```

**Validation Error Response (422):**
```json
{
  "status": false,
  "message": "Validation Error",
  "data": {
    "email": [
      "The email has already been taken."
    ],
    "phone": [
      "The phone has already been taken."
    ]
  },
  "code": 422
}
```

**Error Responses:**

| Status | Message | Reason |
|--------|---------|--------|
| 422 | Email already exists | Email in database |
| 422 | Phone already exists | Phone in database |
| 422 | Password must contain symbols | Password too weak |
| 500 | Email sending failed | SMTP error |
| 500 | Registration failed | Database error |

---

#### Register as Business Owner

**Endpoint:** `POST /owner/register`

**Description:** Create a new business owner account. Business owners can provide services. They must select a category during registration.

**Authentication Required:** No

**Middleware Applied:** None

**Request Body:**
```json
{
  "name": "Jane Service Provider",
  "email": "jane@example.com",
  "phone": "+1234567890",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!",
  "category_id": 1
}
```

**Request Field Details:**

| Field | Type | Required | Description | Validation Rules |
|-------|------|----------|-------------|------------------|
| `name` | string | Yes | Full name | Max 255 characters |
| `email` | string | Yes | Email address | Valid email, must be unique |
| `phone` | string | Yes | Phone number | Must be unique |
| `password` | string | Yes | Password | Min 8 chars, letters, numbers, symbols |
| `password_confirmation` | string | Yes | Confirm password | Must match password |
| `category_id` | integer | Yes | Service category | Must exist in categories table |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Registered successfully. Please verify your email.",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    },
    "stripe_onboarding_url": "https://connect.stripe.com/onboarding/..."
  },
  "code": 200
}
```

**Note:** Business owners must complete Stripe onboarding to accept payments.

---

#### Login

**Endpoint:** `POST /login`

**Description:** Authenticate user credentials and return JWT token. Works for both customers and business owners.

**Authentication Required:** No

**Middleware Applied:** None

**Request Body:**
```json
{
  "email": "john@example.com",
  "password": "SecurePass123!"
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | Registered email address |
| `password` | string | Yes | Account password |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Login successful",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    },
    "role": "user"
  },
  "code": 200
}
```

**Response Field Explanation:**

| Field | Description |
|-------|-------------|
| `access_token` | JWT token to use for authenticated requests |
| `token_type` | Always "Bearer" |
| `expires_in` | Token lifetime in seconds (7 days) |
| `role` | User role ("user" for customer, "owner" for business owner) |

**Error Responses:**

| Status | Message | Reason |
|--------|---------|--------|
| 422 | Email is required | Missing email |
| 422 | Password is required | Missing password |
| 401 | Invalid email or password | Credentials don't match |
| 403 | Account is inactive | User account suspended |

---

#### Google Social Login

**Endpoint:** `POST /social-login/google`

**Description:** Authenticate using Google Sign-In. Creates account automatically if user doesn't exist.

**Authentication Required:** No

**Request Body:**
```json
{
  "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ..."
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `id_token` | string | Yes | Google ID token from Google Sign-In SDK |

**JavaScript Example:**
```javascript
import { GoogleLogin } from '@react-oauth/google';

function LoginButton() {
  const handleSuccess = async (credentialResponse) => {
    const response = await axios.post('/api/social-login/google', {
      id_token: credentialResponse.credential
    });
    // Handle token
    const token = response.data.data.token.access_token;
    localStorage.setItem('authToken', token);
  };

  return <GoogleLogin onSuccess={handleSuccess} />;
}
```

**Flutter Example:**
```dart
import 'package:google_sign_in/google_sign_in.dart';
import 'package:dio/dio.dart';

final googleSignIn = GoogleSignIn();

Future<void> googleLogin() async {
  try {
    final GoogleSignInAccount? googleUser = await googleSignIn.signIn();
    
    if (googleUser != null) {
      final GoogleSignInAuthentication googleAuth = 
          await googleUser.authentication;
      
      final response = await dio.post('/social-login/google', 
        data: {
          'id_token': googleAuth.idToken,
        }
      );
      
      final token = response.data['data']['token']['access_token'];
      await storage.write(key: 'access_token', value: token);
    }
  } catch (error) {
    print('Google login failed: $error');
  }
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Google login successful",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    },
    "role": "user"
  },
  "code": 200
}
```

---

#### Logout

**Endpoint:** `POST /logout`

**Description:** Invalidate current JWT token and logout user.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Request Headers:**
```http
Authorization: Bearer {JWT_TOKEN}
Content-Type: application/json
```

**Request Body:**
```json
{}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Logged out successfully",
  "data": [],
  "code": 200
}
```

**Error Response (401):**
```json
{
  "status": false,
  "message": "Token is Expired",
  "data": [],
  "code": 401
}
```

**JavaScript Example:**
```javascript
async function logout() {
  try {
    await axios.post('/api/logout', {}, {
      headers: {
        'Authorization': `Bearer ${localStorage.getItem('authToken')}`
      }
    });
    
    // Clear local storage
    localStorage.removeItem('authToken');
    localStorage.removeItem('tokenExpiresAt');
    
    // Redirect to login
    window.location.href = '/login';
  } catch (error) {
    console.error('Logout failed:', error);
  }
}
```

---

#### Forget Password

**Endpoint:** `POST /forget-password`

**Description:** Request password reset link. Sends OTP to registered email.

**Authentication Required:** No

**Request Body:**
```json
{
  "email": "john@example.com"
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | Account email address |

**Success Response (200):**
```json
{
  "success": true,
  "message": "OTP sent to your email",
  "data": [],
  "code": 200
}
```

**Error Responses:**

| Status | Message |
|--------|---------|
| 404 | Email not found |
| 500 | Email sending failed |

---

#### Verify OTP (for Password Reset)

**Endpoint:** `POST /verify-otp-password`

**Description:** Verify OTP sent to email during password reset flow.

**Authentication Required:** No

**Request Body:**
```json
{
  "email": "john@example.com",
  "otp": "123456"
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | Account email |
| `otp` | string | Yes | 6-digit OTP |

**Success Response (200):**
```json
{
  "success": true,
  "message": "OTP verified",
  "data": {
    "email": "john@example.com",
    "reset_token": "abc123xyz789..."
  },
  "code": 200
}
```

**Error Responses:**

| Status | Message | Reason |
|--------|---------|--------|
| 400 | OTP expired | More than 10 minutes passed |
| 400 | Invalid OTP | Wrong OTP code |

---

#### Reset Password

**Endpoint:** `POST /reset-password`

**Description:** Set new password using reset token from OTP verification.

**Authentication Required:** No

**Request Body:**
```json
{
  "email": "john@example.com",
  "password": "NewSecurePass123!",
  "password_confirmation": "NewSecurePass123!",
  "reset_token": "abc123xyz789..."
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | Account email |
| `password` | string | Yes | New password (8+ chars, letters, numbers, symbols) |
| `password_confirmation` | string | Yes | Confirm new password |
| `reset_token` | string | Yes | Token from OTP verification |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Password reset successful",
  "data": {
    "token": {
      "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "token_type": "Bearer",
      "expires_in": 604800
    }
  },
  "code": 200
}
```

---

### Service Management Endpoints

#### Get All Services (Public)

**Endpoint:** `GET /service/getAllServices`

**Description:** Retrieve all active services. No authentication required.

**Authentication Required:** No

**Query Parameters:**

| Parameter | Type | Required | Description | Example |
|-----------|------|----------|-------------|---------|
| `page` | integer | No | Page number | 1 |
| `limit` | integer | No | Items per page | 15 |
| `search` | string | No | Search by service title | "cleaning services" |
| `category_id` | integer | No | Filter by category | 1 |

**Example Request:**
```http
GET /service/getAllServices?page=1&limit=15&category_id=1
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Service retrieved successfully",
  "data": [
    {
      "id": 1,
      "title": "House Cleaning",
      "description": "Professional house cleaning service",
      "price": 50,
      "duration": "2 hours",
      "service_at": "person",
      "location": "Downtown Area",
      "image": "https://api.bachelorgirl.com/uploads/service-1.jpg",
      "owner": {
        "id": 5,
        "name": "Jane Service Provider",
        "avatar": "https://api.bachelorgirl.com/uploads/avatar-5.jpg"
      },
      "average_rating": 4.5,
      "total_reviews": 32
    }
  ],
  "code": 200
}
```

**Error Response (404):**
```json
{
  "status": false,
  "message": "No services found",
  "data": [],
  "code": 404
}
```

---

#### Get Owner Services

**Endpoint:** `GET /service/getOwnerServices`

**Description:** Get all services for authenticated business owner.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `service_id` | integer | Filter by specific service |
| `title` | string | Search by title |

**Example Request:**
```http
GET /service/getOwnerServices?title=cleaning
Authorization: Bearer {JWT_TOKEN}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Service retrieved successfully",
  "data": [
    {
      "id": 1,
      "title": "Home Cleaning",
      "description": "Complete home cleaning service",
      "price": 50,
      "duration": "2 hours",
      "is_deposite": "yes",
      "minimum_deposite": 25,
      "tax": 5,
      "service_at": "person",
      "location": "Downtown",
      "long": "-87.6298",
      "lat": "41.8781",
      "slug": "home-cleaning",
      "image": "https://api.bachelorgirl.com/uploads/service-1.jpg",
      "status": "active",
      "time_slots": [
        {
          "id": 1,
          "time": "09:00 AM"
        },
        {
          "id": 2,
          "time": "10:00 AM"
        }
      ],
      "more_images": [
        {
          "id": 1,
          "image": "https://api.bachelorgirl.com/uploads/service-1-extra.jpg"
        }
      ]
    }
  ],
  "code": 200
}
```

---

#### Create Service

**Endpoint:** `POST /service/create`

**Description:** Create a new service (Business owners only).

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Request Body:**
```json
{
  "title": "Home Cleaning",
  "description": "Professional cleaning of your home",
  "duration": "2 hours",
  "price": 50,
  "is_deposite": "yes",
  "minimum_deposite": 25,
  "tax": 5,
  "service_at": "person",
  "location": "Downtown Area",
  "long": "-87.6298",
  "lat": "41.8781",
  "zip_code": "60601",
  "status": "active"
}
```

**Request Field Details:**

| Field | Type | Required | Description | Validation |
|-------|------|----------|-------------|-----------|
| `title` | string | Yes | Service name | Max 255 chars |
| `description` | string | No | Service details | Text field |
| `duration` | string | No | Service duration | E.g., "2 hours" |
| `price` | numeric | No | Service price | Min 0 |
| `is_deposite` | string | No | Requires deposit | "yes" or "no" |
| `minimum_deposite` | numeric | Yes if `is_deposite=yes` | Minimum deposit | Min 0 |
| `tax` | numeric | No | Tax amount | |
| `service_at` | string | Yes | Service location type | "person" or "virtual" |
| `location` | string | Yes if `service_at=person` | Physical location | String |
| `long` | string | Yes if `service_at=person` | Longitude | GPS coordinate |
| `lat` | string | Yes if `service_at=person` | Latitude | GPS coordinate |
| `zip_code` | string | No | Area postal code | |
| `status` | string | No | Service status | "active" or "inactive" |

**File Upload:**

To include service image, use `multipart/form-data`:

```javascript
const formData = new FormData();
formData.append('title', 'Home Cleaning');
formData.append('price', 50);
formData.append('service_at', 'person');
formData.append('location', 'Downtown');
formData.append('long', '-87.6298');
formData.append('lat', '41.8781');
formData.append('image', fileInput.files[0]);

axios.post('/api/service/create', formData, {
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'multipart/form-data'
  }
});
```

**Success Response (201):**
```json
{
  "success": true,
  "message": "Service created successfully",
  "data": {
    "id": 1,
    "title": "Home Cleaning",
    "price": 50,
    "status": "active"
  },
  "code": 201
}
```

---

### Booking Endpoints

#### Create Booking (Customer)

**Endpoint:** `POST /book/service`

**Description:** Create new service booking as customer.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Request Body:**
```json
{
  "service_id": 1,
  "date": "2024-02-20",
  "time_slot_id": 5,
  "advance": 25,
  "remark": "Please be on time",
  "payment_method": "stripe"
}
```

**Request Field Details:**

| Field | Type | Required | Description | Validation |
|-------|------|----------|-------------|-----------|
| `service_id` | integer | Yes | Service to book | Must exist |
| `date` | string | Yes | Booking date | Format: YYYY-MM-DD, future date |
| `time_slot_id` | integer | Yes | Time slot | Must exist for service |
| `advance` | numeric | Yes | Advance amount to pay | Min 0 |
| `remark` | string | No | Special requests | Max 500 chars |
| `payment_method` | string | Yes | Payment method | "stripe" or "wallet" |

**Success Response (201):**
```json
{
  "success": true,
  "message": "Booking created successfully",
  "data": {
    "id": 123,
    "service_id": 1,
    "customer_id": 10,
    "date": "2024-02-20",
    "status": "pending",
    "total": 50,
    "advance": 25,
    "due": 25,
    "payment_status": "unpaid"
  },
  "code": 201
}
```

---

#### Get Customer Bookings

**Endpoint:** `GET /get/customer/booking`

**Description:** Retrieve all bookings for authenticated customer.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `status` | string | Filter: "pending", "confirmed", "cancelled" |
| `date_filter` | string | Filter: "today", "week", "month" |
| `limit` | integer | Results per page |

**Example Request:**
```http
GET /get/customer/booking?status=confirmed&date_filter=week
Authorization: Bearer {JWT_TOKEN}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Booking data fetched successfully",
  "data": {
    "total_booking": 5,
    "bookings": [
      {
        "id": 1,
        "date": "2024-02-20",
        "time": "10:00 AM",
        "status": "confirmed",
        "total": 50,
        "advance": 25,
        "due": 25,
        "payment_status": "paid",
        "service": {
          "id": 1,
          "title": "House Cleaning",
          "price": 50,
          "image": "https://api.bachelorgirl.com/uploads/service-1.jpg"
        },
        "owner": {
          "id": 5,
          "name": "Jane Provider",
          "avatar": "https://api.bachelorgirl.com/uploads/avatar-5.jpg"
        }
      }
    ]
  },
  "code": 200
}
```

---

### Booking-Due Payment Endpoints

These endpoints handle payment requests for remaining balance after partial payment:

#### Get Payment Requests (For Customer)

**Endpoint:** `GET /get/payment/requests`

**Description:** Get the customer request inbox for owner-created due-payment requests, ordered by most recent request time.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Success Response (200):**
```json
{
  "success": true,
  "message": "Payment requests fetched",
  "data": [
    {
      "id": 1,
      "booking_id": 123,
      "requested_amount": 25,
      "full_payable_amount": 100,
      "status_request": "pending",
      "requested_at": "2024-02-15T10:30:00Z",
      "booking": {
        "id": 123,
        "service_id": 1,
        "date": "2024-02-20"
      }
    }
  ],
  "code": 200
}
```

---

#### Pay Due Amount

**Endpoint:** `POST /pay/due/amount`

**Description:** Create a Stripe checkout session for a due-payment request.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "due_id": 1,
  "type": "partial"
}
```

**Success Response (201):**
```json
{
  "success": true,
  "message": "Payment successful",
  "data": {
    "transaction_id": "ch_1234567890",
    "amount": 25,
    "status": "paid"
  },
  "code": 201
}
```

---

### Profile & Account Endpoints

#### Get Profile

**Endpoint:** `GET /profile`

**Description:** Get authenticated user's profile information.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Success Response (200):**
```json
{
  "success": true,
  "message": "Profile loaded",
  "data": {
    "id": 10,
    "name": "John Doe",
    "email": "john@example.com",
    "phone": "+1234567890",
    "avatar": "https://api.bachelorgirl.com/uploads/avatar-10.jpg",
    "username": "johndoe",
    "description": "Professional service provider",
    "status": "active",
    "role": "user",
    "category": {
      "id": 1,
      "name": "Cleaning Services"
    },
    "stripe_account_status": "completed"
  },
  "code": 200
}
```

---

#### Update Profile

**Endpoint:** `POST /profile/update`

**Description:** Update user profile information.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "name": "John Doe Updated",
  "phone": "+1234567890",
  "description": "Updated bio",
  "about_me": "About me section",
  "preffered_contact": "email"
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Profile updated successfully",
  "data": {
    "id": 10,
    "name": "John Doe Updated",
    "phone": "+1234567890"
  },
  "code": 200
}
```

---

#### Update Password

**Endpoint:** `POST /update/password`

**Description:** Change user's password.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "old_password": "OldPassword123!",
  "new_password": "NewPassword123!",
  "new_password_confirmation": "NewPassword123!"
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Password updated successfully",
  "data": [],
  "code": 200
}
```

**Error Response (400):**
```json
{
  "status": false,
  "message": "Old password is incorrect",
  "data": [],
  "code": 400
}
```

---

### Review Endpoints

#### Store Review

**Endpoint:** `POST /review/store`

**Description:** Create a review for a completed service or business owner.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "rating": 5,
  "comment": "Excellent service! Very professional.",
  "service_id": 1,
  "booking_id": 123
}
```

**Request Field Details:**

| Field | Type | Required | Description | Validation |
|-------|------|----------|-------------|-----------|
| `rating` | integer | Yes | Rating | 1-5 |
| `comment` | string | Yes | Review text | Max 1000 chars |
| `service_id` | integer | Yes | Service reviewed | Must exist |
| `booking_id` | integer | Yes | Related booking | Must exist |

**Success Response (201):**
```json
{
  "success": true,
  "message": "Review created successfully",
  "data": {
    "id": 1,
    "rating": 5,
    "comment": "Excellent service!",
    "created_at": "2024-02-20T15:30:00Z"
  },
  "code": 201
}
```

---

#### Get Customer Reviews

**Endpoint:** `GET /review/getCustomerReviews`

**Description:** Get all reviews written by authenticated customer.

**Authentication Required:** Yes

**Success Response (200):**
```json
{
  "success": true,
  "message": "Reviews retrieved",
  "data": [
    {
      "id": 1,
      "rating": 5,
      "comment": "Great service!",
      "service": {
        "id": 1,
        "title": "House Cleaning"
      },
      "created_at": "2024-02-20T15:30:00Z"
    }
  ],
  "code": 200
}
```

---

### Chat Endpoints

#### Send Message

**Endpoint:** `POST /chat/send`

**Description:** Send chat message or file to another user.

**Authentication Required:** Yes

**Request Body (multipart/form-data):**
```json
{
  "receiver_id": 5,
  "message": "Hi, are you available this weekend?",
  "attachment": "<optional file>"
}
```

**Request Field Details:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `receiver_id` | integer | Yes | ID of recipient |
| `message` | string | Conditional | Required when `attachment` is not sent (max 1000 chars) |
| `attachment` | file | Conditional | Required when `message` is not sent (max 10MB) |

**Success Response (201):**
```json
{
  "success": true,
  "message": "Message sent successfully",
  "data": {
    "id": 100,
    "sender_id": 10,
    "receiver_id": 5,
    "message": "Hi, are you available this weekend?",
    "attachment_path": "chat-attachments/abc123.pdf",
    "attachment_name": "quote.pdf",
    "attachment_mime": "application/pdf",
    "attachment_size": 204800,
    "attachment_url": "https://example.com/storage/chat-attachments/abc123.pdf",
    "created_at": "2024-02-20T15:30:00Z"
  },
  "code": 201
}
```

**Note:** Realtime chat broadcasting is temporarily disabled. Users need to reload chat to see new incoming messages.

---

#### Fetch Messages

**Endpoint:** `GET /chat/get/{conversation_id}`

**Description:** Retrieve all messages in a conversation.

**Authentication Required:** Yes

**URL Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `conversation_id` | integer | Conversation ID |

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `page` | integer | Page number |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Messages retrieved",
  "data": {
    "messages": [
      {
        "id": 100,
        "sender_id": 10,
        "receiver_id": 5,
        "message": "Hi, are you available?",
        "created_at": "2024-02-20T15:30:00Z"
      }
    ],
    "pagination": {
      "current_page": 1,
      "total": 50,
      "per_page": 20
    }
  },
  "code": 200
}
```

---

### Category Endpoints

#### Get Categories

**Endpoint:** `GET /category/get`

**Description:** List all service categories.

**Authentication Required:** No

**Success Response (200):**
```json
{
  "success": true,
  "message": "Successfully!",
  "data": [
    {
      "id": 1,
      "name": "Cleaning Services",
      "image": "https://api.bachelorgirl.com/uploads/category-cleaning.jpg"
    },
    {
      "id": 2,
      "name": "Home Repair",
      "image": "https://api.bachelorgirl.com/uploads/category-repair.jpg"
    }
  ],
  "code": 200
}
```

---

### Static Pages Endpoints

#### Get Help Center

**Endpoint:** `GET /help-center`

**Description:** Get help center content.

**Authentication Required:** No

**Success Response (200):**
```json
{
  "success": true,
  "data": {
    "title": "Help Center",
    "content": "HTML content here..."
  },
  "code": 200
}
```

---

#### Get Privacy Policy

**Endpoint:** `GET /privacy-policy`

**Description:** Get privacy policy content.

**Authentication Required:** No

---

#### Get Terms & Conditions

**Endpoint:** `GET /terms-condition`

**Description:** Get terms and conditions.

**Authentication Required:** No

---

#### Get About Us

**Endpoint:** `GET /about-us`

**Description:** Get company about information.

**Authentication Required:** No

---

### Stripe Payment Endpoints

#### Get Onboard Link

**Endpoint:** `GET /stripe/onboard-link`

**Description:** Get Stripe Connect onboarding link for business owners. Used to complete Stripe verification.

**Authentication Required:** Yes

**Middleware Applied:** `auth:api`

**Success Response (200):**
```json
{
  "success": true,
  "message": "Onboard link generated",
  "data": {
    "onboard_url": "https://connect.stripe.com/onboarding/..."
  },
  "code": 200
}
```

---

### Notification Endpoints

#### Get Notifications

**Endpoint:** `GET /notifications`

**Description:** Retrieve all notifications for authenticated user.

**Authentication Required:** Yes

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `page` | integer | Page number |
| `limit` | integer | Items per page |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Notifications retrieved",
  "data": [
    {
      "id": 1,
      "type": "booking",
      "title": "New Booking",
      "message": "You have a new booking request",
      "read_at": null,
      "created_at": "2024-02-20T15:30:00Z"
    }
  ],
  "code": 200
}
```

---

#### Mark All Notifications as Read

**Endpoint:** `POST /notifications/mark-all-read`

**Description:** Mark all notifications as read.

**Authentication Required:** Yes

**Success Response (200):**
```json
{
  "success": true,
  "message": "All notifications marked as read",
  "data": [],
  "code": 200
}
```

---

#### Mark Single Notification as Read

**Endpoint:** `POST /notifications/mark-read`

**Description:** Mark specific notification as read.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "notification_id": 1
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Notification marked as read",
  "data": [],
  "code": 200
}
```

---

#### Delete All Notifications

**Endpoint:** `POST /notifications/delete-all`

**Description:** Delete all notifications for user.

**Authentication Required:** Yes

**Success Response (200):**
```json
{
  "success": true,
  "message": "All notifications deleted",
  "data": [],
  "code": 200
}
```

---

#### Delete Single Notification

**Endpoint:** `POST /notifications/delete`

**Description:** Delete specific notification.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "notification_id": 1
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Notification deleted",
  "data": [],
  "code": 200
}
```

---

### Favorite Services Endpoints

#### Add to Favorites

**Endpoint:** `POST /add-favourite`

**Description:** Add service to user favorites.

**Authentication Required:** Yes

**Request Body:**
```json
{
  "service_id": 1
}
```

**Success Response (200):**
```json
{
  "success": true,
  "message": "Service added to favourites successfully.",
  "data": [],
  "code": 200
}
```

**Error Response (400):**
```json
{
  "status": false,
  "message": "Service already exists in favourites.",
  "data": [],
  "code": 400
}
```

---

#### Get Favorites

**Endpoint:** `GET /get-favourite`

**Description:** Get all favorite services for user.

**Authentication Required:** Yes

**Success Response (200):**
```json
{
  "success": true,
  "message": "Favourite services retrieved",
  "data": [
    {
      "id": 1,
      "title": "House Cleaning",
      "price": 50,
      "image": "https://api.bachelorgirl.com/uploads/service-1.jpg"
    }
  ],
  "code": 200
}
```

---

#### Remove from Favorites

**Endpoint:** `GET /remove-favourite/{id}`

**Description:** Remove service from favorites.

**Authentication Required:** Yes

**URL Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | integer | Service ID |

**Success Response (200):**
```json
{
  "success": true,
  "message": "Service removed from favourites",
  "data": [],
  "code": 200
}
```

---

## 8. FILE UPLOAD APIs

### Uploading Service Images

When creating or updating a service with images, use `multipart/form-data`:

**Endpoint:** `POST /service/create` (with image)

**Request Type:** `multipart/form-data`

**Headers:**
```http
Authorization: Bearer {JWT_TOKEN}
Content-Type: multipart/form-data
```

**Form Fields:**
- `title` (string): Service title
- `price` (number): Service price
- `image` (file): Main service image
- `imgs[]` (file array): Additional images (optional)

**JavaScript FormData Example:**
```javascript
const uploadService = async (formData) => {
  try {
    const response = await axios.post('/api/service/create', formData, {
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'multipart/form-data'
      }
    });
    return response.data;
  } catch (error) {
    console.error('Upload failed:', error.response.data);
  }
};

// Usage
const formData = new FormData();
formData.append('title', 'Cleaning Service');
formData.append('price', 50);
formData.append('service_at', 'person');
formData.append('location', 'Downtown');
formData.append('long', '-87.6298');
formData.append('lat', '41.8781');
formData.append('image', document.getElementById('imageInput').files[0]);

uploadService(formData);
```

### File Size Limits

| File Type | Max Size |
|-----------|----------|
| Image (JPG, PNG, GIF) | 2 MB |
| Regular documents | 5 MB |

### Supported Formats

**Images:**
- `image/jpeg` (.jpg, .jpeg)
- `image/png` (.png)
- `image/gif` (.gif)
- `image/webp` (.webp)

### Flutter File Upload

```dart
import 'package:image_picker/image_picker.dart';
import 'package:dio/dio.dart';

Future<void> uploadService() async {
  final picker = ImagePicker();
  final image = await picker.pickImage(source: ImageSource.gallery);
  
  if (image != null) {
    FormData formData = FormData.fromMap({
      'title': 'Home Cleaning',
      'price': 50,
      'service_at': 'person',
      'location': 'Downtown',
      'long': '-87.6298',
      'lat': '41.8781',
      'image': await MultipartFile.fromFile(
        image.path,
        filename: 'service_image.jpg',
      ),
    });
    
    try {
      Response response = await dio.post(
        '/service/create',
        data: formData,
      );
      print('Upload successful: ${response.data}');
    } catch (e) {
      print('Upload failed: $e');
    }
  }
}
```

---

## 9. PAGINATION SYSTEM

### How Pagination Works

Most list endpoints support pagination to handle large datasets efficiently.

### Pagination Parameters

**Query Parameters:**

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `page` | integer | 1 | Current page (1-indexed) |
| `limit`/`per_page` | integer | 15 | Items per page |

### Pagination Response Structure

```json
{
  "success": true,
  "message": "Data fetched successfully",
  "data": {
    "items": [
      { "id": 1, "title": "Item 1" },
      { "id": 2, "title": "Item 2" }
    ],
    "pagination": {
      "current_page": 1,
      "per_page": 15,
      "total": 150,
      "last_page": 10,
      "from": 1,
      "to": 15,
      "next_page_url": "https://api.bachelorgirl.com/api/services?page=2",
      "prev_page_url": null
    }
  },
  "code": 200
}
```

**Pagination Fields:**

| Field | Type | Description |
|-------|------|-------------|
| `current_page` | integer | Current page number |
| `per_page` | integer | Items returned this page |
| `total` | integer | Total items available |
| `last_page` | integer | Last page number |
| `from` | integer | Item number of first result |
| `to` | integer | Item number of last result |
| `next_page_url` | string \| null | URL for next page (null if last page) |
| `prev_page_url` | string \| null | URL for previous page (null if first page) |

### Example Usage

**Get second page with 20 items per page:**
```http
GET /service/getAllServices?page=2&limit=20
```

### Frontend Pagination Implementation

**React Example:**
```javascript
import { useState, useEffect } from 'react';

function ServicesList() {
  const [services, setServices] = useState([]);
  const [page, setPage] = useState(1);
  const [pagination, setPagination] = useState(null);

  useEffect(() => {
    fetchServices(page);
  }, [page]);

  const fetchServices = async (pageNum) => {
    try {
      const response = await axios.get('/api/service/getAllServices', {
        params: { page: pageNum, limit: 15 }
      });
      
      setServices(response.data.data.items);
      setPagination(response.data.data.pagination);
    } catch (error) {
      console.error('Error fetching services:', error);
    }
  };

  return (
    <div>
      {/* Display services */}
      {services.map(service => (
        <div key={service.id}>{service.title}</div>
      ))}
      
      {/* Pagination buttons */}
      <div>
        <button 
          disabled={!pagination?.prev_page_url}
          onClick={() => setPage(page - 1)}
        >
          Previous
        </button>
        
        <span>Page {pagination?.current_page} of {pagination?.last_page}</span>
        
        <button 
          disabled={!pagination?.next_page_url}
          onClick={() => setPage(page + 1)}
        >
          Next
        </button>
      </div>
    </div>
  );
}
```

---

## 10. FILTERING / SEARCH / SORTING

### Filtering

**Filter by Status:**
```http
GET /get/customer/booking?status=confirmed
```

**Available Filters:**
- Booking Status: `pending`, `confirmed`, `cancelled`
- Payment Status: `paid`, `unpaid`
- Date: `today`, `week`, `month`

### Search

**Search Services:**
```http
GET /service/getAllServices?search=cleaning
```

**Search by Title:**
```http
GET /service/getOwnerServices?title=home
```

### Sorting

**Sort by Date (Descending):**
```http
GET /get/customer/booking?sort=-date
```

**Sort by Price (Ascending):**
```http
GET /service/getAllServices?sort=price
```

**Common Sort Parameters:**
- `sort=created_at` (Ascending)
- `sort=-created_at` (Descending)
- `sort=price` (Ascending)
- `sort=-price` (Descending)

### Combined Filters

```http
GET /get/customer/booking?status=confirmed&date_filter=week&limit=10
```

---

## 11. RATE LIMITING

Currently, the API does not enforce strict rate limiting for most endpoints. However, some operations like OTP generation have cooldown periods:

**OTP Request Cooldown:**
- Minimum 60 seconds between consecutive OTP requests
- Response: `429 Too Many Requests`

```json
{
  "status": false,
  "message": "Please wait 1 minute",
  "data": [],
  "code": 429
}
```

**Best Practices:**
1. Implement exponential backoff on client side
2. Cache responses when possible
3. Don't make unnecessary API calls
4. Respect rate limiting headers

---

## 12. ERROR HANDLING GUIDE FOR FRONTEND

### How Frontend Should Handle Different Errors

#### 1. Validation Errors (422)

These occur when request data doesn't meet validation rules:

```javascript
try {
  const response = await axios.post('/api/customer/register', {
    email: 'invalid-email',
    password: 'weak'
  });
} catch (error) {
  if (error.response.status === 422) {
    // Display validation errors to user
    const errors = error.response.data.data;
    Object.keys(errors).forEach(field => {
      errors[field].forEach(message => {
        console.error(`${field}: ${message}`);
        // Show in UI: "Email: The email must be a valid email address"
      });
    });
  }
}
```

#### 2. Expired Token (401)

When user's JWT token expires:

```javascript
// Set up axios interceptor to handle token expiration
axios.interceptors.response.use(
  response => response,
  async error => {
    if (error.response?.status === 401 && 
        error.response?.data?.message === 'Token is Expired') {
      
      // Try to refresh token
      try {
        const refreshResponse = await axios.post('/api/refresh');
        const newToken = refreshResponse.data.data.token.access_token;
        
        // Save new token
        localStorage.setItem('authToken', newToken);
        
        // Retry original request with new token
        error.config.headers.Authorization = `Bearer ${newToken}`;
        return axios(error.config);
      } catch (refreshError) {
        // Refresh failed, redirect to login
        localStorage.removeItem('authToken');
        window.location.href = '/login';
      }
    }
    
    return Promise.reject(error);
  }
);
```

#### 3. Resource Not Found (404)

When trying to access non-existent resource:

```javascript
try {
  const response = await axios.get(`/api/service/${serviceId}`);
} catch (error) {
  if (error.response.status === 404) {
    // Show user-friendly message
    alert('Service not found. It may have been deleted.');
    // Navigate back
    window.history.back();
  }
}
```

#### 4. Permission Denied (403)

When user tries to access resource they don't have permission for:

```javascript
try {
  const response = await axios.get(`/api/user/${userId}/edit`);
} catch (error) {
  if (error.response.status === 403) {
    alert('You do not have permission to access this resource.');
  }
}
```

#### 5. Server Errors (500)

Unexpected server errors:

```javascript
try {
  const response = await axios.post('/api/booking', bookingData);
} catch (error) {
  if (error.response?.status >= 500) {
    // Log to error tracking service
    Sentry.captureException(error);
    
    // Show generic message to user
    alert('An error occurred. Please try again later.');
    console.error('Server error:', error.response.data);
  }
}
```

#### 6. Network Errors

No internet connection or network timeout:

```javascript
try {
  const response = await axios.get('/api/profile');
} catch (error) {
  if (!error.response) {
    // Network error
    alert('No internet connection. Please check your network.');
  } else if (error.code === 'ECONNABORTED') {
    // Timeout
    alert('Request timed out. Please try again.');
  }
}
```

### Error Handling Best Practices

#### 1. Create Global Error Handler

```javascript
// Create a utility function
export const handleApiError = (error) => {
  const status = error.response?.status;
  const message = error.response?.data?.message;
  const data = error.response?.data?.data;

  switch (status) {
    case 401:
      if (message === 'Token is Expired') {
        return refreshTokenAndRetry();
      }
      return { error: 'Please log in again' };
    
    case 404:
      return { error: 'Resource not found' };
    
    case 422:
      return { error: 'Invalid data', validationErrors: data };
    
    case 500:
      return { error: 'Server error. Please try again later.' };
    
    default:
      return { error: message || 'An error occurred' };
  }
};

// Usage
try {
  const response = await api.get('/endpoint');
} catch (error) {
  const { error: errorMsg, validationErrors } = handleApiError(error);
  // Display error to user
}
```

#### 2. User-Friendly Error Messages

```javascript
const errorMessages = {
  'Invalid email or password': 'Email or password is incorrect',
  'The email has already been taken': 'Email already registered',
  'Token is Expired': 'Your session expired. Please log in again',
  'Account is inactive': 'Your account has been suspended'
};

const getUserFriendlyMessage = (apiMessage) => {
  return errorMessages[apiMessage] || apiMessage;
};
```

#### 3. Retry Logic with Exponential Backoff

```javascript
async function apiCallWithRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // Wait before retrying (exponential backoff)
      const delay = Math.pow(2, i) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Usage
apiCallWithRetry(() => axios.get('/api/services'));
```

---

## 13. DATA MODELS / OBJECT STRUCTURE

### User Object

```json
{
  "id": 10,
  "name": "John Doe",
  "username": "johndoe",
  "email": "john@example.com",
  "phone": "+1234567890",
  "avatar": "https://api.bachelorgirl.com/uploads/avatar-10.jpg",
  "description": "Professional service provider",
  "about_me": "More detailed bio",
  "status": "active",
  "email_verified_at": "2024-01-15T10:30:00Z",
  "category_id": 1,
  "balance": 500.00,
  "stripe_account_id": "acct_1234567890",
  "stripe_account_status": "completed",
  "created_at": "2024-01-10T08:00:00Z",
  "updated_at": "2024-02-20T15:30:00Z"
}
```

**Field Descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Unique user identifier |
| `name` | string | User's full name |
| `username` | string | Unique username handle |
| `email` | string | Email address |
| `phone` | string | Phone number |
| `avatar` | string | Profile image URL |
| `description` | string | Short bio (for owners) |
| `about_me` | string | Detailed bio |
| `status` | string | Account status: "active", "inactive" |
| `email_verified_at` | datetime | When email was verified |
| `category_id` | integer | Service category ID (for owners) |
| `balance` | decimal | Wallet balance |
| `stripe_account_id` | string | Stripe Connect account ID |
| `stripe_account_status` | string | Stripe verification: "pending", "completed" |

---

### Service Object

```json
{
  "id": 1,
  "owner_id": 5,
  "title": "House Cleaning",
  "description": "Professional house cleaning with eco-friendly products",
  "slug": "house-cleaning",
  "price": 50.00,
  "duration": "2 hours",
  "service_at": "person",
  "location": "Downtown Area",
  "long": "-87.6298",
  "lat": "41.8781",
  "zip_code": "60601",
  "image": "https://api.bachelorgirl.com/uploads/service-1.jpg",
  "is_deposite": true,
  "minimum_deposite": 25.00,
  "tax": 5.00,
  "status": "active",
  "category_id": 1,
  "created_at": "2024-01-15T10:30:00Z",
  "updated_at": "2024-02-20T15:30:00Z"
}
```

**Field Descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Service ID |
| `owner_id` | integer | Business owner's user ID |
| `title` | string | Service name |
| `description` | string | Detailed service description |
| `slug` | string | URL-friendly identifier |
| `price` | decimal | Service price |
| `duration` | string | How long service takes |
| `service_at` | string | "person" (on-site) or "virtual" |
| `location` | string | Physical location |
| `long` | string | Longitude coordinate |
| `lat` | string | Latitude coordinate |
| `zip_code` | string | Postal code |
| `image` | string | Main image URL |
| `is_deposite` | boolean | Is deposit required |
| `minimum_deposite` | decimal | Minimum advance payment |
| `tax` | decimal | Tax amount |
| `status` | string | "active" or "inactive" |
| `category_id` | integer | Service category |

---

### Booking Object

```json
{
  "id": 123,
  "service_id": 1,
  "owner_id": 5,
  "customer_id": 10,
  "date": "2024-02-20",
  "time_slot_id": 5,
  "status": "confirmed",
  "subtotal": 50.00,
  "total": 55.00,
  "advance": 27.50,
  "due": 27.50,
  "tax": 5.00,
  "remark": "Special instructions",
  "payment_status": "paid",
  "payment_method": "stripe",
  "booking_type": "standard",
  "created_at": "2024-02-15T10:30:00Z",
  "updated_at": "2024-02-20T15:30:00Z"
}
```

**Field Descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Booking ID |
| `service_id` | integer | Service booked |
| `owner_id` | integer | Service provider |
| `customer_id` | integer | Customer |
| `date` | date | Booking date (YYYY-MM-DD) |
| `time_slot_id` | integer | Selected time slot |
| `status` | string | "pending", "confirmed", "cancelled", "completed" |
| `subtotal` | decimal | Service total before tax |
| `total` | decimal | Final total including tax |
| `advance` | decimal | Paid amount |
| `due` | decimal | Remaining payment |
| `tax` | decimal | Tax amount |
| `remark` | string | Special requests |
| `payment_status` | string | "paid" or "unpaid" |
| `payment_method` | string | "stripe" or "wallet" |
| `booking_type` | string | "standard" or "custom" |

---

### Review Object

```json
{
  "id": 1,
  "user_id": 10,
  "reviewable_type": "Service",
  "reviewable_id": 1,
  "rating": 5,
  "comment": "Excellent service! Very professional and courteous.",
  "likes_count": 12,
  "created_at": "2024-02-20T15:30:00Z"
}
```

**Field Descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Review ID |
| `user_id` | integer | Reviewer's user ID |
| `reviewable_type` | string | What is reviewed: "Service" or "User" |
| `reviewable_id` | integer | ID of reviewed item |
| `rating` | integer | 1-5 star rating |
| `comment` | string | Review text |
| `likes_count` | integer | How many people liked review |
| `created_at` | datetime | When review was written |

---

### Chat Message Object

```json
{
  "id": 100,
  "sender_id": 10,
  "receiver_id": 5,
  "message": "Hi, are you available this weekend?",
  "read_at": null,
  "created_at": "2024-02-20T15:30:00Z"
}
```

**Field Descriptions:**

| Field | Type | Description |
|-------|------|-------------|
| `id` | integer | Message ID |
| `sender_id` | integer | Who sent message |
| `receiver_id` | integer | Who receives message |
| `message` | string | Message content |
| `read_at` | datetime \| null | When message was read |
| `created_at` | datetime | When sent |

---

### Payment/Transaction Object

```json
{
  "id": 1,
  "booking_id": 123,
  "amount": 27.50,
  "status": "paid",
  "payment_method": "stripe",
  "transaction_id": "ch_1234567890",
  "created_at": "2024-02-15T10:30:00Z"
}
```

---

## 14. FRONTEND INTEGRATION GUIDE

### Recommended Tech Stack

**Web Frontend:**
- React 18+ or Vue 3 or Angular 16+
- Axios or Fetch API
- Redux/Vuex/NgRx for state management
- TypeScript for type safety

**Mobile Frontend:**
- React Native or Flutter
- Dio (Flutter) or Axios (React Native)
- Provider/Bloc/Riverpod (state management)

### Complete Login Flow

#### Step 1: Create Login Component

```javascript
import axios from 'axios';
import { useState } from 'react';

const LoginForm = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');

  const handleLogin = async (e) => {
    e.preventDefault();
    setLoading(true);
    setError('');

    try {
      const response = await axios.post(
        'https://api.bachelorgirl.com/api/login',
        { email, password }
      );

      const { access_token, expires_in } = response.data.data.token;
      
      // Save token
      localStorage.setItem('authToken', access_token);
      localStorage.setItem('tokenExpiresAt', 
        Date.now() + (expires_in * 1000)
      );

      // Redirect to dashboard
      window.location.href = '/dashboard';
    } catch (err) {
      setError(err.response?.data?.message || 'Login failed');
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleLogin}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
        required
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
        required
      />
      {error && <div className="error">{error}</div>}
      <button type="submit" disabled={loading}>
        {loading ? 'Logging in...' : 'Login'}
      </button>
    </form>
  );
};

export default LoginForm;
```

#### Step 2: Set Up API Interceptor

```javascript
// api/client.js
import axios from 'axios';

const apiClient = axios.create({
  baseURL: 'https://api.bachelorgirl.com/api',
  timeout: 30000,
});

// Request interceptor - add token to every request
apiClient.interceptors.request.use((config) => {
  const token = localStorage.getItem('authToken');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Response interceptor - handle token refresh
apiClient.interceptors.response.use(
  (response) => response,
  async (error) => {
    const originalRequest = error.config;

    if (error.response?.status === 401 && !originalRequest._retry) {
      originalRequest._retry = true;

      try {
        // Try to refresh token
        const refreshResponse = await axios.post(
          'https://api.bachelorgirl.com/api/refresh',
          {},
          {
            headers: {
              Authorization: `Bearer ${localStorage.getItem('authToken')}`
            }
          }
        );

        const newToken = refreshResponse.data.data.token.access_token;
        localStorage.setItem('authToken', newToken);

        // Retry original request
        originalRequest.headers.Authorization = `Bearer ${newToken}`;
        return apiClient(originalRequest);
      } catch (refreshError) {
        // Refresh failed, logout user
        localStorage.removeItem('authToken');
        window.location.href = '/login';
        return Promise.reject(refreshError);
      }
    }

    return Promise.reject(error);
  }
);

export default apiClient;
```

#### Step 3: Use API in Components

```javascript
import apiClient from './api/client';

function ServicesList() {
  const [services, setServices] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchServices = async () => {
      try {
        const response = await apiClient.get('/service/getAllServices');
        setServices(response.data.data);
      } catch (error) {
        console.error('Error fetching services:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchServices();
  }, []);

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      {services.map(service => (
        <ServiceCard key={service.id} service={service} />
      ))}
    </div>
  );
}
```

### Token Storage Best Practices

**DO:**
✅ Store in secure storage (for mobile)
✅ Implement token refresh automatically
✅ Clear token on logout
✅ Set token expiry reminder
✅ Use HTTPS only in production

**DON'T:**
❌ Store in cookies without HttpOnly flag
❌ Display token in console logs
❌ Hardcode tokens in code
❌ Store sensitive data in localStorage (web)
❌ Trust token expiry on client alone

### Request Retry Strategy

```javascript
const withRetry = async (
  fn,
  maxRetries = 3,
  delay = 1000
) => {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
      
      // Exponential backoff
      const waitTime = delay * Math.pow(2, i);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }
  }
};

// Usage
const getServices = () => withRetry(
  () => apiClient.get('/service/getAllServices')
);
```

---

## 15. FLUTTER INTEGRATION GUIDE

### Setup Dio Package

```yaml
# pubspec.yaml
dependencies:
  dio: ^5.0.0
  get: ^4.6.5
  flutter_secure_storage: ^9.0.0
```

### Configure Dio Client

```dart
// lib/services/api_service.dart
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class ApiService {
  static final ApiService _instance = ApiService._internal();
  
  late Dio dio;
  final storage = const FlutterSecureStorage();

  const FlutterSecureStorage storage

  ApiService._internal() {
    dio = Dio(BaseOptions(
      baseUrl: 'https://api.bachelorgirl.com/api',
      contentType: Headers.jsonContentType,
      responseType: ResponseType.json,
    ));

    // Request interceptor
    dio.interceptors.add(
      InterceptorsWrapper(
        onRequest: (options, handler) async {
          final token = await storage.read(key: 'access_token');
          if (token != null) {
            options.headers['Authorization'] = 'Bearer $token';
          }
          return handler.next(options);
        },
        onError: (error, handler) async {
          if (error.response?.statusCode == 401) {
            if (error.response?.data['message'] == 'Token is Expired') {
              // Try to refresh token
              try {
                final refreshed = await refreshToken();
                if (refreshed) {
                  // Retry request
                  return handler.resolve(await dio.request(
                    error.requestOptions.path,
                    options: error.requestOptions,
                  ));
                }
              } catch (e) {
                // Logout user
              }
            }
          }
          return handler.next(error);
        },
      ),
    );
  }

  Future<bool> refreshToken() async {
    try {
      final currentToken = await storage.read(key: 'access_token');
      
      final response = await Dio().post(
        '${dio.options.baseUrl}/refresh',
        options: Options(headers: {
          'Authorization': 'Bearer $currentToken',
        }),
      );

      final newToken = response.data['data']['token']['access_token'];
      await storage.write(key: 'access_token', value: newToken);
      
      return true;
    } catch (e) {
      await logout();
      return false;
    }
  }

  Future<void> logout() async {
    await storage.delete(key: 'access_token');
    // Navigate to login
  }

  factory ApiService() {
    return _instance;
  }
}
```

### Login Implementation

```dart
// lib/screens/login_screen.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class LoginController extends GetxController {
  final storage = const FlutterSecureStorage();
  final apiService = ApiService();
  
  var isLoading = false.obs;
  var errorMessage = ''.obs;

  Future<void> login(String email, String password) async {
    isLoading.value = true;
    errorMessage.value = '';

    try {
      final response = await apiService.dio.post('/login', data: {
        'email': email,
        'password': password,
      });

      final token = response.data['data']['token']['access_token'];
      final expiresIn = response.data['data']['token']['expires_in'];

      // Save token
      await storage.write(key: 'access_token', value: token);
      await storage.write(
        key: 'token_expires_at',
        value: DateTime.now()
            .add(Duration(seconds: expiresIn))
            .toIso8601String(),
      );

      // Navigate to home
      Get.offAllNamed('/dashboard');
    } on DioException catch (e) {
      errorMessage.value = e.response?.data['message'] ?? 'Login failed';
    } finally {
      isLoading.value = false;
    }
  }
}

class LoginScreen extends StatelessWidget {
  final controller = Get.put(LoginController());
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: emailController,
              decoration: InputDecoration(labelText: 'Email'),
            ),
            TextField(
              controller: passwordController,
              decoration: InputDecoration(labelText: 'Password'),
              obscureText: true,
            ),
            SizedBox(height: 20),
            Obx(() => ElevatedButton(
              onPressed: controller.isLoading.value
                  ? null
                  : () => controller.login(
                    emailController.text,
                    passwordController.text,
                  ),
              child: controller.isLoading.value
                  ? LinearProgressIndicator()
                  : Text('Login'),
            )),
            Obx(() => controller.errorMessage.value.isEmpty
                ? SizedBox()
                : Text(
                  controller.errorMessage.value,
                  style: TextStyle(color: Colors.red),
                )),
          ],
        ),
      ),
    );
  }
}
```

### Pagination Implementation

```dart
class ServiceListController extends GetxController {
  final apiService = ApiService();
  
  var services = <Service>[].obs;
  var currentPage = 1.obs;
  var lastPage = 1.obs;
  var isLoading = false.obs;

  @override
  void onInit() {
    super.onInit();
    fetchServices();
  }

  Future<void> fetchServices({int page = 1}) async {
    isLoading.value = true;

    try {
      final response = await apiService.dio.get(
        '/service/getAllServices',
        queryParameters: {
          'page': page,
          'limit': 15,
        },
      );

      final data = response.data['data'];
      
      if (page == 1) {
        services.assignAll(
          (data as List).map((s) => Service.fromJson(s)).toList(),
        );
      } else {
        services.addAll(
          (data as List).map((s) => Service.fromJson(s)).toList(),
        );
      }

      currentPage.value = page;
      lastPage.value = response.data.containsKey('pagination')
          ? response.data['pagination']['last_page']
          : 1;
    } catch (e) {
      print('Error: $e');
    } finally {
      isLoading.value = false;
    }
  }

  Future<void> loadMoreServices() async {
    if (currentPage.value < lastPage.value) {
      await fetchServices(page: currentPage.value + 1);
    }
  }
}

class ServiceListScreen extends StatelessWidget {
  final controller = Get.put(ServiceListController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Services')),
      body: Obx(() => ListView.builder(
        itemCount: controller.services.length + 1,
        itemBuilder: (context, index) {
          if (index == controller.services.length) {
            if (controller.currentPage.value < controller.lastPage.value) {
              return Padding(
                padding: EdgeInsets.all(16),
                child: ElevatedButton(
                  onPressed: controller.loadMoreServices,
                  child: Text('Load More'),
                ),
              );
            }
            return SizedBox();
          }

          final service = controller.services[index];
          return ServiceTile(service: service);
        },
      )),
    );
  }
}
```

### File Upload in Flutter

```dart
// lib/services/file_upload_service.dart
class FileUploadService {
  final apiService = ApiService();

  Future<void> uploadService({
    required String title,
    required double price,
    required String serviceAt,
    required String location,
    required String long,
    required String lat,
    required XFile image,
  }) async {
    FormData formData = FormData.fromMap({
      'title': title,
      'price': price,
      'service_at': serviceAt,
      'location': location,
      'long': long,
      'lat': lat,
      'image': await MultipartFile.fromFile(
        image.path,
        filename: 'service_image.jpg',
      ),
    });

    try {
      final response = await apiService.dio.post(
        '/service/create',
        data: formData,
      );

      print('Upload successful: ${response.data}');
    } on DioException catch (e) {
      if (e.response?.statusCode == 422) {
        // Validation error
        final errors = e.response?.data['data'];
        print('Validation errors: $errors');
      } else {
        print('Upload failed: ${e.message}');
      }
    }
  }
}
```

### Error Handling Best Practices

```dart
class ApiInterceptor extends Interceptor {
  final storage = const FlutterSecureStorage();

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) {
    // Handle different error scenarios
    switch (err.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.receiveTimeout:
        // Network timeout
        showErrorDialog('Connection timeout. Please try again.');
        break;

      case DioExceptionType.badResponse:
        final statusCode = err.response?.statusCode;
        
        if (statusCode == 401) {
          // Unauthorized - logout
          _logout();
        } else if (statusCode == 422) {
          // Validation error
          final errors = err.response?.data['data'];
          _showValidationErrors(errors);
        } else if (statusCode == 500) {
          // Server error
          showErrorDialog('Server error. Please try again later.');
        }
        break;

      case DioExceptionType.cancel:
        // Request cancelled
        break;

      default:
        // Other error
        showErrorDialog('An error occurred. Please try again.');
    }

    return handler.next(err);
  }

  void _logout() async {
    await storage.delete(key: 'access_token');
    Get.offAllNamed('/login');
  }

  void _showValidationErrors(Map<String, dynamic> errors) {
    String message = 'Please check the following:';
    errors.forEach((field, messages) {
      message += '\n• ${messages.join(', ')}';
    });
    Get.snackbar('Validation Error', message);
  }
}
```

---

## 16. SECURITY BEST PRACTICES

### 1. Token Security

**DO:**
✅ **Use HTTPS Only**
   - All production API calls must use HTTPS
   - No plain HTTP in production

✅ **Store Token Securely**
   - Web: Use secure, HttpOnly cookies (not localStorage)
   - Mobile: Use secure device storage (Keychain/Keystore)

✅ **Set Token Expiry**
   - Don't disable token expiration
   - Default: 7 days is good
   - Refresh before expiration

✅ **Clear Token on Logout**
   ```javascript
   localStorage.removeItem('authToken');
   localStorage.removeItem('tokenExpiresAt');
   ```

**DON'T:**
❌ **Never store token in localStorage** (for highly sensitive apps)
```javascript
// ❌ UNSAFE
localStorage.setItem('token', jwtToken);
```

❌ **Don't send token in URL**
```
// ❌ UNSAFE
GET /api/profile?token=abc123
```

❌ **Don't log tokens**
```javascript
// ❌ UNSAFE
console.log('Token:', token);
```

---

### 2. HTTPS Requirements

All API communication must use HTTPS in production:

```javascript
// ❌ Development (HTTP is okay for local testing)
baseURL: 'http://localhost:8000/api'

// ✅ Production (HTTPS required)
baseURL: 'https://api.bachelorgirl.com/api'
```

**SSL Certificate:**
- Obtain from Let's Encrypt, DigiCert, or similar
- Auto-renew certificates before expiration
- Support TLS 1.2 minimum

---

### 3. Request Validation

**Server validates all inputs:**
- Email format
- Password strength
- Data types
- Field lengths
- Business logic rules

**Client should also validate:**
```javascript
const isValidEmail = (email) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

const isValidPassword = (password) => {
  return password.length >= 8 &&
    /[A-Z]/.test(password) &&
    /\d/.test(password) &&
    /[!@#$%^&*]/.test(password);
};
```

---

### 4. CSRF Considerations

The API uses JWT tokens instead of session cookies, which are naturally protected from CSRF attacks.

**If using cookies:**
- Include CSRF token in HTTP headers
- Implement Same-Site cookie attributes
- Validate origin headers

---

### 5. Sensitive Data Handling

**Never transmit or display:**
- Full credit card numbers
- Passwords (server hashes them)
- OTP codes (only show last 4 digits)
- API secrets or keys

**Example of safe password reset:**
```json
{
  "message": "Password reset email sent to j***@example.com",
  "data": []
}
```

---

### 6. Rate Limiting & DDoS Protection

**Best practices:**
- Implement rate limiting on server
- Use CDN for static content
- Monitor suspicious patterns
- Block automated attacks

---

### 7. OpenAPI/Swagger Security

If exposing API docs:
- Use Basic Auth for docs access
- Don't expose sensitive examples
- Remove production URLs from docs
- Add security disclaimers

---

### 8. Dependency Security

**Keep dependencies updated:**
```bash
npm audit
npm update
pub upgrade
flutter pub upgrade
```

**Vulnerable packages to watch:**
- Authentication libraries
- Crypto libraries
- HTTP clients

---

### 9. Environment Configuration

**Development:**
```javascript
process.env.REACT_APP_API_URL = 'http://localhost:8000/api'
process.env.REACT_APP_DEBUG = true
```

**Production:**
```javascript
process.env.REACT_APP_API_URL = 'https://api.bachelorgirl.com/api'
process.env.REACT_APP_DEBUG = false
```

**Never commit secrets:**
```bash
# .gitignore
.env
.env.local
.env.*.local
```

---

### 10. Security Headers

Ensure server sends security headers:
```http
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'
```

---

## QUICK REFERENCE

### Most Used Endpoints

| Endpoint | Method | Purpose |
|----------|--------|---------|
| `/login` | POST | User login |
| `/customer/register` | POST | Customer signup |
| `/owner/register` | POST | Owner signup |
| `/profile` | GET | Get profile |
| `/profile/update` | POST | Update profile |
| `/service/getAllServices` | GET | List services |
| `/service/getOwnerServices` | GET | Owner's services |
| `/service/create` | POST | Create service |
| `/book/service` | POST | Create booking |
| `/get/customer/booking` | GET | Customer bookings |
| `/review/store` | POST | Write review |
| `/chat/send` | POST | Send message |
| `/notifications` | GET | Get notifications |
| `/add-favourite` | POST | Add favorite |
| `/refresh` | POST | Refresh token |

### Common Status Codes

| Code | Meaning |
|------|---------|
| 200 | OK - Request succeeded |
| 201 | Created - Resource created |
| 400 | Bad Request - Invalid input |
| 401 | Unauthorized - Missing/invalid token |
| 403 | Forbidden - No permission |
| 404 | Not Found - Resource doesn't exist |
| 422 | Validation Error |
| 500 | Server Error |

---

## SUPPORT & RESOURCES

For API support:
- Email: api-support@bachelorgirl.com
- Documentation: https://docs.bachelorgirl.com
- GitHub Issues: https://github.com/bachelorgirl/api-issues
- Community Forum: https://community.bachelorgirl.com

---

**Last Updated:** February 2024
**Version:** 1.0.0
**Status:** Production Ready

