Baya Vendor API

Complete API reference for the Baya vendor mobile application. Covers authentication, store management, orders, products, POS, payouts, and more.

Base URL: {{BASE_URL}} Version: 1.0 Endpoints: 113 Format: JSON

Getting Started

Everything you need to integrate with the Baya Vendor API.

Base URL

All endpoints are relative to your BASE_URL (e.g. https://your-domain.com/api/v1/vendor). Replace {{BASE_URL}} throughout this document with your actual server address. All request and response bodies are JSON unless noted otherwise (file uploads use multipart/form-data).

Request Headers

{
  "Content-Type": "application/json",
  "Accept": "application/json",
  "Accept-Language": "en",          // "en" or "ar" — affects response messages
  "Authorization": "Bearer {access_token}"  // required for authenticated endpoints
}

Authentication Flow

Baya uses JWT bearer tokens with a refresh token rotation mechanism. Here is the full lifecycle:

// 1. Login → get access_token + refresh_token
POST /login
  → { access_token, refresh_token, expires_in: 3600, user, store, role }

// 2. Use access_token for all authenticated requests
GET /orders
  Headers: { Authorization: "Bearer {access_token}" }

// 3. When access_token expires (401), use refresh_token to get a new pair
POST /refresh-token
  Body: { refresh_token: "{refresh_token}" }
  → { access_token, refresh_token, expires_in: 3600 }

// 4. On logout, invalidate both tokens
POST /logout
  Headers: { Authorization: "Bearer {access_token}" }
  → tokens revoked server-side

Token Refresh — Important

The access_token expires after 60 minutes. The refresh_token expires after 30 days. When you receive a 401 on any authenticated request, call POST /refresh-token with the stored refresh token to get a new pair. The old refresh token is invalidated on each use (rotation), so always store the latest one. If the refresh token is also expired or invalid, redirect the user to the login screen.

Refresh Token Implementation

// Flutter — Dio interceptor for automatic token refresh

class AuthInterceptor extends Interceptor {
  final Dio dio;
  final AuthStorage storage;
  bool _isRefreshing = false;

  @override
  void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    final token = await storage.getAccessToken();
    if (token != null) {
      options.headers['Authorization'] = 'Bearer $token';
    }
    handler.next(options);
  }

  @override
  void onError(DioException err, ErrorInterceptorHandler handler) async {
    if (err.response?.statusCode == 401 && !_isRefreshing) {
      _isRefreshing = true;
      try {
        final refreshToken = await storage.getRefreshToken();
        if (refreshToken == null) {
          // No refresh token — force re-login
          await storage.clear();
          handler.reject(err);
          return;
        }

        final response = await Dio().post(
          '${AppConfig.baseUrl}/refresh-token',
          data: { 'refresh_token': refreshToken },
        );

        // Store new token pair
        await storage.setAccessToken(response.data['access_token']);
        await storage.setRefreshToken(response.data['refresh_token']);

        // Retry the original request with new token
        final opts = err.requestOptions;
        opts.headers['Authorization'] = 'Bearer ${response.data["access_token"]}';
        final retryResponse = await dio.fetch(opts);
        handler.resolve(retryResponse);
      } catch (e) {
        // Refresh failed — force re-login
        await storage.clear();
        handler.reject(err);
      } finally {
        _isRefreshing = false;
      }
    } else {
      handler.next(err);
    }
  }
}

Role-Based Permissions

Each employee has one role. The role determines which endpoints they can access. Requests to forbidden endpoints return 403 Forbidden.

RoleAccess
OwnerFull access to all endpoints including settings, bank, employees
ManagerAll operational access — orders, products, coupons, reviews, reports, employees
OrdersOrders (view + manage) only
ProductsProducts (view + manage), categories, variants
CashierPOS register only — create sales, search products/customers
AccountantPayouts (view), reports (view) — read-only financials

Standard Error Response

{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email field is required."],
    "password": ["The password must be at least 8 characters."]
  }
}

HTTP Status Codes

200Success — request completed
201Created — resource created successfully
401Unauthorized — token missing, expired, or invalid. Try refreshing the token.
403Forbidden — your role lacks permission for this endpoint
404Not found — resource doesn't exist or doesn't belong to your store
422Validation error — check the errors object for field-specific messages
429Rate limited — too many requests. Retry after the Retry-After header
500Server error — an unexpected error occurred. Contact support.

Pagination

List endpoints return paginated responses using Laravel's cursor/offset pagination. Use per_page (default: 20, max: 100) and navigate with the links object.

