API v1.0

واجهة المطورين

نظام برمجي متكامل وسهل الاستخدام. اربط متجرك مع منصتنا خلال دقائق وابدأ عمليات التوصيل بكفاءة عالية.

Production Base URL
https://wassel.delivery/api/v1
Authentication
Bearer Token
🏠

Home

Home page and health check endpoints

GET /api/health
Public

Check API health status and server availability

Response Example

{
  "status": "healthy"
}
📱

Introduction Pages

Onboarding/introduction pages for mobile app first-time users

GET /api/v1/introduction-pages
Public

Get all active introduction pages for app onboarding. Returns pages ordered by page_number (1, 2, 3). Only active pages are returned. Use this endpoint to display introduction/onboarding screens in the mobile app.

Response Example

[
  {
    "created_at": "2024-12-25T00:00:00Z",
    "id": 1,
    "image": "https://wassel.delivery/static/uploads/introduction_pages/intro_page_1_abc123.jpg",
    "is_active": true,
    "page_number": 1,
    "text1": "Welcome to our app",
    "text2": "Discover amazing products",
    "text3": "Start shopping now",
    "updated_at": "2024-12-25T00:00:00Z"
  },
  {
    "created_at": "2024-12-25T00:00:00Z",
    "id": 2,
    "image": "https://wassel.delivery/static/uploads/introduction_pages/intro_page_2_def456.jpg",
    "is_active": true,
    "page_number": 2,
    "text1": "Fast delivery",
    "text2": "Get your orders quickly",
    "text3": "Track in real-time",
    "updated_at": "2024-12-25T00:00:00Z"
  },
  {
    "created_at": "2024-12-25T00:00:00Z",
    "id": 3,
    "image": "https://wassel.delivery/static/uploads/introduction_pages/intro_page_3_ghi789.jpg",
    "is_active": true,
    "page_number": 3,
    "text1": "Secure payments",
    "text2": "Your data is safe",
    "text3": "Shop with confidence",
    "updated_at": "2024-12-25T00:00:00Z"
  }
]
🔐

Authentication

User registration, login, and token management

POST /api/v1/auth/register
Public

Register a new user account

Body Parameters

  • email
  • username
  • password
  • full_name (optional)
  • phone (optional)

Response Example

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 86400,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": {
    "avatar": null,
    "created_at": "2024-12-08T10:30:00Z",
    "email": "[email protected]",
    "full_name": "John Doe",
    "id": 1,
    "is_active": true,
    "is_verified": false,
    "last_login": null,
    "phone": "+1234567890",
    "selected_currency_id": null,
    "store_id": null,
    "updated_at": "2024-12-08T10:30:00Z",
    "user_type": "normal_user",
    "username": "johndoe"
  }
}
POST /api/v1/auth/login
Public

Login with email/username and password. Users can login with either their email address or username.

Body Parameters

  • email (or username)
  • password

Response Example

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 86400,
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "bearer",
  "user": {
    "avatar": null,
    "created_at": "2024-12-08T10:30:00Z",
    "email": "[email protected]",
    "full_name": "John Doe",
    "id": 1,
    "is_active": true,
    "is_verified": false,
    "last_login": "2024-12-08T10:30:00Z",
    "phone": "+1234567890",
    "store_id": null,
    "updated_at": "2024-12-08T10:30:00Z",
    "user_type": "normal_user",
    "username": "johndoe"
  }
}
POST /api/v1/auth/refresh
Public

Refresh access token using refresh token

Body Parameters

  • refresh_token

Response Example

{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "expires_in": 86400,
  "token_type": "bearer"
}
POST /api/v1/auth/logout
Public

Logout user (client-side token removal)

Response Example

{
  "message": "Logged out successfully"
}
POST /api/v1/auth/forgot-password
Public

Request password reset. User submits their email address. The system generates a secure password reset token and sends it via email to the user's registered email address. The token expires in 1 hour. For security reasons, the API always returns a success message regardless of whether the email exists (prevents email enumeration attacks). The reset link is sent to the user's email only - no token is returned in the API response.

Body Parameters

  • email

Response Example

{
  "message": "If the email exists, a password reset link has been sent to your email.",
  "success": true
}

SECURITY: The reset token is NEVER returned in the API response. It is sent ONLY via email to the registered email address. This prevents unauthorized access to password reset tokens. Always check the user's email inbox for the reset link.

POST /api/v1/auth/verify-reset-token
Public

Verify password reset token. Checks if the token is valid and not expired. Returns success if token is valid. Use this before showing the password reset form to ensure the token is still valid.

Body Parameters

  • token

Response Example

{
  "message": "Reset token is valid",
  "success": true
}
POST /api/v1/auth/reset-password
Public

Reset password using reset token. Resets the user's password and invalidates the reset token. Password must be at least 8 characters. After successful reset, user can login with the new password.

Body Parameters

  • token
  • new_password (minimum 8 characters)

Response Example

{
  "message": "Password has been reset successfully",
  "success": true
}
👤

Profile

User profile management and information

GET /api/v1/auth/me
Private

Get current authenticated user profile. Returns user information including user type (normal_user or shop_owner), store_id if the user is a shop owner, and opening_hours for shop owners.

Auth Method Bearer Token (JWT)

Response Example

{
  "avatar": "https://example.com/avatar.jpg",
  "created_at": "2024-12-08T10:30:00Z",
  "email": "[email protected]",
  "full_name": "John Doe",
  "id": 1,
  "is_active": true,
  "is_verified": true,
  "last_login": "2024-12-08T10:30:00Z",
  "opening_hours": null,
  "phone": "+1234567890",
  "selected_currency_id": null,
  "store_id": null,
  "updated_at": "2024-12-08T10:30:00Z",
  "user_type": "normal_user",
  "username": "johndoe"
}

opening_hours is only returned for shop owners (user_type='shop_owner'). For regular users, opening_hours will be null. The opening_hours object contains all 7 days of the week (monday through sunday), each with is_closed (bool), open_time (HH:MM format, 24-hour, UTC+3), and close_time (HH:MM format, 24-hour, UTC+3). All times are in UTC+3 (Bahrain Time). Use is_closed=true to mark a day as closed. See opening_hours_example above for the structure.

PUT /api/v1/auth/me
Private

Update current user profile with file upload support. Use multipart/form-data for avatar upload. You can update full_name, phone, upload avatar image file, and opening_hours (for shop owners only).

Auth Method Bearer Token (JWT)

Response Example

{
  "avatar": "https://wassel.delivery/static/uploads/users/user_1_a3b5c7d9.png",
  "created_at": "2024-12-08T10:30:00Z",
  "email": "[email protected]",
  "full_name": "Jane Doe Updated",
  "id": 1,
  "is_active": true,
  "is_verified": true,
  "last_login": "2024-12-08T10:30:00Z",
  "opening_hours": {
    "friday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "monday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "saturday": {
      "close_time": null,
      "is_closed": true,
      "open_time": null
    },
    "sunday": {
      "close_time": null,
      "is_closed": true,
      "open_time": null
    },
    "thursday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "tuesday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "wednesday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    }
  },
  "phone": "+1987654321",
  "store_id": "store_a1b2c3d4e5f6g7h8",
  "updated_at": "2024-12-08T11:45:00Z",
  "user_type": "shop_owner",
  "username": "johndoe"
}

opening_hours is only applicable for shop owners (user_type='shop_owner'). For regular users, opening_hours will be null. Use is_closed=true to mark a day as closed. Times are in 24-hour format (HH:MM) and are in UTC+3 (Bahrain Time).

PUT /api/v1/auth/me/json
Private

Update current user profile (JSON format). Use this for text fields only. For avatar file upload, use PUT /me with multipart/form-data. You can update full_name, phone, avatar (as URL string), and opening_hours (for shop owners only).

Auth Method Bearer Token (JWT)

Body Parameters

  • full_name (optional, string)
  • phone (optional, string)
  • avatar (optional, URL string)
  • opening_hours (optional, object) - Opening hours for shop owners. Format: {"monday": {"is_closed": false, "open_time": "09:00", "close_time": "17:00"}, "tuesday": {"is_closed": true}, ...}. Days: monday, tuesday, wednesday, thursday, friday, saturday, sunday. Each day has is_closed (bool), open_time (HH:MM format, 24-hour), close_time (HH:MM format, 24-hour).

