📡 API Documentation - Perfume POS UAE

Base URL

https://perfume-pos-uae.val.run

All endpoints return JSON. Timestamps are in ISO 8601 format.


🛍️ Product Endpoints

Get All Products

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 Product by ID

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

💳 Sales Endpoints

Create Sale Transaction

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:

  • VAT is automatically calculated at 5%
  • Inventory is reduced immediately
  • Transaction ID is generated automatically
  • All items must have valid IDs
  • Payment methods: "cash", "card", "transfer"

📊 Report Endpoints

Get Sales Report

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"

📦 Inventory Endpoints

Get Inventory Status

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:

  • Low stock threshold is 20 units
  • lowStockList contains products below threshold
  • Stock reflects all sales and adjustments

Update Stock

POST /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:

  • Use positive numbers to add stock
  • Use negative numbers to subtract stock
  • Type can be: "adjustment", "restock", "return", "damage", etc.
  • Reference is optional but recommended for audit trail

📈 Dashboard Endpoints

Get Dashboard Statistics

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

🔄 Data Models

Product Object

{ "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" }

Sale Object

{ "id": 1, "transactionId": "TXN-1692984000000", "total": 1444.5, "subtotal": 1380, "vatAmount": 64.5, "paymentMethod": "cash", "status": "completed", "createdAt": "2026-08-26T01:56:14.000Z" }

Cart Item Object (Client-side)

{ "id": 1, "name": "Oud Al Amerat", "price": 450, "quantity": 2 }

🔐 Error Handling

All errors return appropriate HTTP status codes:

400 Bad Request

Sent when request data is invalid:

{ "error": "No items in cart" }

404 Not Found

Sent when resource doesn't exist:

{ "error": "Product not found" }

500 Internal Server Error

Sent when server encounters an error:

{ "error": "Failed to process sale" }

📋 Payment Methods

Valid payment methods for sales:

  • "cash" - Cash payment
  • "card" - Credit/Debit card
  • "transfer" - Bank transfer

🔍 Filtering & Searching

By Category

Products are automatically categorized. Available categories:

  • Oud
  • Musk
  • Attar
  • Agarwood
  • Water

Filter in frontend by clicking category buttons.

By Date Range

Sales reports support date filtering:

curl "https://perfume-pos-uae.val.run/api/reports/sales?startDate=2026-08-01&endDate=2026-08-31"

By SKU/Name

Search is performed client-side in the product catalog.


📊 Common Queries

Get all Oud products

curl https://perfume-pos-uae.val.run/api/products | jq '.[] | select(.category=="Oud")'

Get low stock items

curl https://perfume-pos-uae.val.run/api/inventory | jq '.lowStockList'

Get total sales revenue

curl https://perfume-pos-uae.val.run/api/reports/sales | jq '.summary.totalRevenue'

Get all transactions by payment method

curl https://perfume-pos-uae.val.run/api/reports/sales | jq '.sales[] | select(.paymentMethod=="cash")'

⚠️ Rate Limiting

No rate limiting is currently implemented. Recommended:

  • Max 100 requests per minute per IP
  • Database queries are optimized for performance
  • Bulk operations may need pagination (future feature)

🔐 Authentication

Currently, no authentication is required. For future implementation:

  • PIN-based authentication for cashiers
  • API token authentication for integrations
  • Role-based access control

📝 Notes

  • All timestamps are UTC
  • Prices are in AED (Arab Emirates Dirham)
  • VAT is always 5%
  • Database auto-initializes on first request
  • Changes are persisted immediately
  • No transaction rollback on failure (use try-catch in client)

🆘 Troubleshooting

Products not loading

  1. Check /api/products returns 200
  2. Verify database initialized
  3. Check browser console for errors

Sales not processing

  1. Verify all items have valid IDs
  2. Check product stock is not 0
  3. Verify network request completed

Inventory not updating

  1. Check /api/inventory after sale
  2. Verify stock adjustment POST returns success
  3. Review inventory movement logs

Reports showing no data

  1. Verify sales have been processed
  2. Check date range parameters
  3. Try query without date filters

For more details, see README.md and QUICK_START.md