{
  "data": [...],
  "links": {
    "first": "{{BASE_URL}}/orders?page=1",
    "last": "{{BASE_URL}}/orders?page=5",
    "prev": null,
    "next": "{{BASE_URL}}/orders?page=2"
  },
  "meta": {
    "current_page": 1,
    "per_page": 20,
    "total": 95,
    "last_page": 5
  }
}

API Modules

Authentication

Login, registration, OTP verification, password reset, and token management.
🌐 Public 401 403 422
Request Body
{
  "email": "string (required)",
  "password": "string (required)"
}
Success Response 200
{
  "token": "eyJ0eXAiOiJKV1...",
  "user": {
    "id": "uuid",
    "email": "vendor@example.com",
    "first_name_en": "Ahmed",
    "type": "vendor"
  },
  "store": {
    "id": "uuid",
    "name_en": "My Fashion Store"
  },
  "role": "owner"
}
Notes
Rate limit: 10 requests/minute
🌐 Public 401 422
Request Body
{
  "refresh_token": "eyJ0eXAiOiJKV1..."
}
Success Response 200
{
  "access_token": "eyJ0eXAiOiJKV1...",
  "refresh_token": "dGhpcyBpcyBh...",
  "expires_in": 3600,
  "token_type": "Bearer"
}
Notes
Rotates the refresh token — old refresh token is invalidated. Store the new pair immediately. If refresh token is expired or invalid, returns 401 and user must re-login.
🌐 Public 422 429
Request Body
{
  "phone_code": "+966",
  "phone": "501234567"
}
Success Response 200
{
  "message": "OTP sent successfully",
  "expires_in": 300
}
Notes
Rate limit: 10 requests/minute. Phone format: Saudi 5XXXXXXXX
🌐 Public 422
Request Body
{
  "phone_code": "+966",
  "phone": "501234567",
  "otp": "1234"
}
Success Response 200
{
  "message": "Phone number verified successfully",
  "phone_verified": true
}
Notes
OTP is 4 digits. Max 3 attempts before requiring new OTP
🌐 Public 429
Request Body
{
  "phone_code": "+966",
  "phone": "501234567"
}
Success Response 200
{
  "message": "OTP sent successfully"
}
Notes
Cooldown period applies between resends
🌐 Public 422
Request Body
{
  "email": "vendor@example.com",
  "password": "SecurePass123!",
  "first_name": "Ahmed",
  "last_name": "Ali",
  "phone_code": "+966",
  "phone": "501234567",
  "store_name_en": "My Fashion Store",
  "store_name_ar": "متجر الأزياء",
  "store_logo": "(file, optional)"
}
Success Response 200
{"message": "Registration successful", "token": "eyJ0eXAiOiJKV1...", "user": {...}, "store": {...}, "role": "owner"}
Notes
Content-Type: multipart/form-data. Password: min 8 chars with mixed case and symbols
🌐 Public 422
Request Body
{
  "email": "vendor@example.com"
}
Success Response 200
{
  "message": "Password reset link sent to your email."
}
Notes
Sends password reset email
🌐 Public 422
Request Body
{
  "token": "reset-token-from-email",
  "email": "vendor@example.com",
  "password": "NewSecurePass123!",
  "password_confirmation": "NewSecurePass123!"
}
Success Response 200
{
  "message": "Password has been reset successfully."
}
Notes
Token from email link
🌐 Public 404 422
Request Body
{
  "email": "employee@example.com",
  "token": "invitation-token",
  "password": "SecurePass123!",
  "password_confirmation": "SecurePass123!"
}
Success Response 200
{
  "message": "Password set successfully. You can now log in."
}
Notes
Rate limit: 5 requests/minute. For employee onboarding
🔒 Auth Required 401
Success Response 200
{
  "message": "Logged out successfully"
}
Notes
Invalidates current token
🔒 Auth Required 401
Success Response 200
{
  "user": {
    "id": "uuid",
    "email": "vendor@example.com",
    "first_name_en": "Ahmed"
  },
  "store": {
    "id": "uuid",
    "name_en": "My Fashion Store"
  },
  "role": "owner"
}
Notes
Returns current authenticated user and store info

Dashboard

Role-specific dashboard data, charts, and onboarding progress.
🔒 Auth Required ⚙ dashboard.view 401
Query Parameters
period=7d|30d|90d
Success Response 200
{"stats": {"revenue": {"value": 15000.00, "change": 12.5}, "orders": {"value": 45, "change": 8.3}}, "recent_orders": [...], "top_products": [...], "onboarding": {...}, "role_dashboard": {...}}
Notes
Default period: 7d. Includes role-specific dashboard data
🔒 Auth Required ⚙ dashboard.view 401
Query Parameters
period=7d|30d|90d
Success Response 200
{
  "period": "7d",
  "data": [
    {
      "date": "2026-08-26",
      "revenue": 1200.0,
      "orders": 5
    }
  ]
}
Notes
Returns chart-ready time series data
🔒 Auth Required ⚙ dashboard.view 401
Success Response 200
{
  "store_info_completed": true,
  "phone_verified": true,
  "pickup_address_completed": false,
  "bank_account_completed": false,
  "first_product_added": true,
  "store_logo_completed": true,
  "dismissed": false
}
Notes
Tracks vendor setup progress
🔒 Auth Required 401
Success Response 200
{
  "message": "Onboarding dismissed.",
  "dismissed": true
}
Notes
Hides onboarding widget from dashboard