Response Example

{
  "avatar": "https://example.com/avatar.jpg",
  "created_at": "2024-12-08T10:30:00Z",
  "email": "[email protected]",
  "full_name": "Jane Doe Updated",
  "id": 1,
  "is_active": true,
  "is_verified": true,
  "last_login": "2024-12-08T10:30:00Z",
  "opening_hours": {
    "friday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "monday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "saturday": {
      "close_time": null,
      "is_closed": true,
      "open_time": null
    },
    "sunday": {
      "close_time": null,
      "is_closed": true,
      "open_time": null
    },
    "thursday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "tuesday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    },
    "wednesday": {
      "close_time": "17:00",
      "is_closed": false,
      "open_time": "09:00"
    }
  },
  "phone": "+1987654321",
  "store_id": "store_a1b2c3d4e5f6g7h8",
  "updated_at": "2024-12-08T11:45:00Z",
  "user_type": "shop_owner",
  "username": "johndoe"
}

opening_hours is only applicable for shop owners (user_type='shop_owner'). For regular users, opening_hours will be null. Use is_closed=true to mark a day as closed. Times are in 24-hour format (HH:MM) and are in UTC+3 (Bahrain Time).

POST /api/v1/auth/currency
Private

Update user's selected currency preference. The selected currency will be stored in the user's profile and remembered for future sessions. Currency must be active.

Auth Method Bearer Token (JWT)

Body Parameters

  • currency_id

Response Example

{
  "avatar": null,
  "created_at": "2024-12-08T10:30:00Z",
  "email": "[email protected]",
  "full_name": "John Doe",
  "id": 1,
  "is_active": true,
  "is_verified": true,
  "last_login": "2024-12-08T10:30:00Z",
  "phone": "+1234567890",
  "selected_currency_id": 2,
  "store_id": null,
  "updated_at": "2024-12-09T12:00:00Z",
  "user_type": "normal_user",
  "username": "johndoe"
}

Returns updated user profile with selected_currency_id. Use this ID to convert prices in the app. Check /api/v1/settings endpoint to get currency details including exchange rates.

🎨

Branding

Branding and site configuration endpoints including dynamic app color customization (read-only)

GET /api/v1/branding
Public

Get current branding information including favicon, logos, copyright text, social media links, and dynamic app color customization. The response includes a 'colors' object with all customizable app colors for both light and dark modes. This endpoint enables dynamic theming - the Flutter app can fetch these colors and apply them automatically. All color fields are optional (nullable) - if a color is null or not provided, the app will use default fallback colors. This is a read-only endpoint. To update branding, use the admin panel at /admin/branding. To customize app colors, use the admin panel at /admin/app-colors.

Response Example

{
  "app_name": "My Application",
  "colors": {
    "animation_base_color_dark": "#FFFFFF",
    "animation_base_color_light": "#808080",
    "animation_highlight_color_dark": "#161616",
    "animation_highlight_color_light": "#FAFAFA",
    "bg_color_dark": "#161616",
    "bg_color_light": "#FAFAFA",
    "border_color_dark": "#2A2A2A",
    "border_color_light": "#DFDFDF",
    "button_color_dark": "#A3D97A",
    "button_color_light": "#76974C",
    "card_color_dark": "#1E1E1E",
    "card_color_light": "#FFFFFF",
    "chat_other_side_color": "#2196F3",
    "divider_color_dark": "#212121",
    "divider_color_light": "#F1F1F1",
    "error_color": "#FF6565",
    "info_color": "#2196F3",
    "light_button_color_dark": "#1D231C",
    "light_button_color_light": "#EEF6E4",
    "primary_text_dark": "#F2F2F2",
    "primary_text_light": "#000000",
    "regular_black_dark": "#F2F2F2",
    "regular_black_light": "#000000",
    "regular_white_dark": "#1E1E1E",
    "regular_white_light": "#FFFFFF",
    "secondary_text_dark": "#B8BFC7",
    "secondary_text_light": "#808080",
    "sub_title_color_dark": "#A7AFB8",
    "sub_title_color_light": "#808080",
    "success_color": "#4CAF50",
    "warning_color": "#FF9800"
  },
  "copyright_text": "\u00a9 2024 SaaS E-commerce Platform. All rights reserved.",
  "created_at": "2024-12-08T10:30:00Z",
  "favicon": "https://wassel.delivery/static/uploads/branding/favicon.ico",
  "id": 1,
  "logo_dark": "https://wassel.delivery/static/uploads/branding/logo_dark.png",
  "logo_light": "https://wassel.delivery/static/uploads/branding/logo_light.png",
  "social_media": [
    {
      "icon": "https://wassel.delivery/static/uploads/branding/social_facebook.png",
      "name": "Facebook",
      "url": "https://facebook.com/yourcompany"
    },
    {
      "icon": "https://wassel.delivery/static/uploads/branding/social_twitter.png",
      "name": "Twitter",
      "url": "https://twitter.com/yourcompany"
    },
    {
      "icon": "https://wassel.delivery/static/uploads/branding/social_instagram.png",
      "name": "Instagram",
      "url": "https://instagram.com/yourcompany"
    }
  ],
  "updated_at": "2024-12-08T11:45:00Z"
}

