Baya Vendor API
Complete API reference for the Baya vendor mobile application. Covers authentication, store management, orders, products, POS, payouts, and more.
Getting Started
Everything you need to integrate with the Baya Vendor API.
Base URL
All endpoints are relative to yourBASE_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
Theaccess_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.
| Role | Access |
|---|---|
| Owner | Full access to all endpoints including settings, bank, employees |
| Manager | All operational access — orders, products, coupons, reviews, reports, employees |
| Orders | Orders (view + manage) only |
| Products | Products (view + manage), categories, variants |
| Cashier | POS register only — create sales, search products/customers |
| Accountant | Payouts (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
| 200 | Success — request completed |
| 201 | Created — resource created successfully |
| 401 | Unauthorized — token missing, expired, or invalid. Try refreshing the token. |
| 403 | Forbidden — your role lacks permission for this endpoint |
| 404 | Not found — resource doesn't exist or doesn't belong to your store |
| 422 | Validation error — check the errors object for field-specific messages |
| 429 | Rate limited — too many requests. Retry after the Retry-After header |
| 500 | Server 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.
POST
/api/v1/vendor/login
Login
▼
🌐 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
POST
/api/v1/vendor/refresh-token
Refresh Token
▼
🌐 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.
POST
/api/v1/vendor/register/send-otp
Send OTP
▼
🌐 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
POST
/api/v1/vendor/register/verify-phone-otp
Verify Phone OTP
▼
🌐 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
POST
/api/v1/vendor/register/resend-phone-otp
Resend Phone OTP
▼
🌐 Public
429
Request Body
{
"phone_code": "+966",
"phone": "501234567"
}
Success Response 200
{
"message": "OTP sent successfully"
}
Notes
Cooldown period applies between resends
POST
/api/v1/vendor/register
Register
▼
🌐 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
POST
/api/v1/vendor/forgot-password
Forgot Password
▼
🌐 Public
422
Request Body
{
"email": "vendor@example.com"
}
Success Response 200
{
"message": "Password reset link sent to your email."
}
Notes
Sends password reset email
POST
/api/v1/vendor/reset-password
Reset Password
▼
🌐 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
POST
/api/v1/vendor/accept-invitation
Accept Invitation
▼
🌐 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
POST
/api/v1/vendor/logout
Logout
▼
🔒 Auth Required
401
Success Response 200
{
"message": "Logged out successfully"
}
Notes
Invalidates current token
GET
/api/v1/vendor/me
Get Current User
▼
🔒 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.
GET
/api/v1/vendor/dashboard
Overview
▼
🔒 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
GET
/api/v1/vendor/dashboard/chart
Chart 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
GET
/api/v1/vendor/onboarding
Onboarding Status
▼
🔒 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
PATCH
/api/v1/vendor/onboarding/dismiss
Dismiss Onboarding
▼
🔒 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.
GET
/api/v1/vendor/orders
List
▼
🔒 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
GET
/api/v1/vendor/orders/{order_id}
Detail
▼
🔒 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
POST
/api/v1/vendor/orders/{order_id}/confirm
Confirm
▼
🔒 Auth Required
⚙ orders.manage
401
422
500
Success Response 200
{"message": "Order confirmed", "order": {...}}
Notes
Only for orders with status: new
POST
/api/v1/vendor/orders/{order_id}/ready
Mark Ready
▼
🔒 Auth Required
⚙ orders.manage
401
422
Success Response 200
{"message": "Order marked as ready", "order": {...}}
Notes
Transitions order to ready for pickup
POST
/api/v1/vendor/orders/{order_id}/cancel
Cancel
▼
🔒 Auth Required
⚙ orders.manage
401
422
Request Body
{
"reason": "Customer requested cancellation"
}
Success Response 200
{"message": "Order cancelled", "order": {...}}
Notes
Reason required
POST
/api/v1/vendor/orders/{order_id}/confirm-return
Confirm Return
▼
🔒 Auth Required
⚙ orders.manage
401
422
Success Response 200
{"message": "Return confirmed", "order": {...}}
Notes
Confirms receipt of returned items
GET
/api/v1/vendor/orders/export
Export
▼
🔒 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.
GET
/api/v1/vendor/products
List
▼
🔒 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
GET
/api/v1/vendor/products/{product_id}
Detail
▼
🔒 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
POST
/api/v1/vendor/products
Create
▼
🔒 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
PUT
/api/v1/vendor/products/{product_id}
Update
▼
🔒 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
DELETE
/api/v1/vendor/products/{product_id}
Delete
▼
🔒 Auth Required
⚙ products.manage
401
422
Success Response 200
{
"message": "Product deleted successfully."
}
Notes
Cannot delete products with active orders
POST
/api/v1/vendor/products/{product_id}/publish
Publish
▼
🔒 Auth Required
⚙ products.manage
401
422
Success Response 200
{"message": "Product submitted for review.", "product": {...}}
Notes
Requires at least one image and one variant
POST
/api/v1/vendor/products/{product_id}/archive
Archive
▼
🔒 Auth Required
⚙ products.manage
401
Success Response 200
{"message": "Product archived.", "product": {...}}
Notes
Removes from marketplace but keeps data
POST
/api/v1/vendor/products/{product_id}/draft
Draft
▼
🔒 Auth Required
⚙ products.manage
401
Success Response 200
{"message": "Product moved to draft.", "product": {...}}
Notes
Returns product to draft status
POST
/api/v1/vendor/products/{product_id}/duplicate
Duplicate
▼
🔒 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
POST
/api/v1/vendor/products/{product_id}/images
Upload Images
▼
🔒 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
DELETE
/api/v1/vendor/products/{product_id}/images/{image_id}
Delete Image
▼
🔒 Auth Required
⚙ products.manage
401
Success Response 200
{
"message": "Image deleted successfully."
}
Notes
Live products: marked for removal pending review
PATCH
/api/v1/vendor/products/{product_id}/images/reorder
Reorder Images
▼
🔒 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
DELETE
/api/v1/vendor/products/{product_id}/pending-images/{id}
Cancel Pending Image
▼
🔒 Auth Required
⚙ products.manage
401
Success Response 200
{
"message": "Pending action cancelled.",
"has_pending_review": false
}
Notes
Cancels pending add/remove image action
GET
/api/v1/vendor/categories
Categories Lookup
▼
🔒 Auth Required
401
Success Response 200
{"data": [{"id": "uuid", "name_en": "Abayas", "name_ar": "عبايات", "children": [...]}]}
Notes
Hierarchical category list for product forms
GET
/api/v1/vendor/variant-options
Variant Options Lookup
▼
🔒 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
GET
/api/v1/vendor/occasion-tags
Occasion Tags Lookup
▼
🔒 Auth Required
401
Success Response 200
{
"data": [
{
"id": "uuid",
"name_en": "Casual",
"name_ar": "كاجوال"
}
]
}
Notes
Tags like Casual/Formal/Wedding
GET
/api/v1/vendor/specification-options
Specification Options Lookup
▼
🔒 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.
GET
/api/v1/vendor/settings/pos
Subscription Status
▼
🔒 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
POST
/api/v1/vendor/settings/pos/subscribe
Subscribe
▼
🔒 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
POST
/api/v1/vendor/settings/pos/cancel
Cancel Subscription
▼
🔒 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
POST
/api/v1/vendor/settings/pos/reactivate
Reactivate Subscription
▼
🔒 Auth Required
⚙ settings.manage
401
Request Body
{
"plan_name": "Monthly"
}
Success Response 200
{"message": "Subscription reactivated successfully!", "subscription": {...}}
Notes
Reactivates cancelled subscription
POST
/api/v1/vendor/settings/pos/change-plan
Change Plan
▼
🔒 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
GET
/api/v1/vendor/pos/products
Products
▼
🔒 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
GET
/api/v1/vendor/pos/products/frequent
Frequent Products
▼
🔒 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
GET
/api/v1/vendor/pos/categories
Categories
▼
🔒 Auth Required
⚙ pos.register
401
Success Response 200
{
"categories": [
{
"id": "uuid",
"name": "Abayas",
"name_ar": "عبايات"
}
]
}
Notes
Category filter for POS terminal
GET
/api/v1/vendor/pos/customers/search
Search Customers
▼
🔒 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
POST
/api/v1/vendor/pos/sales
Create Sale
▼
🔒 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
GET
/api/v1/vendor/pos/sales
List Sales
▼
🔒 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
GET
/api/v1/vendor/pos/receipts/{order_id}/pdf
Download Receipt
▼
🔒 Auth Required
⚙ pos.sales
401
Response
PDF file download
Notes
80mm receipt format. Use Accept-Language header for ar/en
GET
/api/v1/vendor/settings/pos/invoices
Invoices List
▼
🔒 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
GET
/api/v1/vendor/settings/pos/invoices/{invoice_id}
Invoice Detail
▼
🔒 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
GET
/api/v1/vendor/settings/pos/invoices/{invoice_id}/pdf
Download Invoice
▼
🔒 Auth Required
⚙ pos.view OR pos.manage
401
Response
PDF file download
Notes
Downloadable invoice PDF
GET
/api/v1/vendor/reports/pos-dashboard
Dashboard/Reports
▼
🔒 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.
GET
/api/v1/vendor/coupons
List
▼
🔒 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
POST
/api/v1/vendor/coupons
Create
▼
🔒 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
PUT
/api/v1/vendor/coupons/{coupon_id}
Update
▼
🔒 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
DELETE
/api/v1/vendor/coupons/{coupon_id}
Delete
▼
🔒 Auth Required
⚙ coupons.manage
401
Success Response 200
{
"message": "Coupon deleted successfully."
}
Notes
Permanently deletes coupon
POST
/api/v1/vendor/coupons/{coupon_id}/toggle
Toggle Status
▼
🔒 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.
GET
/api/v1/vendor/reviews
List
▼
🔒 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
POST
/api/v1/vendor/reviews/{review_id}/reply
Reply
▼
🔒 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.
GET
/api/v1/vendor/reports
Get
▼
🔒 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
GET
/api/v1/vendor/reports/export
Export
▼
🔒 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.
GET
/api/v1/vendor/payouts
List
▼
🔒 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
GET
/api/v1/vendor/payouts/balance
Balance Summary
▼
🔒 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
GET
/api/v1/vendor/payouts/{payout_id}
Detail
▼
🔒 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.
GET
/api/v1/vendor/employees
List
▼
🔒 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
POST
/api/v1/vendor/employees
Invite
▼
🔒 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
PATCH
/api/v1/vendor/employees/{employee_id}
Update
▼
🔒 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
DELETE
/api/v1/vendor/employees/{employee_id}
Remove
▼
🔒 Auth Required
⚙ employees.manage
401
422
Success Response 200
{
"message": "Employee removed."
}
Notes
Cannot remove owner or yourself
POST
/api/v1/vendor/employees/{employee_id}/resend-invitation
Resend Invitation
▼
🔒 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.
GET
/api/v1/vendor/notifications
List
▼
🔒 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
GET
/api/v1/vendor/notifications/unread-count
Unread Count
▼
🔒 Auth Required
401
Success Response 200
{
"unread_count": 8
}
Notes
Quick badge count check
PATCH
/api/v1/vendor/notifications/{notification_id}/read
Mark Read
▼
🔒 Auth Required
401
Success Response 200
{
"message": "Notification marked as read."
}
Notes
Marks single notification as read
PATCH
/api/v1/vendor/notifications/read-all
Mark All 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.
GET
/api/v1/vendor/market/status
Status
▼
🔒 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
GET
/api/v1/vendor/market/items
List Items
▼
🔒 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
GET
/api/v1/vendor/market/cart
Get Cart
▼
🔒 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
POST
/api/v1/vendor/market/cart/items
Add to Cart
▼
🔒 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
PATCH
/api/v1/vendor/market/cart/items/{item_id}
Update Cart Item
▼
🔒 Auth Required
⚙ market.manage
401
Request Body
{
"quantity": 5
}
Success Response 200
{"message": "Cart updated.", "item": {...}, "cart": {...}}
Notes
Updates item quantity
DELETE
/api/v1/vendor/market/cart/items/{item_id}
Remove from Cart
▼
🔒 Auth Required
⚙ market.manage
401
Success Response 200
{"message": "Item removed from cart.", "cart": {...}}
Notes
Removes single item from cart
DELETE
/api/v1/vendor/market/cart
Clear Cart
▼
🔒 Auth Required
⚙ market.manage
401
Success Response 200
{
"message": "Cart cleared."
}
Notes
Removes all items from cart
GET
/api/v1/vendor/market/payment-methods
Payment Methods
▼
🔒 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
POST
/api/v1/vendor/market/checkout
Checkout Validate
▼
🔒 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
POST
/api/v1/vendor/market/orders
Place Order
▼
🔒 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
GET
/api/v1/vendor/market/orders
List Orders
▼
🔒 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
GET
/api/v1/vendor/market/orders/{order_id}
Order Detail
▼
🔒 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
POST
/api/v1/vendor/market/orders/{order_id}/cancel
Cancel Order
▼
🔒 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
POST
/api/v1/vendor/market/orders/{order_id}/report
Report Problem
▼
🔒 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
GET
/api/v1/vendor/market/orders/{order_id}/invoice
Download Invoice
▼
🔒 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.
GET
/api/v1/vendor/settings/store
Store Info
▼
🔒 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
PATCH
/api/v1/vendor/settings/store
Update Store
▼
🔒 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
POST
/api/v1/vendor/settings/request-name-change
Request Name Change
▼
🔒 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
GET
/api/v1/vendor/settings/owner
Owner Info
▼
🔒 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
PATCH
/api/v1/vendor/settings/owner
Update Owner
▼
🔒 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
POST
/api/v1/vendor/settings/request-email-change
Request Email Change
▼
🔒 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
POST
/api/v1/vendor/verify-email-change
Verify Email Change
▼
🌐 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
POST
/api/v1/vendor/settings/request-phone-change
Request Phone Change
▼
🔒 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
POST
/api/v1/vendor/settings/verify-phone-change
Verify Phone Change
▼
🔒 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
GET
/api/v1/vendor/settings/pickup
Pickup Address
▼
🔒 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
PATCH
/api/v1/vendor/settings/pickup
Update Pickup
▼
🔒 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
GET
/api/v1/vendor/settings/bank
Bank Details
▼
🔒 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
POST
/api/v1/vendor/settings/request-bank-update
Request Bank Update
▼
🔒 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
POST
/api/v1/vendor/settings/verify-bank-update
Verify Bank Update
▼
🔒 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
GET
/api/v1/vendor/settings/notifications
Notifications
▼
🔒 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
PATCH
/api/v1/vendor/settings/notifications
Update Notifications
▼
🔒 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
PATCH
/api/v1/vendor/settings/password
Change Password
▼
🔒 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
POST
/api/v1/vendor/settings/deactivate
Deactivate Store
▼
🔒 Auth Required
⚙ settings.manage
401
Success Response 200
{
"message": "Store hidden from marketplace."
}
Notes
Owner only. Vacation mode - hides store
POST
/api/v1/vendor/settings/activate
Activate 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
GET
/api/v1/vendor/settings/platform
Platform Config
▼
🔒 Auth Required
401
Success Response 200
{
"platform": {
"vat_rate": 0.15,
"minPrice": 50,
"payoutReleaseDays": 14,
"otpResendCooldown": 60
}
}
Notes
Platform-wide settings and limits
GET
/api/v1/vendor/banks
Banks Lookup
▼
🔒 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.
POST
/api/v1/vendor/device-tokens
Register
▼
🔒 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
DELETE
/api/v1/vendor/device-tokens
Unregister
▼
🔒 Auth Required
401
Request Body
{
"token": "fcm-device-token"
}
Success Response 200
{
"message": "Device token removed."
}
Notes
Remove device token on logout