Orders

Online order management — listing, details, status transitions, and export.
🔒 Auth Required ⚙ orders.view OR orders.manage 401
Query Parameters
status, sale_channel, search, from, to, sort_by, sort_dir, per_page, with_stats
Success Response 200
{"data": [{"id": "uuid", "order_number": "ORD-4821", "status": "new", "total": 577.00, "customer": {...}}], "links": {...}, "meta": {...}, "stats": {...}}
Notes
Status: new|confirmed|packaging|ready|shipped|delivered|cancelled|returned. Default per_page: 20
🔒 Auth Required ⚙ orders.view OR orders.manage 401 403 404
Success Response 200
{"order": {"id": "uuid", "order_number": "ORD-4821", "status": "new", "items": [...], "timeline": [...], "customer": {...}}}
Notes
Returns full order details with items and timeline
🔒 Auth Required ⚙ orders.manage 401 422 500
Success Response 200
{"message": "Order confirmed", "order": {...}}
Notes
Only for orders with status: new
🔒 Auth Required ⚙ orders.manage 401 422
Success Response 200
{"message": "Order marked as ready", "order": {...}}
Notes
Transitions order to ready for pickup
🔒 Auth Required ⚙ orders.manage 401 422
Request Body
{
  "reason": "Customer requested cancellation"
}
Success Response 200
{"message": "Order cancelled", "order": {...}}
Notes
Reason required
🔒 Auth Required ⚙ orders.manage 401 422
Success Response 200
{"message": "Return confirmed", "order": {...}}
Notes
Confirms receipt of returned items
🔒 Auth Required ⚙ orders.view OR orders.manage 401
Query Parameters
same as List Orders
Response
CSV file download
Notes
Downloads CSV with order data

Products

Product catalogue CRUD, image management, variants, and publishing workflow.
🔒 Auth Required ⚙ products.view OR products.manage 401
Query Parameters
status, category_id, search, sort, sort_by, sort_dir, per_page
Success Response 200
{"data": [{"id": "uuid", "sku": "ABC-STR001", "name_en": "Classic Black Abaya", "price": 480.00, "status": "live", "variants": [...]}], "links": {...}, "meta": {...}}
Notes
Status: draft|pending_review|live|rejected|archived|out_of_stock
🔒 Auth Required ⚙ products.view OR products.manage 401 404
Success Response 200
{"product": {"id": "uuid", "sku": "ABC-STR001", "name_en": "Classic Black Abaya", "images": [...], "variants": [...], "pendingImages": [...]}}
Notes
Includes pending image changes for live products
🔒 Auth Required ⚙ products.manage 401 422 500
Request Body
{
  "name_en": "New Abaya",
  "name_ar": "عباية جديدة",
  "category_id": "uuid",
  "price": 550.0,
  "variants": [
    {
      "variant_combination": {
        "size": "M"
      },
      "stock_quantity": 20
    }
  ]
}
Success Response 200
{"message": "Product created successfully.", "product": {...}}
Notes
Price min: 50 SAR. Creates as draft status
🔒 Auth Required ⚙ products.manage 401 422 404
Request Body
{
  "name_en": "Updated Abaya",
  "price": 600.0
}
Success Response 200
{"message": "Product updated successfully.", "product": {...}}
Notes
All fields optional. Live products may require review
🔒 Auth Required ⚙ products.manage 401 422
Success Response 200
{
  "message": "Product deleted successfully."
}
Notes
Cannot delete products with active orders
🔒 Auth Required ⚙ products.manage 401 422
Success Response 200
{"message": "Product submitted for review.", "product": {...}}
Notes
Requires at least one image and one variant
🔒 Auth Required ⚙ products.manage 401
Success Response 200
{"message": "Product archived.", "product": {...}}
Notes
Removes from marketplace but keeps data
🔒 Auth Required ⚙ products.manage 401
Success Response 200
{"message": "Product moved to draft.", "product": {...}}
Notes
Returns product to draft status
🔒 Auth Required ⚙ products.manage 401
Success Response 200
{
  "message": "Product duplicated successfully.",
  "product": {
    "id": "new-uuid",
    "name_en": "Classic Black Abaya (Copy)",
    "status": "draft"
  }
}
Notes
Creates draft copy with new SKU
🔒 Auth Required ⚙ products.manage 401 422
Request Body multipart/form-data
images[] (files)
Success Response 200
{"message": "Images uploaded and pending admin review.", "images": [...], "pending_review": true}
Notes
Max 6 images. Formats: jpeg/png/jpg/webp. Max 5MB each
🔒 Auth Required ⚙ products.manage 401
Success Response 200
{
  "message": "Image deleted successfully."
}
Notes
Live products: marked for removal pending review
🔒 Auth Required ⚙ products.manage 401
Request Body
{
  "image_ids": [
    123,
    456,
    789
  ]
}
Success Response 200
{
  "message": "Images reordered successfully."
}
Notes
Array order determines display order
🔒 Auth Required ⚙ products.manage 401
Success Response 200
{
  "message": "Pending action cancelled.",
  "has_pending_review": false
}
Notes
Cancels pending add/remove image action
🔒 Auth Required 401
Success Response 200
{"data": [{"id": "uuid", "name_en": "Abayas", "name_ar": "عبايات", "children": [...]}]}
Notes
Hierarchical category list for product forms
🔒 Auth Required 401
Success Response 200
{
  "data": [
    {
      "id": 1,
      "type": "size",
      "name_en": "Size",
      "options": [
        {
          "id": 1,
          "value": "S"
        }
      ]
    }
  ]
}
Notes
Available size/color options for variants
🔒 Auth Required 401
Success Response 200
{
  "data": [
    {
      "id": "uuid",
      "name_en": "Casual",
      "name_ar": "كاجوال"
    }
  ]
}
Notes
Tags like Casual/Formal/Wedding
🔒 Auth Required 401
Success Response 200
{
  "data": [
    {
      "id": 1,
      "type_name_en": "Fabric",
      "name_en": "Cotton",
      "name_ar": "قطن"
    }
  ]
}
Notes
Fabric types and other specifications

