https://perfume-pos-uae.val.run
All endpoints return JSON. Timestamps are in ISO 8601 format.
GET /api/products
Response (200 OK):
[ { "id": 1, "name": "Oud Al Amerat", "sku": "OUD001", "category": "Oud", "price": 450, "stock": 100 }, { "id": 2, "name": "Rose Oud", "sku": "OUD002", "category": "Oud", "price": 350, "stock": 100 } ]
cURL Example:
curl https://perfume-pos-uae.val.run/api/products
GET /api/products/{id}
Parameters:
id (path) - Product ID (integer)Response (200 OK):
{ "id": 1, "name": "Oud Al Amerat", "sku": "OUD001", "category": "Oud", "price": 450, "cost": 200, "stock": 100, "description": null }
Response (404 Not Found):
{ "error": "Product not found" }
cURL Example:
curl https://perfume-pos-uae.val.run/api/products/1
POST /api/sales Content-Type: application/json
Request Body:
{ "items": [ { "id": 1, "name": "Oud Al Amerat", "price": 450, "quantity": 2 }, { "id": 3, "name": "Musk Al Noor", "price": 280, "quantity": 1 } ], "paymentMethod": "cash" }
Response (200 OK):
{ "success": true, "transactionId": "TXN-1692984000000", "total": 1444.5, "subtotal": 1180, "vatAmount": 59, "itemCount": 2 }
Response (400 Bad Request):
{ "error": "No items in cart" }
Response (500 Internal Server Error):
{ "error": "Failed to process sale" }
cURL Example:
curl -X POST https://perfume-pos-uae.val.run/api/sales \ -H "Content-Type: application/json" \ -d '{ "items": [ { "id": 1, "name": "Oud Al Amerat", "price": 450, "quantity": 1 } ], "paymentMethod": "card" }'
Notes:
GET /api/reports/sales
Query Parameters:
startDate (optional) - Start date (YYYY-MM-DD format)endDate (optional) - End date (YYYY-MM-DD format)Response (200 OK):
{ "sales": [ { "id": 1, "transactionId": "TXN-1692984000000", "total": 1444.5, "subtotal": 1180, "vatAmount": 64.5, "paymentMethod": "cash", "createdAt": "2026-08-26T01:56:14.000Z" } ], "summary": { "transactionCount": 1, "totalRevenue": 1444.5, "totalVat": 64.5 } }
cURL Examples:
# All sales curl https://perfume-pos-uae.val.run/api/reports/sales # Sales for specific date curl "https://perfume-pos-uae.val.run/api/reports/sales?startDate=2026-08-26&endDate=2026-08-26" # Sales for date range curl "https://perfume-pos-uae.val.run/api/reports/sales?startDate=2026-08-01&endDate=2026-08-31"
GET /api/inventory
Response (200 OK):
{ "products": [ { "id": 1, "name": "Oud Al Amerat", "sku": "OUD001", "category": "Oud", "price": 450, "stock": 98 } ], "stats": { "totalProducts": 6, "lowStockItems": 0, "lowStockList": [] } }
cURL Example:
curl https://perfume-pos-uae.val.run/api/inventory
Notes:
lowStockList contains products below thresholdPOST /api/inventory/stock Content-Type: application/json
Request Body:
{ "productId": 1, "quantity": 50, "type": "adjustment", "reference": "REORDER-2026-08-26" }
Response (200 OK):
{ "success": true }
Response (500 Internal Server Error):
{ "error": "Failed to update stock" }
cURL Example:
# Add stock curl -X POST https://perfume-pos-uae.val.run/api/inventory/stock \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "quantity": 50, "type": "restock", "reference": "PO-2026-001" }' # Reduce stock for damage/shrinkage curl -X POST https://perfume-pos-uae.val.run/api/inventory/stock \ -H "Content-Type: application/json" \ -d '{ "productId": 1, "quantity": -5, "type": "adjustment", "reference": "DAMAGED-2026-08-26" }'
Notes:
GET /api/dashboard
Response (200 OK):
{ "todaysSales": 1444.5, "todaysTransactions": 1, "lowStockAlert": 0, "totalProducts": 6 }
cURL Example:
curl https://perfume-pos-uae.val.run/api/dashboard
{ "id": 1, "name": "Oud Al Amerat", "sku": "OUD001", "category": "Oud", "price": 450, "cost": 200, "stock": 100, "description": null, "barcode": null, "createdAt": "2026-08-26T01:56:14.000Z", "updatedAt": "2026-08-26T01:56:14.000Z" }
{ "id": 1, "transactionId": "TXN-1692984000000", "total": 1444.5, "subtotal": 1380, "vatAmount": 64.5, "paymentMethod": "cash", "status": "completed", "createdAt": "2026-08-26T01:56:14.000Z" }
{ "id": 1, "name": "Oud Al Amerat", "price": 450, "quantity": 2 }
All errors return appropriate HTTP status codes:
Sent when request data is invalid:
{ "error": "No items in cart" }
Sent when resource doesn't exist:
{ "error": "Product not found" }
Sent when server encounters an error:
{ "error": "Failed to process sale" }
Valid payment methods for sales:
"cash" - Cash payment"card" - Credit/Debit card"transfer" - Bank transferProducts are automatically categorized. Available categories:
Filter in frontend by clicking category buttons.
Sales reports support date filtering:
curl "https://perfume-pos-uae.val.run/api/reports/sales?startDate=2026-08-01&endDate=2026-08-31"
Search is performed client-side in the product catalog.
curl https://perfume-pos-uae.val.run/api/products | jq '.[] | select(.category=="Oud")'
curl https://perfume-pos-uae.val.run/api/inventory | jq '.lowStockList'
curl https://perfume-pos-uae.val.run/api/reports/sales | jq '.summary.totalRevenue'
curl https://perfume-pos-uae.val.run/api/reports/sales | jq '.sales[] | select(.paymentMethod=="cash")'
No rate limiting is currently implemented. Recommended:
Currently, no authentication is required. For future implementation:
/api/products returns 200/api/inventory after saleFor more details, see README.md and QUICK_START.md