DYNAMIC COLORS API: The 'colors' object enables dynamic app theming. Colors are organized by category: 📌 PRIMARY COLORS: - button_color_light/dark: Main button colors (default: #76974C/#A3D97A) - light_button_color_light/dark: Light button backgrounds (default: #EEF6E4/#1D231C) 🎨 BACKGROUND COLORS: - bg_color_light/dark: Main background (default: #FAFAFA/#161616) - card_color_light/dark: Card/surface colors (default: #FFFFFF/#1E1E1E) 📝 TEXT COLORS: - primary_text_light/dark: Primary text (default: #000000/#F2F2F2) - secondary_text_light/dark: Secondary text (default: #808080/#B8BFC7) - sub_title_color_light/dark: Subtitle text (default: #808080/#A7AFB8) 🔲 BORDER & DIVIDER COLORS: - border_color_light/dark: Border colors (default: #DFDFDF/#2A2A2A) - divider_color_light/dark: Divider colors (default: #F1F1F1/#212121) ⚫ STANDARD COLORS: - regular_black_light/dark: Black variant (default: #000000/#F2F2F2) - regular_white_light/dark: White variant (default: #FFFFFF/#1E1E1E) ✨ ANIMATION COLORS (for shimmer effects): - animation_base_color_light/dark: Base shimmer color (default: #808080/#FFFFFF) - animation_highlight_color_light/dark: Highlight shimmer (default: #FAFAFA/#161616) 🚦 STATUS COLORS (same for both modes): - error_color: Error/red (default: #FF6565) - success_color: Success/green (default: #4CAF50) - warning_color: Warning/orange (default: #FF9800) - info_color: Info/blue (default: #2196F3) - chat_other_side_color: Chat message color (default: #2196F3) 📋 COLOR FORMAT: - Colors are in hex format: #RRGGBB (6 digits) or #AARRGGBB (8 digits with alpha) - The # prefix is optional (both '#76974C' and '76974C' are accepted) - All color fields are optional (nullable) - partial customization is supported - If a color is null or empty, the app uses default fallback colors 💡 USAGE: - Fetch colors from this endpoint on app startup - Cache colors locally for offline use - Colors automatically adapt to light/dark mode - Changes in admin panel (/admin/app-colors) are reflected after app refresh

⚙️

Settings

General platform settings and feature toggles. Use this endpoint to check if features like Events or Blogs are enabled before making API calls.

GET /api/v1/settings
Public

Get general platform settings including feature toggles and currencies. Returns events_enabled (shows if Events feature is active), blogs_enabled (shows if Blogs feature is active), top_sellers_enabled (shows if Top Sellers feature is active), shops_enabled (shows if Shops feature is active), chat_enabled (shows if Chat feature is active), support_enabled (shows if Support System feature is active), master_categories_enabled (shows if Master Categories feature is active), platform_fees_enabled, platform_fees_percentage, and currencies array with exchange rates. Always check these feature toggles before calling respective endpoints to know if features are available. Currencies are returned with their exchange rates against BHD (default currency).

Response Example

{
  "blogs_enabled": true,
  "chat_enabled": true,
  "currencies": [
    {
      "created_at": "2024-12-09T10:30:00Z",
      "flag_image": "https://wassel.delivery/static/uploads/currencies/flag_1_abc123.jpg",
      "id": 1,
      "is_active": true,
      "is_default": true,
      "rate": 1.0,
      "symbol": "BHD",
      "updated_at": "2024-12-09T10:30:00Z"
    },
    {
      "created_at": "2024-12-09T10:35:00Z",
      "flag_image": "https://wassel.delivery/static/uploads/currencies/flag_2_def456.jpg",
      "id": 2,
      "is_active": true,
      "is_default": false,
      "rate": 10.0,
      "symbol": "SAR",
      "updated_at": "2024-12-09T10:35:00Z"
    }
  ],
  "events_enabled": true,
  "maintenance_mode": false,
  "master_categories_enabled": true,
  "platform_fees_enabled": false,
  "platform_fees_percentage": 0.0,
  "shops_enabled": true,
  "support_enabled": true,
  "top_sellers_enabled": true
}

If events_enabled is false, Events API endpoints return empty arrays or 404 errors. If blogs_enabled is false, Blogs API endpoints return empty arrays or 404 errors. If top_sellers_enabled is false, Top Sellers feature should be hidden in the app. If shops_enabled is false, Shops feature should be hidden in the app. If chat_enabled is false, Chat API endpoints will be unavailable. If support_enabled is false, Support System API endpoints will be unavailable. If master_categories_enabled is false, Master Categories feature should be hidden in the app and master categories API endpoints may return empty arrays. If maintenance_mode is true, the platform is in maintenance mode and users should see a maintenance message. Always check these settings first before displaying features in your app. Currencies array contains all active currencies with their exchange rates against BHD. The rate represents how many units of the currency equal 1 BHD (e.g., rate: 10 means 10 SAR = 1 BHD). The default currency (is_default: true) is BHD.

🖼️

Banners

Home page banners management endpoints

GET /api/v1/banners
Public

Get all home page banners. Returns banners ordered by display order (ascending). By default, only active banners within their scheduled time range are returned. Use this endpoint to display banners on the home page.

Query Parameters

  • is_active (optional, boolean) - Filter by active status. If not provided, returns only active banners.

Response Example

[
  {
    "createdAt": "2024-12-08T10:30:00Z",
    "endAt": null,
    "id": 1,
    "image": "https://wassel.delivery/static/uploads/banners/banner_1_a1b2c3d4.png",
    "isActive": true,
    "link": "https://wassel.delivery/sale",
    "order": 0,
    "startAt": null,
    "targetId": "987",
    "targetType": "product",
    "title": "Summer Sale 2024",
    "updatedAt": "2024-12-08T10:30:00Z",
    "url": null
  },
  {
    "createdAt": "2024-12-08T11:00:00Z",
    "endAt": null,
    "id": 2,
    "image": "https://wassel.delivery/static/uploads/banners/banner_2_e5f6g7h8.png",
    "isActive": true,
    "link": null,
    "order": 1,
    "startAt": null,
    "targetId": "store_a1b2c3d4e5f6g7h8",
    "targetType": "store",
    "title": "Visit Our Store",
    "updatedAt": "2024-12-08T11:00:00Z",
    "url": null
  },
  {
    "createdAt": "2024-12-08T12:00:00Z",
    "endAt": "2024-12-31T23:59:59Z",
    "id": 3,
    "image": "https://wassel.delivery/static/uploads/banners/banner_3_i9j0k1l2.png",
    "isActive": true,
    "link": null,
    "order": 2,
    "startAt": "2024-12-10T00:00:00Z",
    "targetId": "https://example.com/promotion",
    "targetType": "url",
    "title": "Special Promotion",
    "updatedAt": "2024-12-08T12:00:00Z",
    "url": "https://example.com/promotion"
  },
  {
    "createdAt": "2024-12-08T13:00:00Z",
    "endAt": null,
    "id": 4,
    "image": "https://wassel.delivery/static/uploads/banners/banner_4_m3n4o5p6.png",
    "isActive": true,
    "link": null,
    "order": 3,
    "startAt": null,
    "targetId": "42",
    "targetType": "event",
    "title": "Upcoming Event",
    "updatedAt": "2024-12-08T13:00:00Z",
    "url": null
  }
]
🔔

Popups

Popup images with deep linking support for products, stores, events, and external URLs

GET /api/v1/popups
Public

Get all active popups. Returns popups ordered by display order (ascending). Only active popups within their scheduled time range are returned by default. Use this endpoint to display popups in the mobile app.

Query Parameters

  • is_active (optional, boolean) - Filter by active status. If not provided, returns only active popups.

Response Example

[
  {
    "createdAt": "2024-12-09T10:30:00Z",
    "endAt": null,
    "id": 12,
    "image": "https://wassel.delivery/static/uploads/popups/popup_abc123.jpg",
    "isActive": true,
    "order": 0,
    "startAt": null,
    "targetId": "987",
    "targetType": "product",
    "title": "Limited offer",
    "updatedAt": "2024-12-09T10:30:00Z",
    "url": null
  },
  {
    "createdAt": "2024-12-09T11:00:00Z",
    "endAt": "2024-12-31T23:59:59Z",
    "id": 13,
    "image": "https://wassel.delivery/static/uploads/popups/popup_def456.jpg",
    "isActive": true,
    "order": 1,
    "startAt": "2024-12-10T00:00:00Z",
    "targetId": "https://example.com/promotion",
    "targetType": "url",
    "title": "Special Promotion",
    "updatedAt": "2024-12-09T11:00:00Z",
    "url": "https://example.com/promotion"
  },
  {
    "createdAt": "2024-12-09T12:00:00Z",
    "endAt": null,
    "id": 14,
    "image": "https://wassel.delivery/static/uploads/popups/popup_ghi789.jpg",
    "isActive": true,
    "order": 2,
    "startAt": null,
    "targetId": "store_a1b2c3d4e5f6g7h8",
    "targetType": "store",
    "title": "Visit Our Store",
    "updatedAt": "2024-12-09T12:00:00Z",
    "url": null
  }
]
📰

Blogs

Blog posts and articles management endpoints. Note: Description fields accept and return HTML formatted content from a rich text editor. When displaying in Flutter, use packages like 'flutter_html' or 'html_widget' to render the HTML content properly. Blogs feature can be enabled/disabled by admin. When disabled, API endpoints return empty results or 404 errors. Check /api/v1/settings endpoint to see if blogs feature is enabled.

GET /api/v1/blogs
Public

List all active blogs. Filter by master_category_id to get blogs for a specific master category. Returns blogs ordered by creation date (newest first). Description fields contain HTML formatted content from the rich text editor. If blogs feature is disabled by admin, returns an empty list [].

Query Parameters

  • master_category_id (optional, integer - filter by master category)
  • skip (optional, default: 0)
  • limit (optional, default: 100, max: 100)
  • is_active (optional, default: true, boolean)

Response Example

[
  {
    "created_at": "2024-12-08T10:30:00Z",
    "description_ar": "\u003cp\u003e\u062a\u0639\u0644\u0645 \u003cstrong\u003e\u0623\u0633\u0627\u0633\u064a\u0627\u062a \u0627\u0644\u0643\u0631\u0648\u0634\u064a\u0647\u003c/strong\u003e \u0648\u0627\u0628\u062f\u0623 \u0631\u062d\u0644\u062a\u0643...\u003c/p\u003e\u003cul\u003e\u003cli\u003e\u0627\u0644\u062e\u0637\u0648\u0629 1: \u0627\u062e\u062a\u0631 \u062e\u064a\u0648\u0637\u0643\u003c/li\u003e\u003cli\u003e\u0627\u0644\u062e\u0637\u0648\u0629 2: \u0627\u062e\u062a\u0631 \u0627\u0644\u062e\u0637\u0627\u0641\u0627\u062a\u003c/li\u003e\u003c/ul\u003e",
    "description_en": "\u003cp\u003eLearn the \u003cstrong\u003ebasics of crochet\u003c/strong\u003e and start your journey...\u003c/p\u003e\u003cul\u003e\u003cli\u003eStep 1: Choose your yarn\u003c/li\u003e\u003cli\u003eStep 2: Select hooks\u003c/li\u003e\u003c/ul\u003e",
    "id": 1,
    "image": "https://wassel.delivery/static/uploads/blogs/blog_1_abc123.jpg",
    "is_active": true,
    "title_ar": "\u0645\u0642\u062f\u0645\u0629 \u0641\u064a \u0627\u0644\u0643\u0631\u0648\u0634\u064a\u0647",
    "title_en": "Introduction to Crochet",
    "updated_at": "2024-12-08T10:30:00Z"
  },
  {
    "created_at": "2024-12-07T14:20:00Z",
    "description_ar": "\u003cp\u003e\u0627\u0643\u062a\u0634\u0641 \u003cem\u003e\u0623\u0641\u0636\u0644 \u0623\u0646\u0648\u0627\u0639 \u0627\u0644\u062e\u064a\u0648\u0637\u003c/em\u003e \u0644\u0645\u0628\u062a\u062f\u0626\u064a \u0627\u0644\u0643\u0631\u0648\u0634\u064a\u0647...\u003c/p\u003e\u003cblockquote\u003e\u0627\u0644\u062c\u0648\u062f\u0629 \u0641\u064a \u0627\u0644\u062e\u064a\u0648\u0637 \u062a\u062d\u062f\u062b \u0627\u0644\u0641\u0631\u0642!\u003c/blockquote\u003e",
    "description_en": "\u003cp\u003eDiscover the \u003cem\u003ebest yarn types\u003c/em\u003e for crochet beginners...\u003c/p\u003e\u003cblockquote\u003eQuality yarn makes all the difference!\u003c/blockquote\u003e",
    "id": 2,
    "image": "https://wassel.delivery/static/uploads/blogs/blog_2_def456.jpg",
    "is_active": true,
    "title_ar": "\u0623\u0641\u0636\u0644 \u0627\u0644\u062e\u064a\u0648\u0637 \u0644\u0644\u0645\u0628\u062a\u062f\u0626\u064a\u0646",
    "title_en": "Best Yarn for Beginners",
    "updated_at": "2024-12-07T14:20:00Z"
  }
]
GET /api/v1/blogs/{blog_id}
Public

Get blog details by ID. Returns complete blog information including title, description (HTML formatted), and image in both English and Arabic. Description fields contain HTML content from the rich text editor and should be rendered in your Flutter app using HtmlWidget or similar package. If blogs feature is disabled by admin, returns 404 error with message 'Blogs feature is disabled'.

Response Example

{
  "created_at": "2024-12-08T10:30:00Z",
  "description_ar": "\u003ch2\u003e\u0627\u0644\u0628\u062f\u0621\u003c/h2\u003e\u003cp\u003e\u062a\u0639\u0644\u0645 \u0623\u0633\u0627\u0633\u064a\u0627\u062a \u0627\u0644\u0643\u0631\u0648\u0634\u064a\u0647 \u0648\u0627\u0628\u062f\u0623 \u0631\u062d\u0644\u062a\u0643 \u0641\u064a \u0639\u0627\u0644\u0645 \u0627\u0644\u062d\u0631\u0641 \u0627\u0644\u064a\u062f\u0648\u064a\u0629 \u0627\u0644\u0631\u0627\u0626\u0639. \u064a\u063a\u0637\u064a \u0647\u0630\u0627 \u0627\u0644\u062f\u0644\u064a\u0644 \u0627\u0644\u0634\u0627\u0645\u0644 \u0643\u0644 \u0645\u0627 \u062a\u062d\u062a\u0627\u062c \u0644\u0645\u0639\u0631\u0641\u062a\u0647 \u0644\u0644\u0628\u062f\u0621.\u003c/p\u003e\u003ch3\u003e\u0645\u0627 \u0633\u062a\u062d\u062a\u0627\u062c\u0647\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003e\u0627\u0644\u062e\u064a\u0648\u0637:\u003c/strong\u003e \u0627\u062e\u062a\u0631 \u062e\u064a\u0648\u0637 \u0645\u062a\u0648\u0633\u0637\u0629 \u0627\u0644\u0648\u0632\u0646\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e\u0627\u0644\u062e\u0637\u0627\u0641:\u003c/strong\u003e \u0645\u0642\u0627\u0633 5.0 \u0645\u0644\u0645 \u0645\u0648\u0635\u0649 \u0628\u0647\u003c/li\u003e\u003cli\u003e\u003cstrong\u003e\u0645\u0642\u0635:\u003c/strong\u003e \u0632\u0648\u062c \u062d\u0627\u062f \u0644\u0644\u0642\u0637\u0639\u003c/li\u003e\u003c/ul\u003e\u003cp\u003e\u0644\u0645\u0632\u064a\u062f \u0645\u0646 \u0627\u0644\u0645\u0639\u0644\u0648\u0645\u0627\u062a\u060c \u0632\u0631 \u003ca href=\u0027https://example.com\u0027\u003e\u0645\u0648\u0642\u0639\u0646\u0627\u003c/a\u003e.\u003c/p\u003e",
  "description_en": "\u003ch2\u003eGetting Started\u003c/h2\u003e\u003cp\u003eLearn the basics of crochet and start your journey into the wonderful world of yarn crafts. This comprehensive guide covers everything you need to know to get started.\u003c/p\u003e\u003ch3\u003eWhat You\u0027ll Need\u003c/h3\u003e\u003cul\u003e\u003cli\u003e\u003cstrong\u003eYarn:\u003c/strong\u003e Choose a medium weight yarn\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eHook:\u003c/strong\u003e Size 5.0mm recommended\u003c/li\u003e\u003cli\u003e\u003cstrong\u003eScissors:\u003c/strong\u003e Sharp pair for cutting\u003c/li\u003e\u003c/ul\u003e\u003cp\u003eFor more information, visit our \u003ca href=\u0027https://example.com\u0027\u003ewebsite\u003c/a\u003e.\u003c/p\u003e",
  "id": 1,
  "image": "https://wassel.delivery/static/uploads/blogs/blog_1_abc123.jpg",
  "is_active": true,
  "title_ar": "\u0645\u0642\u062f\u0645\u0629 \u0641\u064a \u0627\u0644\u0643\u0631\u0648\u0634\u064a\u0647",
  "title_en": "Introduction to Crochet",
  "updated_at": "2024-12-08T10:30:00Z"
}
📄

Custom Pages

Custom content pages management endpoints for creating and managing custom pages

GET /api/v1/pages
Public

List all active custom pages. Returns pages ordered by order field and creation date.

Query Parameters

  • skip (optional, default: 0)
  • limit (optional, default: 100)
  • is_active (optional, default: true, boolean)

Response Example

[
  {
    "created_at": "2024-12-09T10:30:00Z",
    "description_ar": "\u062a\u0639\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0645\u0632\u064a\u062f \u062d\u0648\u0644 \u0634\u0631\u0643\u062a\u0646\u0627 \u0648\u0645\u0647\u0645\u062a\u0646\u0627...",
    "description_en": "Learn more about our company and mission...",
    "id": 1,
    "image": "https://wassel.delivery/static/uploads/custom_pages/page_1_abc123.jpg",
    "is_active": true,
    "order": 0,
    "slug": "about-us",
    "title_ar": "\u0645\u0646 \u0646\u062d\u0646",
    "title_en": "About Us",
    "updated_at": "2024-12-09T10:30:00Z"
  },
  {
    "created_at": "2024-12-09T11:00:00Z",
    "description_ar": "\u0634\u0631\u0648\u0637 \u0648\u0623\u062d\u0643\u0627\u0645 \u062e\u062f\u0645\u062a\u0646\u0627...",
    "description_en": "Our terms and conditions of service...",
    "id": 2,
    "image": null,
    "is_active": true,
    "order": 1,
    "slug": "terms-and-conditions",
    "title_ar": "\u0627\u0644\u0634\u0631\u0648\u0637 \u0648\u0627\u0644\u0623\u062d\u0643\u0627\u0645",
    "title_en": "Terms and Conditions",
    "updated_at": "2024-12-09T11:00:00Z"
  }
]
GET /api/v1/pages/{slug}
Public

Get custom page by slug (URL-friendly identifier). Returns complete page information including title, description, and image in both English and Arabic.

Response Example

{
  "created_at": "2024-12-09T10:30:00Z",
  "description_ar": "\u062a\u0639\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0645\u0632\u064a\u062f \u062d\u0648\u0644 \u0634\u0631\u0643\u062a\u0646\u0627 \u0648\u0645\u0647\u0645\u062a\u0646\u0627. \u0646\u062d\u0646 \u0645\u0644\u062a\u0632\u0645\u0648\u0646 \u0628\u062a\u0642\u062f\u064a\u0645 \u0645\u0646\u062a\u062c\u0627\u062a \u0648\u062e\u062f\u0645\u0627\u062a \u0639\u0627\u0644\u064a\u0629 \u0627\u0644\u062c\u0648\u062f\u0629.",
  "description_en": "Learn more about our company and mission. We are dedicated to providing quality products and services.",
  "id": 1,
  "image": "https://wassel.delivery/static/uploads/custom_pages/page_1_abc123.jpg",
  "is_active": true,
  "order": 0,
  "slug": "about-us",
  "title_ar": "\u0645\u0646 \u0646\u062d\u0646",
  "title_en": "About Us",
  "updated_at": "2024-12-09T10:30:00Z"
}
GET /api/v1/pages/id/{page_id}
Public

Get custom page by ID. Returns complete page information including title, description, and image in both English and Arabic.

Response Example

{
  "created_at": "2024-12-09T10:30:00Z",
  "description_ar": "\u062a\u0639\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0645\u0632\u064a\u062f \u062d\u0648\u0644 \u0634\u0631\u0643\u062a\u0646\u0627 \u0648\u0645\u0647\u0645\u062a\u0646\u0627. \u0646\u062d\u0646 \u0645\u0644\u062a\u0632\u0645\u0648\u0646 \u0628\u062a\u0642\u062f\u064a\u0645 \u0645\u0646\u062a\u062c\u0627\u062a \u0648\u062e\u062f\u0645\u0627\u062a \u0639\u0627\u0644\u064a\u0629 \u0627\u0644\u062c\u0648\u062f\u0629.",
  "description_en": "Learn more about our company and mission. We are dedicated to providing quality products and services.",
  "id": 1,
  "image": "https://wassel.delivery/static/uploads/custom_pages/page_1_abc123.jpg",
  "is_active": true,
  "order": 0,
  "slug": "about-us",
  "title_ar": "\u0645\u0646 \u0646\u062d\u0646",
  "title_en": "About Us",
  "updated_at": "2024-12-09T10:30:00Z"
}
🚚

Delivery API

Bahrain-only delivery: cities dropdown, user addresses, price estimate, create delivery, delivery history and status (pending, assigned, accepted, preparing, ready_for_pickup, picked_up, on_the_way, arrived, delivered, customer_not_available, delivery_failed, cancelled, returned).

GET /api/v1/delivery/cities
Public

List Bahrain delivery cities for address dropdown. Only Bahrain is supported. Use for city picker when saving address or creating delivery.

Query Parameters

  • is_active (optional, default: true)

Response Example

[
  {
    "id": 1,
    "is_active": true,
    "latitude": 26.2285,
    "longitude": 50.586,
    "name_ar": "\u0627\u0644\u0645\u0646\u0627\u0645\u0629",
    "name_en": "Manama",
    "order": 0,
    "slug": "manama"
  },
  {
    "id": 2,
    "is_active": true,
    "latitude": 26.2572,
    "longitude": 50.6119,
    "name_ar": "\u0627\u0644\u0645\u062d\u0631\u0642",
    "name_en": "Muharraq",
    "order": 1,
    "slug": "muharraq"
  }
]
GET /api/v1/delivery/addresses
Private

List current user's saved addresses. Only Bahrain addresses are valid for delivery. Requires Bearer token.

Response Example

[
  {
    "address_line1": "Block 123, Road 456",
    "city": "Manama",
    "country": "Bahrain",
    "delivery_city_id": 1,
    "id": 1,
    "is_active": true,
    "is_default": true,
    "label": "Home",
    "user_id": 1
  }
]
POST /api/v1/delivery/addresses
Private

Add a new address. Country must be Bahrain. delivery_city_id must be from /delivery/cities. Requires Bearer token.

Body Parameters

  • address_line1
  • city
  • country (must be Bahrain)
  • delivery_city_id (optional, from cities list)
  • label
  • full_name
  • phone
  • is_default

Response Example

{
  "address_line1": "Block 123",
  "city": "Manama",
  "country": "Bahrain",
  "delivery_city_id": 1,
  "id": 1,
  "user_id": 1
}
PUT /api/v1/delivery/addresses/{address_id}
Private

Update a saved address. Country must remain Bahrain. Requires Bearer token.

Body Parameters

  • address_line1
  • city
  • country
  • delivery_city_id
  • label
  • phone
  • is_default
  • is_active

Response Example

{
  "address_line1": "Block 123",
  "city": "Manama",
  "country": "Bahrain",
  "id": 1
}
DELETE /api/v1/delivery/addresses/{address_id}
Private

Delete a saved address. Requires Bearer token.

GET /api/v1/delivery/geocode
Public

Reverse geocode: convert lat/lng (e.g. user selected point on map) to human-readable address and delivery_city_id. Use response address_line and delivery_city_id when calling POST /delivery or POST /delivery/addresses. Uses OpenRouteService if API key set, else Nominatim (OSM).

Query Parameters

  • lat (required)
  • lng (required)
  • delivery_city_id (optional hint)

Response Example

{
  "address_line": "Block 123, Road 456, Manama",
  "city": "Manama",
  "delivery_city_id": 1
}
GET /api/v1/delivery/route
Public

Get driving route between pickup and destination for drawing on map and showing ETA. Returns polyline (list of [lat, lng]), distance_km, duration_minutes (typical driving time; no live traffic). Requires OPENROUTE_API_KEY.

Query Parameters

  • from_lat
  • from_lng
  • to_lat
  • to_lng

Response Example

{
  "distance_km": 8.5,
  "duration_minutes": 18.0,
  "polyline": [
    [
      26.2285,
      50.586
    ],
    [
      26.2572,
      50.6119
    ]
  ]
}
POST /api/v1/delivery/estimate
Public

Get fixed price by delivery_type (normal | express). One price for all cities. Optional from_city_id, to_city_id for distance_km/duration_minutes.

Body Parameters

  • delivery_type (string: normal | express)
  • from_city_id (optional)
  • to_city_id (optional)

Response Example

{
  "delivery_type": "normal",
  "distance_km": 8.5,
  "duration_minutes": 18.0,
  "price_bhd": 2.0
}
POST /api/v1/delivery
Private

Create a delivery request (pickup + destination). Price is fixed per delivery_type (normal|express). Requires Bearer token.

Body Parameters

  • pickup_address_line
  • pickup_city_id
  • pickup_phone (optional)
  • pickup_lat/lng (optional)
  • destination_address_line
  • destination_city_id
  • destination_phone (optional)
  • destination_lat/lng (optional)
  • notes (optional)

Response Example

{
  "created_at": "2024-12-09T10:00:00Z",
  "destination_address_line": "Road 456",
  "destination_city_id": 2,
  "distance_km": 10.2,
  "duration_minutes": 22.0,
  "id": 1,
  "pickup_address_line": "Block 123",
  "pickup_city_id": 1,
  "price_bhd": 1.5,
  "status": "pending",
  "user_id": 1
}
GET /api/v1/delivery
Private

List current user's delivery history. Optional status_filter: pending, assigned, accepted, preparing, ready_for_pickup, picked_up, on_the_way, arrived, delivered, customer_not_available, delivery_failed, cancelled, returned. Requires Bearer token.

Query Parameters

  • status_filter (optional)
  • skip (default: 0)
  • limit (default: 50, max: 100)

Response Example

[
  {
    "created_at": "2024-12-09T10:00:00Z",
    "destination_address_line": "Road 456",
    "id": 1,
    "pickup_address_line": "Block 123",
    "price_bhd": 1.5,
    "status": "pending"
  }
]
GET /api/v1/delivery/{delivery_id}
Private

Get a delivery by ID. User can only access their own deliveries. Requires Bearer token.

Response Example

{
  "created_at": "2024-12-09T10:00:00Z",
  "delivered_at": null,
  "destination_address_line": "Road 456",
  "distance_km": 10.2,
  "duration_minutes": 22.0,
  "id": 1,
  "pickup_address_line": "Block 123",
  "price_bhd": 1.5,
  "status": "in_transit",
  "user_id": 1
}
🔔

Notifications

Notifications management endpoints. Admins can create and manage notifications with titles and descriptions in English and Arabic. Notifications can be displayed to users in the mobile app. The system also automatically sends notifications for: order creation, order status changes, event reminders (1 day before), and course reminders (1 day before).

GET /api/v1/notifications
Public

List all active notifications. Returns notifications ordered by order field, then by creation date. Use is_active query parameter to filter by active status.

Query Parameters

  • skip (optional, default: 0)
  • limit (optional, default: 100, max: 100)
  • is_active (optional, default: true, boolean)

Response Example

[
  {
    "createdAt": "2024-12-10T10:00:00Z",
    "descriptionAr": "\u062a\u062d\u0642\u0642 \u0645\u0646 \u0645\u064a\u0632\u0629 \u0627\u0644\u062f\u0648\u0631\u0627\u062a \u0627\u0644\u062c\u062f\u064a\u062f\u0629!",
    "descriptionEn": "Check out our new courses feature!",
    "id": 1,
    "isActive": true,
    "order": 0,
    "titleAr": "\u0645\u064a\u0632\u0629 \u062c\u062f\u064a\u062f\u0629 \u0645\u062a\u0627\u062d\u0629",
    "titleEn": "New Feature Available",
    "updatedAt": "2024-12-10T10:00:00Z"
  }
]
GET /api/v1/notifications/{notification_id}
Public

Get notification details by ID. Returns complete notification information including title and description in both languages.

Response Example

{
  "createdAt": "2024-12-10T10:00:00Z",
  "descriptionAr": "\u062a\u062d\u0642\u0642 \u0645\u0646 \u0645\u064a\u0632\u0629 \u0627\u0644\u062f\u0648\u0631\u0627\u062a \u0627\u0644\u062c\u062f\u064a\u062f\u0629!",
  "descriptionEn": "Check out our new courses feature!",
  "id": 1,
  "isActive": true,
  "isGlobal": true,
  "order": 0,
  "titleAr": "\u0645\u064a\u0632\u0629 \u062c\u062f\u064a\u062f\u0629 \u0645\u062a\u0627\u062d\u0629",
  "titleEn": "New Feature Available",
  "updatedAt": "2024-12-10T10:00:00Z"
}
GET /api/v1/notifications/my-notifications
Private

Get all notifications for the current authenticated user. Returns both global notifications (sent to all users) and user-specific notifications (sent only to this user). Includes read status for user-specific notifications.

Auth Method Bearer Token (User Required)

Query Parameters

  • skip (optional, default: 0)
  • limit (optional, default: 100, max: 100)
  • is_read (optional, boolean - filter by read status)
  • include_global (optional, default: true, boolean - include global notifications)

Response Example

[
  {
    "createdAt": "2024-12-10T10:00:00Z",
    "descriptionAr": "\u062a\u062d\u0642\u0642 \u0645\u0646 \u0645\u064a\u0632\u0629 \u0627\u0644\u062f\u0648\u0631\u0627\u062a \u0627\u0644\u062c\u062f\u064a\u062f\u0629!",
    "descriptionEn": "Check out our new courses feature!",
    "id": 1,
    "isActive": true,
    "isGlobal": true,
    "isRead": null,
    "order": 0,
    "readAt": null,
    "titleAr": "\u0645\u064a\u0632\u0629 \u062c\u062f\u064a\u062f\u0629 \u0645\u062a\u0627\u062d\u0629",
    "titleEn": "New Feature Available",
    "updatedAt": "2024-12-10T10:00:00Z"
  },
  {
    "createdAt": "2024-12-10T11:00:00Z",
    "descriptionAr": "\u0644\u062f\u064a\u0643 \u0643\u0648\u062f \u062e\u0635\u0645 \u062e\u0627\u0635!",
    "descriptionEn": "You have a special discount code!",
    "id": 2,
    "isActive": true,
    "isGlobal": false,
    "isRead": false,
    "order": 1,
    "readAt": null,
    "titleAr": "\u0639\u0631\u0636 \u062e\u0627\u0635 \u0644\u0643",
    "titleEn": "Special Offer for You",
    "updatedAt": "2024-12-10T11:00:00Z",
    "userNotificationId": 123
  }
]
POST /api/v1/notifications/{notification_id}/mark-read
Private

Mark a user-specific notification as read. Only works for user-specific notifications (not global notifications).

Auth Method Bearer Token (User Required)

Response Example

{
  "is_read": true,
  "message": "Notification marked as read",
  "notification_id": 2,
  "success": true
}
GET /api/v1/notifications/unread-count
Private

Get count of unread notifications for the current user. Useful for displaying notification badges.

Auth Method Bearer Token (User Required)

Response Example

{
  "unread_count": 5
}
PATCH /api/v1/notifications/mark-all-read
Private

Mark all unread notifications as read for the current user.

Auth Method Bearer Token (User Required)

Response Example

{
  "count": 5,
  "message": "5 notifications marked as read",
  "success": true
}
DELETE /api/v1/notifications/{user_notification_id}
Private

Delete a specific user notification. Only the user who owns the notification can delete it. Use the userNotificationId from the /my-notifications response.

Auth Method Bearer Token (User Required)

Response Example

{
  "message": "Notification deleted successfully",
  "success": true,
  "user_notification_id": 123
}
DELETE /api/v1/notifications/delete-read
Private

Delete all read notifications for the current user. Useful for clearing old notifications.

Auth Method Bearer Token (User Required)

Response Example

{
  "count": 10,
  "message": "10 read notifications deleted",
  "success": true
}
💬

Chat API

Real-time chat between users and shop owners using Pusher. All messages are stored in the database. Users can start conversations with shop owners, send text messages, upload media (images, videos, audio, files), record voice messages, and receive real-time updates via Pusher. Shop owners can manage conversations through the Shop Owner API. Supported media types: images (.jpg, .png, .gif, .webp), videos (.mp4, .avi, .mov, .webm), audio files (.mp3, .wav, .ogg, .m4a, .aac), voice recordings (.webm), and documents (.pdf, .doc, .docx). Max file size: 50MB.

POST /api/v1/chat/conversations
Private

Create a new chat conversation with a shop owner. If a conversation already exists with this store, returns the existing one. Optionally include an initial message.

Auth Method Bearer Token (User Required)

Body Parameters

  • store_id (required, string)
  • initial_message (optional, string)

Response Example

{
  "conversation_type": "user",
  "created_at": "2024-12-12T10:30:00Z",
  "id": 1,
  "is_active": true,
  "last_message": {
    "conversation_id": 1,
    "created_at": "2024-12-12T10:30:00Z",
    "file_name": null,
    "id": 1,
    "is_read": false,
    "media_url": null,
    "message": "Hello, I have a question about your products",
    "message_type": "text",
    "sender_id": 10,
    "sender_name": "John Doe"
  },
  "last_message_at": "2024-12-12T10:30:00Z",
  "shop_owner_avatar": "https://wassel.delivery/static/uploads/users/user_5_def456.jpg",
  "shop_owner_id": 5,
  "shop_owner_name": "Shop Owner Name",
  "store_id": "store_a1b2c3d4e5f6g7h8",
  "unread_count": 0,
  "updated_at": "2024-12-12T10:30:00Z",
  "user_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
  "user_id": 10,
  "user_name": "John Doe"
}

conversation_type indicates the role of the current user in this conversation: 'shop' if the current user is the shop owner (chatting with customers), 'user' if the current user is the customer (chatting with a shop). This field helps filter conversations in the app - shop owners can separate their store conversations from their customer conversations.

GET /api/v1/chat/conversations
Private

List all chat conversations for the current user. Shop owners see conversations for their store (as shop_owner) AND conversations where they are the user (as customer). Each conversation includes a 'conversation_type' field ('shop' or 'user') to help filter conversations in the app.

Auth Method Bearer Token (User Required)

Query Parameters

  • skip (optional, int, default: 0)
  • limit (optional, int, default: 100)

Response Example

[
  {
    "conversation_type": "user",
    "created_at": "2024-12-12T10:30:00Z",
    "id": 1,
    "is_active": true,
    "last_message": {
      "conversation_id": 1,
      "created_at": "2024-12-12T10:30:00Z",
      "file_name": null,
      "id": 1,
      "is_read": true,
      "media_url": null,
      "message": "Hello, I have a question",
      "message_type": "text",
      "sender_id": 10,
      "sender_name": "John Doe"
    },
    "last_message_at": "2024-12-12T10:30:00Z",
    "shop_owner_avatar": "https://wassel.delivery/static/uploads/users/user_5_def456.jpg",
    "shop_owner_id": 5,
    "shop_owner_name": "Shop Owner Name",
    "store_id": "store_a1b2c3d4e5f6g7h8",
    "unread_count": 0,
    "updated_at": "2024-12-12T10:30:00Z",
    "user_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
    "user_id": 10,
    "user_name": "John Doe"
  },
  {
    "conversation_type": "shop",
    "created_at": "2024-12-12T09:00:00Z",
    "id": 2,
    "is_active": true,
    "last_message": {
      "conversation_id": 2,
      "created_at": "2024-12-12T11:00:00Z",
      "file_name": null,
      "id": 5,
      "is_read": false,
      "media_url": null,
      "message": "When will my order arrive?",
      "message_type": "text",
      "sender_id": 15,
      "sender_name": "Jane Smith"
    },
    "last_message_at": "2024-12-12T11:00:00Z",
    "shop_owner_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
    "shop_owner_id": 10,
    "shop_owner_name": "Current User (Shop Owner)",
    "store_id": "store_current_user_store",
    "unread_count": 1,
    "updated_at": "2024-12-12T11:00:00Z",
    "user_avatar": "https://wassel.delivery/static/uploads/users/user_15_xyz789.jpg",
    "user_id": 15,
    "user_name": "Jane Smith"
  }
]

conversation_type field: 'shop' = current user is the shop owner (chatting with customers), 'user' = current user is the customer (chatting with a shop). Shop owners who also use the app as customers will see both types. Filter conversations by conversation_type to separate 'My Store' chats from 'My Customer' chats in the app UI.

GET /api/v1/chat/conversations/{conversation_id}
Private

Get a specific conversation. User can only access their own conversations. Shop owners can access conversations for their store (as shop_owner) AND conversations where they are the user (as customer). Response includes conversation_type field ('shop' or 'user') to help filter conversations.

Auth Method Bearer Token (User Required)

Response Example

{
  "conversation_type": "user",
  "created_at": "2024-12-12T10:30:00Z",
  "id": 1,
  "is_active": true,
  "last_message": {
    "conversation_id": 1,
    "created_at": "2024-12-12T10:30:00Z",
    "file_name": null,
    "id": 1,
    "is_read": true,
    "media_url": null,
    "message": "Hello, I have a question",
    "message_type": "text",
    "sender_id": 10,
    "sender_name": "John Doe"
  },
  "last_message_at": "2024-12-12T10:30:00Z",
  "shop_owner_avatar": "https://wassel.delivery/static/uploads/users/user_5_def456.jpg",
  "shop_owner_id": 5,
  "shop_owner_name": "Shop Owner Name",
  "store_id": "store_a1b2c3d4e5f6g7h8",
  "unread_count": 0,
  "updated_at": "2024-12-12T10:30:00Z",
  "user_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
  "user_id": 10,
  "user_name": "John Doe"
}
GET /api/v1/chat/conversations/{conversation_id}/messages
Private

Get messages for a conversation. Messages are automatically marked as read when fetched. User can only access their own conversations.

Auth Method Bearer Token (User Required)

Query Parameters

  • skip (optional, int, default: 0)
  • limit (optional, int, default: 100)

Response Example

[
  {
    "conversation_id": 1,
    "created_at": "2024-12-12T10:30:00Z",
    "file_name": null,
    "id": 1,
    "is_read": true,
    "media_url": null,
    "message": "Hello, I have a question",
    "message_type": "text",
    "read_at": "2024-12-12T10:31:00Z",
    "sender_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
    "sender_id": 10,
    "sender_name": "John Doe"
  },
  {
    "conversation_id": 1,
    "created_at": "2024-12-12T10:32:00Z",
    "file_name": "product.jpg",
    "id": 2,
    "is_read": false,
    "media_url": "https://wassel.delivery/static/uploads/chat/chat_2_abc123.jpg",
    "message": "Check this out!",
    "message_type": "image",
    "read_at": null,
    "sender_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
    "sender_id": 10,
    "sender_name": "John Doe"
  },
  {
    "conversation_id": 1,
    "created_at": "2024-12-12T10:33:00Z",
    "file_name": "voice_1234567890.webm",
    "id": 3,
    "is_read": false,
    "media_url": "https://wassel.delivery/static/uploads/chat/chat_3_xyz789.webm",
    "message": null,
    "message_type": "audio",
    "read_at": null,
    "sender_avatar": "https://wassel.delivery/static/uploads/users/user_5_def456.jpg",
    "sender_id": 5,
    "sender_name": "Shop Owner"
  }
]
POST /api/v1/chat/conversations/{conversation_id}/messages
Private

Send a message in a conversation. Supports text messages, media uploads (images, videos, audio, files), and voice recordings. Message is broadcasted via Pusher in real-time. User can only send messages in their own conversations. Either 'message' (text) or 'file' (media) is required. Both can be sent together (text with media).

Auth Method Bearer Token (User Required)

Response Example

{
  "conversation_id": 1,
  "created_at": "2024-12-12T10:35:00Z",
  "file_name": "product_image.jpg",
  "file_size": 245760,
  "id": 2,
  "is_read": false,
  "media_url": "https://wassel.delivery/static/uploads/chat/chat_2_abc123def.jpg",
  "message": "Check out this image!",
  "message_type": "image",
  "read_at": null,
  "sender_avatar": "https://wassel.delivery/static/uploads/users/user_10_abc123.jpg",
  "sender_id": 10,
  "sender_name": "John Doe"
}
POST /api/v1/pusher/auth
Private

Authenticate Pusher private channel subscription. This endpoint is called automatically by Pusher when subscribing to private channels. Channel format: private-chat-{conversation_id}

Auth Method Bearer Token (User Required)

Body Parameters

  • socket_id (required, string)
  • channel_name (required, string)

Response Example

{
  "auth": "e18960692a059cc4fafb:abc123def456..."
}
🎧

Live Support System

Real-time support chat between users and admin support team using Pusher. Users can create support tickets, send messages with media attachments, and receive real-time responses from admins. Supports conversation status tracking (open, in_progress, resolved, closed), priority levels (low, normal, high, urgent), and unread message counts. All messages are stored in the database. Supported media types: images (.jpg, .png, .gif, .webp), videos (.mp4, .avi, .mov, .webm), audio files (.mp3, .wav, .ogg, .m4a, .aac), and documents (.pdf, .doc, .docx). Max file size: 50MB.

POST /api/v1/support/conversations
Private

Create a new support conversation. Users can only have one open conversation at a time. If an open conversation exists, returns an error. Optionally include a subject and initial message.

Auth Method Bearer Token (User Required)

Body Parameters

  • subject (optional, string, max 255 characters) - Conversation subject/title
  • initial_message (optional, string, max 5000 characters) - Initial message
  • priority (optional, string, default: 'normal') - Priority level: 'low', 'normal', 'high', 'urgent'

Response Example

{
  "admin_avatar": null,
  "admin_id": null,
  "admin_name": null,
  "created_at": "2024-12-25T10:00:00Z",
  "id": 1,
  "is_active": true,
  "last_message": null,
  "last_message_at": null,
  "message_count": 0,
  "priority": "normal",
  "status": "open",
  "subject": "Order issue",
  "unread_count": 0,
  "updated_at": "2024-12-25T10:00:00Z",
  "user_avatar": "https://...",
  "user_id": 123,
  "user_name": "John Doe"
}
GET /api/v1/support/conversations
Private

List all support conversations for the current user. Returns conversations sorted by last message time (most recent first).

Auth Method Bearer Token (User Required)

Query Parameters

  • skip (optional, int, default: 0)
  • limit (optional, int, default: 50)

Response Example

[
  {
    "admin_avatar": "https://...",
    "admin_id": 5,
    "admin_name": "Support Admin",
    "created_at": "2024-12-25T10:00:00Z",
    "id": 1,
    "is_active": true,
    "last_message": {
      "conversation_id": 1,
      "created_at": "2024-12-25T10:30:00Z",
      "id": 10,
      "message": "We\u0027re looking into your issue...",
      "message_type": "text",
      "sender_id": 5,
      "sender_name": "Support Admin",
      "sender_type": "admin"
    },
    "last_message_at": "2024-12-25T10:30:00Z",
    "message_count": 10,
    "priority": "normal",
    "status": "in_progress",
    "subject": "Order issue",
    "unread_count": 2,
    "updated_at": "2024-12-25T10:30:00Z",
    "user_avatar": "https://...",
    "user_id": 123,
    "user_name": "John Doe"
  }
]
GET /api/v1/support/conversations/{conversation_id}
Private

Get details of a specific support conversation. User can only access their own conversations.

Auth Method Bearer Token (User Required)

Response Example

{
  "admin_avatar": "https://...",
  "admin_id": 5,
  "admin_name": "Support Admin",
  "created_at": "2024-12-25T10:00:00Z",
  "id": 1,
  "is_active": true,
  "last_message": {
    "conversation_id": 1,
    "created_at": "2024-12-25T10:30:00Z",
    "id": 10,
    "message": "We\u0027re looking into your issue",
    "message_type": "text",
    "sender_id": 5,
    "sender_name": "Support Admin",
    "sender_type": "admin"
  },
  "last_message_at": "2024-12-25T10:30:00Z",
  "message_count": 10,
  "priority": "normal",
  "status": "in_progress",
  "subject": "Order issue",
  "unread_count": 2,
  "updated_at": "2024-12-25T10:30:00Z",
  "user_avatar": "https://...",
  "user_id": 123,
  "user_name": "John Doe"
}
GET /api/v1/support/conversations/{conversation_id}/messages
Private

Get messages for a support conversation. Messages are returned in chronological order (oldest first). Admin messages are automatically marked as read when fetched. User can only access their own conversations.

Auth Method Bearer Token (User Required)

Query Parameters

  • skip (optional, int, default: 0)
  • limit (optional, int, default: 100)

Response Example

[
  {
    "conversation_id": 1,
    "created_at": "2024-12-25T10:00:00Z",
    "file_name": null,
    "file_size": null,
    "id": 1,
    "is_read": true,
    "media_url": null,
    "message": "I need help with my order",
    "message_type": "text",
    "read_at": "2024-12-25T10:05:00Z",
    "sender_avatar": "https://...",
    "sender_id": 123,
    "sender_name": "John Doe",
    "sender_type": "user"
  },
  {
    "conversation_id": 1,
    "created_at": "2024-12-25T10:05:00Z",
    "file_name": null,
    "file_size": null,
    "id": 2,
    "is_read": true,
    "media_url": null,
    "message": "We\u0027re looking into your issue",
    "message_type": "text",
    "read_at": "2024-12-25T10:05:00Z",
    "sender_avatar": "https://...",
    "sender_id": 5,
    "sender_name": "Support Admin",
    "sender_type": "admin"
  }
]
POST /api/v1/support/conversations/{conversation_id}/messages
Private

Send a message in a support conversation. Supports text messages and media uploads (images, videos, audio, files). Message is broadcasted via Pusher in real-time. Either 'message' (text) or 'file' (media) is required. Both can be sent together (text with media).

Auth Method Bearer Token (User Required)

Response Example

{
  "conversation_id": 1,
  "created_at": "2024-12-25T10:40:00Z",
  "file_name": "screenshot.jpg",
  "file_size": 245678,
  "id": 10,
  "is_read": false,
  "media_url": "https://...",
  "message": "Here\u0027s a screenshot of the issue",
  "message_type": "image",
  "read_at": null,
  "sender_avatar": "https://...",
  "sender_id": 123,
  "sender_name": "John Doe",
  "sender_type": "user"
}
GET /api/v1/support/admin/conversations
Private

List all support conversations (admin view). Can filter by status and priority. Returns conversations sorted by last message time (most recent first).

Auth Method Bearer Token (Admin Required)

Query Parameters

  • status_filter (optional, string) - Filter by status: 'open', 'in_progress', 'resolved', 'closed'
  • priority_filter (optional, string) - Filter by priority: 'low', 'normal', 'high', 'urgent'
  • skip (optional, int, default: 0)
  • limit (optional, int, default: 50)

Response Example

"Array of SupportConversationResponse objects with user and admin information"
GET /api/v1/support/admin/conversations/{conversation_id}
Private

Get a specific support conversation (admin view). Conversation is automatically assigned to the current admin if unassigned, and status is set to 'in_progress'.

Auth Method Bearer Token (Admin Required)

Response Example

"SupportConversationResponse object with full conversation details"
PUT /api/v1/support/admin/conversations/{conversation_id}
Private

Update a support conversation (status, priority, assignment). Admins can change conversation status, priority, assign to another admin, or update the subject.

Auth Method Bearer Token (Admin Required)

Body Parameters

  • status (optional, string) - Status: 'open', 'in_progress', 'resolved', 'closed'
  • priority (optional, string) - Priority: 'low', 'normal', 'high', 'urgent'
  • admin_id (optional, int) - Assign conversation to specific admin
  • subject (optional, string, max 255 characters) - Update conversation subject

Response Example

"SupportConversationResponse object with updated conversation details"
GET /api/v1/support/admin/conversations/{conversation_id}/messages
Private

Get messages for a support conversation (admin view). User messages are automatically marked as read when fetched.

Auth Method Bearer Token (Admin Required)

Query Parameters

  • skip (optional, int, default: 0)
  • limit (optional, int, default: 100)

Response Example

"Array of SupportMessageResponse objects"
POST /api/v1/support/admin/conversations/{conversation_id}/messages
Private

Send a message in a support conversation (admin). Supports text messages and media uploads. Message is broadcasted via Pusher in real-time. Conversation is automatically assigned to current admin if unassigned.

Auth Method Bearer Token (Admin Required)

Response Example

{
  "conversation_id": 1,
  "created_at": "2024-12-25T10:45:00Z",
  "file_name": null,
  "file_size": null,
  "id": 11,
  "is_read": false,
  "media_url": null,
  "message": "We\u0027ve resolved your issue",
  "message_type": "text",
  "read_at": null,
  "sender_avatar": "https://...",
  "sender_id": 5,
  "sender_name": "Support Admin",
  "sender_type": "admin"
}
POST /api/v1/pusher/auth
Private

Authenticate Pusher private channel subscription for support chat. This endpoint is called automatically by Pusher when subscribing to private channels. Channel format: private-support-{conversation_id}. Supports both user tokens (Bearer) and admin cookies.

Auth Method Bearer Token or Admin Cookie

Response Example

{
  "auth": "e18960692a059cc4fafb:abc123def456..."
}