POS

Point-of-sale — subscription, register, sales, receipts, and POS analytics.
🔒 Auth Required ⚙ pos.view OR pos.manage 401
Success Response 200
{"subscription": {"status": "active", "plan_name": "Monthly", "can_access_pos": true}, "payment_method": {...}, "config": {...}, "features": [...]}
Notes
Returns full POS subscription details and available plans
🔒 Auth Required ⚙ settings.manage 401 422
Request Body
{
  "plan_name": "Monthly"
}
Success Response 200
{"message": "Trial started successfully!", "subscription": {...}}
Notes
Starts trial or activates subscription. Requires payment method
🔒 Auth Required ⚙ settings.manage 401
Success Response 200
{"message": "Subscription cancelled. You can continue using POS until 2026-10-01.", "subscription": {...}}
Notes
Access continues until period end
🔒 Auth Required ⚙ settings.manage 401
Request Body
{
  "plan_name": "Monthly"
}
Success Response 200
{"message": "Subscription reactivated successfully!", "subscription": {...}}
Notes
Reactivates cancelled subscription
🔒 Auth Required ⚙ settings.manage 401
Request Body
{
  "plan_name": "Quarterly"
}
Success Response 200
{"message": "Plan changed successfully.", "subscription": {...}}
Notes
New pricing applies at next billing date
🔒 Auth Required ⚙ pos.register 401
Query Parameters
category_id, search, per_page
Success Response 200
{"data": [{"id": "uuid", "sku": "ABC-001", "name": "Classic Black Abaya", "price": 480.00, "variants": [...]}], "meta": {...}}
Notes
Products for POS terminal. Default per_page: 100
🔒 Auth Required ⚙ pos.register 401
Success Response 200
{"data": [{"id": "uuid", "name": "Popular Item", "variants": [...]}]}
Notes
Top 6 products by POS sales in last 30 days
🔒 Auth Required ⚙ pos.register 401
Success Response 200
{
  "categories": [
    {
      "id": "uuid",
      "name": "Abayas",
      "name_ar": "عبايات"
    }
  ]
}
Notes
Category filter for POS terminal
🔒 Auth Required ⚙ pos.register 401
Query Parameters
q (required, min 2 chars)
Success Response 200
{
  "customers": [
    {
      "id": "uuid",
      "name": "Sara Al-Zahrani",
      "phone": "+966504336883",
      "orders_count": 5
    }
  ]
}
Notes
Search by phone or name
🔒 Auth Required ⚙ pos.register 401 403 422
Request Body
{
  "items": [
    {
      "product_id": "uuid",
      "variant_id": "uuid",
      "quantity": 2,
      "price": 480.0
    }
  ],
  "customer": {
    "phone": "+966504336883"
  },
  "discount": {
    "mode": "pct",
    "value": 10
  },
  "payment_method": "cash"
}
Success Response 200
{"message": "Sale completed successfully.", "order": {...}, "receipt": {...}}
Notes
payment_method: cash|card|split. Requires active POS subscription
🔒 Auth Required ⚙ pos.sales 401
Query Parameters
from, to, search, sort_by, sort_dir, per_page
Success Response 200
{"orders": [...], "pagination": {...}, "stats": {"total_sales": 50, "total_revenue": 25000.00}}
Notes
POS transaction history
🔒 Auth Required ⚙ pos.sales 401
Response
PDF file download
Notes
80mm receipt format. Use Accept-Language header for ar/en
🔒 Auth Required ⚙ pos.view OR pos.manage 401
Success Response 200
{"invoices": [{"id": "uuid", "invoice_number": "INV-001", "total_amount": 99.99, "status": "paid"}], "pagination": {...}}
Notes
POS subscription invoices
🔒 Auth Required ⚙ pos.view OR pos.manage 401
Success Response 200
{
  "invoice": {
    "id": "uuid",
    "invoice_number": "INV-001",
    "amount": 86.95,
    "vat_amount": 13.04,
    "total_amount": 99.99,
    "status": "paid"
  }
}
Notes
Full invoice details
🔒 Auth Required ⚙ pos.view OR pos.manage 401
Response
PDF file download
Notes
Downloadable invoice PDF
🔒 Auth Required ⚙ pos.reports 401
Query Parameters
from, to
Success Response 200
{"revenue": {"total": 25000.00, "chart": [...]}, "products": {...}, "customers": {...}, "orders": {...}}
Notes
POS-specific analytics dashboard

Coupons

Discount coupon management — create, update, toggle, and delete.
🔒 Auth Required ⚙ coupons.manage 401
Query Parameters
status, per_page
Success Response 200
{"data": [{"id": "uuid", "code": "SUMMER10", "type": "percent", "amount": 10, "status": "active", "orders_count": 25}], "pagination": {...}, "stats": {...}}
Notes
Status: active|paused|expired
🔒 Auth Required ⚙ coupons.manage 401 422
Request Body
{
  "code": "SUMMER10",
  "name_en": "Summer Sale",
  "type": "percent",
  "amount": 10,
  "min_order_amount": 100.0,
  "valid_from": "2026-09-01",
  "valid_until": "2026-09-30"
}
Success Response 200
{"message": "Coupon created successfully.", "coupon": {...}}
Notes
Type: percent|fixed. Code must be unique per store
🔒 Auth Required ⚙ coupons.manage 401 422
Request Body
{
  "name_en": "Updated Sale",
  "amount": 15
}
Success Response 200
{"message": "Coupon updated successfully.", "coupon": {...}}
Notes
Code cannot be changed after creation
🔒 Auth Required ⚙ coupons.manage 401
Success Response 200
{
  "message": "Coupon deleted successfully."
}
Notes
Permanently deletes coupon
🔒 Auth Required ⚙ coupons.manage 401
Success Response 200
{
  "message": "Coupon paused.",
  "coupon": {
    "id": "uuid",
    "status": "paused"
  }
}
Notes
Toggles between active and paused

Reviews

Customer review listing and vendor replies.
🔒 Auth Required ⚙ reviews.manage 401
Query Parameters
month, year, stars, unreplied, sort_by, sort_dir, per_page
Success Response 200
{"data": [{"id": "uuid", "stars": 5, "title": "Amazing Quality", "comment": "...", "reply": null, "customer": {...}, "product": {...}}], "pagination": {...}, "stats": {...}}
Notes
Stars: 1-5. Stats includes average rating and distribution
🔒 Auth Required ⚙ reviews.manage 401 422
Request Body
{
  "reply": "Thank you for your wonderful feedback!"
}
Success Response 200
{"message": "Reply added successfully.", "review": {...}}
Notes
Reply max 1000 chars. One reply per review

Reports

Revenue, order, product, and payout reports with export.
🔒 Auth Required ⚙ reports.view 401
Query Parameters
type (required), from, to, channel
Success Response 200
{"type": "revenue", "from": "2026-09-01", "to": "2026-09-30", "summary": {...}, "chart": {...}, "table": {...}}
Notes
Type: revenue|orders|products|payouts|returns|customers
🔒 Auth Required ⚙ reports.view 401
Query Parameters
same as Get Reports
Response
CSV file download
Notes
Downloads report as CSV

Payouts

Payout history, balance summary, and payout details.
🔒 Auth Required ⚙ payouts.view 401
Query Parameters
status, per_page
Success Response 200
{"data": [{"id": "uuid", "payout_number": "PAYOUT-008", "period_label": "September 2026", "net_amount": 12250.00, "status": "pending"}], "meta": {...}, "bank_account": {...}}
Notes
Status: pending|processing|paid|failed
🔒 Auth Required ⚙ payouts.view 401
Success Response 200
{"pending_balance": 12250.00, "total_earned": 85000.00, "next_payout_date": "2026-09-20", "upcoming_payout": {...}, "last_payout": {...}, "bank_account": {...}}
Notes
Overview of earnings and upcoming payout
🔒 Auth Required ⚙ payouts.view 401 404
Success Response 200
{
  "payout": {
    "id": "uuid",
    "payout_number": "PAYOUT-008",
    "gross_amount": 15000.0,
    "commission_amount": 2250.0,
    "net_amount": 12250.0
  }
}
Notes
Full payout breakdown

Employees

Team management — invite, update roles, remove staff members.
🔒 Auth Required ⚙ employees.manage 401
Success Response 200
{
  "data": [
    {
      "id": "uuid",
      "first_name": "Maha",
      "email": "maha@store.com",
      "role": "manager",
      "accepted_at": "2026-08-02T10:30:00Z"
    }
  ]
}
Notes
All store employees including pending invitations
🔒 Auth Required ⚙ employees.manage 401 422
Request Body
{
  "email": "newemployee@store.com",
  "role": "products",
  "first_name_en": "Sara",
  "first_name_ar": "سارة",
  "last_name_en": "Al-Dosari",
  "last_name_ar": "الدوسري"
}
Success Response 200
{"message": "Employee invited successfully.", "employee": {...}}
Notes
Roles: manager|products|orders|accountant|cashier. Cashier requires active POS
🔒 Auth Required ⚙ employees.manage 401
Request Body
{
  "role": "manager",
  "preferred_language": "en"
}
Success Response 200
{"message": "Employee role updated.", "employee": {...}}
Notes
Can change role and language preference
🔒 Auth Required ⚙ employees.manage 401 422
Success Response 200
{
  "message": "Employee removed."
}
Notes
Cannot remove owner or yourself
🔒 Auth Required ⚙ employees.manage 401 422
Success Response 200
{
  "message": "Invitation resent.",
  "invitation_count": 2
}
Notes
Max 5 invitations per employee

Notifications

Push notification listing, read status, and badge counts.
🔒 Auth Required 401
Query Parameters
type, unread_only, per_page
Success Response 200
{"data": [{"id": "uuid", "type": "order", "title": "New Order Received", "message": "...", "is_read": false}], "meta": {...}, "unread_count": 8}
Notes
Type: system|order|product|payout|review
🔒 Auth Required 401
Success Response 200
{
  "unread_count": 8
}
Notes
Quick badge count check
🔒 Auth Required 401
Success Response 200
{
  "message": "Notification marked as read."
}
Notes
Marks single notification as read
🔒 Auth Required 401
Success Response 200
{
  "message": "All notifications marked as read."
}
Notes
Bulk mark all as read

Market

Baya Market — B2B supplies ordering for vendors.
🔒 Auth Required 401
Success Response 200
{
  "enabled": true,
  "has_valid_payment_method": true,
  "shipping_fee": 25.0,
  "vat_rate": 15.0,
  "freeShippingEnabled": true,
  "freeShippingThreshold": 300
}
Notes
Baya Market availability and config
🔒 Auth Required ⚙ market.view OR market.manage 401
Success Response 200
{
  "data": [
    {
      "id": "uuid",
      "name": "Premium Packaging Box (50 pcs)",
      "price": 150.0,
      "category": "Packaging"
    }
  ]
}
Notes
Available market items for purchase
🔒 Auth Required ⚙ market.view OR market.manage 401
Success Response 200
{"cart": {"id": "uuid", "items": [...], "subtotal": 300.00, "shipping_fee": 0, "vat_amount": 45.00, "total": 345.00}}
Notes
Current cart with calculated totals
🔒 Auth Required ⚙ market.manage 401
Request Body
{
  "item_id": "uuid",
  "quantity": 2
}
Success Response 200
{"message": "Item added to cart.", "item": {...}, "cart": {...}}
Notes
Adds item or updates quantity if exists
🔒 Auth Required ⚙ market.manage 401
Request Body
{
  "quantity": 5
}
Success Response 200
{"message": "Cart updated.", "item": {...}, "cart": {...}}
Notes
Updates item quantity
🔒 Auth Required ⚙ market.manage 401
Success Response 200
{"message": "Item removed from cart.", "cart": {...}}
Notes
Removes single item from cart
🔒 Auth Required ⚙ market.manage 401
Success Response 200
{
  "message": "Cart cleared."
}
Notes
Removes all items from cart
🔒 Auth Required ⚙ market.view OR market.manage 401
Success Response 200
{
  "payment_methods": [
    {
      "id": "uuid",
      "card_brand": "Visa",
      "masked_card": "****1234",
      "is_default": true
    }
  ]
}
Notes
Saved payment methods for checkout
🔒 Auth Required ⚙ market.manage 401
Success Response 200
{"cart": {...}, "totals": {"subtotal": 300.00, "shipping_fee": 0, "vat_amount": 45.00, "total": 345.00}}
Notes
Validates cart and returns final totals
🔒 Auth Required ⚙ market.manage 401 422
Request Body
{
  "payment_method_id": "uuid",
  "shipping_address": "King Fahd Road",
  "shipping_city": "Riyadh",
  "shipping_phone": "+966501234567",
  "notes": "Please call before delivery"
}
Success Response 200
{
  "message": "Order placed successfully.",
  "order": {
    "id": "uuid",
    "order_number": "MO-001",
    "total": 345.0
  }
}
Notes
Creates market order and charges payment method
🔒 Auth Required ⚙ market.view OR market.manage 401
Query Parameters
status, search, per_page
Success Response 200
{"data": [{"id": "uuid", "order_number": "MO-001", "status": "delivered", "total": 345.00}], "pagination": {...}, "stats": {...}}
Notes
Status: pending|confirmed|shipped|delivered|cancelled
🔒 Auth Required ⚙ market.view OR market.manage 401 404
Success Response 200
{"order": {"id": "uuid", "order_number": "MO-001", "status": "delivered", "items": [...], "timeline": [...], "report": null}}
Notes
Full order details with timeline
🔒 Auth Required ⚙ market.manage 401 422
Request Body
{
  "reason": "Changed my mind"
}
Success Response 200
{"message": "Order cancelled successfully.", "order": {...}}
Notes
Only pending orders can be cancelled
🔒 Auth Required ⚙ market.manage 401 422
Request Body
{
  "message": "Items arrived damaged. Package was torn."
}
Success Response 200
{
  "message": "Report submitted successfully.",
  "report_id": "uuid"
}
Notes
Message: min 10 chars
🔒 Auth Required ⚙ market.view OR market.manage 401
Response
PDF file download
Notes
Invoice PDF for market order

Settings

Store settings, owner info, pickup address, bank details, and account management.
🔒 Auth Required ⚙ settings.view OR settings.manage 401
Success Response 200
{"store": {"id": "uuid", "name_en": "My Fashion Store", "name_ar": "متجر الأزياء", "logo_url": "https://...", "status": "active"}, "pending_name_change": {...}}
Notes
Current store settings and pending changes
🔒 Auth Required ⚙ settings.manage 401 422
Request Body multipart/form-data
name_en, name_ar, description_en, description_ar, category, city, logo (file)
Success Response 200
{"message": "Store settings updated.", "store": {...}}
Notes
Content-Type: multipart/form-data. Logo: max 2MB
🔒 Auth Required ⚙ settings.manage 401 422
Request Body
{
  "name_en": "New Store Name",
  "name_ar": "اسم المتجر الجديد",
  "reason": "Rebranding"
}
Success Response 200
{
  "message": "Name change request submitted successfully."
}
Notes
Name changes require admin approval
🔒 Auth Required ⚙ settings.view OR settings.manage 401
Success Response 200
{
  "owner": {
    "id": "uuid",
    "email": "owner@store.com",
    "phone": "+966501234567",
    "first_name_en": "Ahmed",
    "national_id": "1234567890"
  }
}
Notes
Owner only. Personal account details
🔒 Auth Required ⚙ settings.manage 401 422
Request Body multipart/form-data
first_name_en, first_name_ar, last_name_en, last_name_ar, phone, national_id, owner_picture (file)
Success Response 200
{"message": "Owner info updated.", "owner": {...}}
Notes
Owner only. Content-Type: multipart/form-data
🔒 Auth Required ⚙ settings.manage 401 422
Request Body
{
  "new_email": "newemail@store.com",
  "password": "currentPassword123!"
}
Success Response 200
{
  "message": "Verification email sent to your new email address."
}
Notes
Sends verification to new email
🌐 Public 422
Request Body
{
  "token": "verification-token",
  "email": "newemail@store.com"
}
Success Response 200
{
  "message": "Email address updated successfully.",
  "new_email": "newemail@store.com"
}
Notes
Public endpoint. Token from email link
🔒 Auth Required ⚙ settings.manage 401
Request Body
{
  "phone_code": "+966",
  "phone": "509876543"
}
Success Response 200
{
  "message": "Verification code sent to your new phone number.",
  "expires_in": 300
}
Notes
Sends OTP to new phone
🔒 Auth Required ⚙ settings.manage 422
Request Body
{
  "phone_code": "+966",
  "phone": "509876543",
  "otp": "1234"
}
Success Response 200
{
  "message": "Phone number updated successfully.",
  "new_phone": "+966509876543"
}
Notes
OTP verification for phone change
🔒 Auth Required ⚙ settings.view OR settings.manage 401
Success Response 200
{
  "pickup_address": {
    "city": "Riyadh",
    "district": "Al-Olaya",
    "street": "King Fahd Road",
    "latitude": 24.7136,
    "longitude": 46.6753,
    "available_from": "09:00",
    "available_to": "18:00"
  }
}
Notes
Shipping pickup location
🔒 Auth Required ⚙ settings.manage 401
Request Body
{
  "city": "Riyadh",
  "district": "Al-Olaya",
  "street": "King Fahd Road",
  "latitude": 24.7136,
  "longitude": 46.6753,
  "contact_name": "Ahmed",
  "contact_phone": "+966501234567"
}
Success Response 200
{"message": "Pickup address updated.", "pickup_address": {...}}
Notes
Location and availability settings
🔒 Auth Required ⚙ bank.manage 401
Success Response 200
{"bank_account": {"bank": {"name_en": "Al Rajhi Bank"}, "iban": "SA****1234567890", "account_holder_name": "Ahmed Ali", "is_verified": true}, "owner": {...}, "platform": {...}}
Notes
Owner only. Bank account for payouts
🔒 Auth Required ⚙ bank.manage 401
Request Body
{
  "bank_id": 1,
  "iban": "SA1234567890123456789012",
  "account_holder_name": "Ahmed Ali"
}
Success Response 200
{
  "message": "Verification code sent to your registered phone number.",
  "expires_in": 300
}
Notes
Owner only. Sends OTP to verify change
🔒 Auth Required ⚙ bank.manage 401 422
Request Body
{
  "bank_id": 1,
  "iban": "SA1234567890123456789012",
  "otp": "1234",
  "account_holder_name": "Ahmed Ali"
}
Success Response 200
{"message": "Bank details updated successfully.", "bank_account": {...}}
Notes
Owner only. OTP verification for bank change
🔒 Auth Required ⚙ settings.view OR settings.manage 401
Success Response 200
{
  "notification_settings": {
    "notify_new_order": true,
    "notify_order_shipped": true,
    "notify_payout": true,
    "notify_marketing": false
  }
}
Notes
Push notification preferences
🔒 Auth Required ⚙ settings.manage 401
Request Body
{
  "notify_new_order": true,
  "notify_marketing": false
}
Success Response 200
{"message": "Notification settings updated.", "notification_settings": {...}}
Notes
Toggle individual notification types
🔒 Auth Required ⚙ settings.manage 401 422
Request Body
{
  "current_password": "OldPassword123!",
  "password": "NewPassword456!",
  "password_confirmation": "NewPassword456!"
}
Success Response 200
{
  "message": "Password changed successfully."
}
Notes
Password: min 8 chars with mixed case/numbers/symbols
🔒 Auth Required ⚙ settings.manage 401
Success Response 200
{
  "message": "Store hidden from marketplace."
}
Notes
Owner only. Vacation mode - hides store
🔒 Auth Required ⚙ settings.manage 401 422
Success Response 200
{
  "message": "Store is now visible on marketplace."
}
Notes
Owner only. Store must be admin-approved
🔒 Auth Required 401
Success Response 200
{
  "platform": {
    "vat_rate": 0.15,
    "minPrice": 50,
    "payoutReleaseDays": 14,
    "otpResendCooldown": 60
  }
}
Notes
Platform-wide settings and limits
🔒 Auth Required 401
Success Response 200
{
  "data": [
    {
      "id": 1,
      "code": "RJHI",
      "name_en": "Al Rajhi Bank",
      "name_ar": "مصرف الراجحي"
    }
  ]
}
Notes
List of supported banks for payout setup

Device Tokens

FCM device token registration for push notifications.
🔒 Auth Required 401
Request Body
{
  "token": "fcm-device-token",
  "platform": "ios"
}
Success Response 200
{
  "message": "Device token registered."
}
Notes
Register FCM token for push notifications. Platform: ios|android
🔒 Auth Required 401
Request Body
{
  "token": "fcm-device-token"
}
Success Response 200
{
  "message": "Device token removed."
}
Notes
Remove device token on logout