9.6 KiB
API Reference — Swish Auto Care GMS
Backend: Node.js + Express.js
Base URL (local):
http://localhost:5000/apiAll protected routes require:Authorization: Bearer <JWT_TOKEN>header.
Auth Routes — /api/auth
POST /api/auth/login
Public. Validates credentials, returns JWT.
Request:
{ "username": "admin", "password": "swish@2024" }
Response (200):
{ "token": "eyJhbG...", "user": { "id": 1, "username": "admin", "full_name": "Swish Admin" } }
Response (401): { "error": "Invalid credentials" }
GET /api/auth/me
Protected. Returns logged-in user info from JWT.
Response:
{ "id": 1, "username": "admin", "full_name": "Swish Admin" }
Dashboard Routes — /api/dashboard
GET /api/dashboard/today
Protected. Returns all today's summary widgets.
Response:
{
"active_jobs": 4,
"completed_jobs": 7,
"today_revenue": 28500,
"cash_balance": 14200,
"staff_present": 3,
"date": "24/03/2026"
}
Job Card Routes — /api/job-cards
GET /api/job-cards
Protected. List all job cards with optional filters.
Query params: ?status=active|done&date=YYYY-MM-DD®_no=GJ06AB1234&page=1&limit=20
Response:
{
"data": [
{
"id": 1,
"job_no": "SAC-20260324-001",
"job_type": "full",
"reg_no": "GJ06AB1234",
"car_name": "Swift",
"owner_name": "Rajesh Shah",
"mobile_no": "9876543210",
"service_type": "Full Detailing",
"assigned_staff_name": "Rajan Mehta",
"estimated_amount": 5000,
"final_amount": null,
"payment_mode": null,
"status": "active",
"job_date": "2026-03-24T10:30:00",
"closed_at": null
}
],
"total": 1,
"page": 1
}
POST /api/job-cards
Protected. Create a new job card.
Request (Full Job):
{
"job_type": "full",
"reg_no": "GJ06AB1234",
"car_name": "Swift",
"owner_name": "Rajesh Shah",
"mobile_no": "9876543210",
"service_type": "Full Detailing",
"assigned_staff_id": 1,
"estimated_amount": 5000,
"notes": "Check AC vent"
}
Request (Quick Wash):
{
"job_type": "wash",
"reg_no": "GJ06CD5678",
"car_name": "Creta",
"mobile_no": "",
"service_type": "Basic Wash",
"assigned_staff_id": 2,
"estimated_amount": 300
}
Response (201):
{ "id": 1, "job_no": "SAC-20260324-001", "message": "Job card created" }
GET /api/job-cards/:id
Protected. Get single job card with full details.
PUT /api/job-cards/:id
Protected. Update job card fields (only while status = 'active').
Request: Partial fields allowed.
{ "notes": "Updated notes", "estimated_amount": 5500 }
POST /api/job-cards/:id/close
Protected. Mark job as Done. Sets final_amount, payment_mode, closed_at.
Request:
{
"final_amount": 4800,
"payment_mode": "upi"
}
Response: { "message": "Job marked as done", "closed_at": "2026-03-24T15:45:00" }
Error if already done: { "error": "Job already closed" }
Staff Routes — /api/staff
GET /api/staff
Protected. List all staff.
Query: ?is_active=1|0
Response:
{
"data": [
{
"id": 1,
"staff_code": "SAC-STF-001",
"full_name": "Rajan Mehta",
"role": "Senior Detailer",
"mobile_no": "9898989898",
"date_of_joining": "2024-01-15",
"monthly_salary": 18000,
"is_active": 1
}
]
}
POST /api/staff
Protected. Add new staff member. Auto-generates staff_code.
Request:
{
"full_name": "Deepak Verma",
"role": "Washer",
"mobile_no": "9712345678",
"date_of_joining": "2026-03-01",
"monthly_salary": 13000
}
PUT /api/staff/:id
Protected. Update staff details.
PATCH /api/staff/:id/toggle
Protected. Toggle is_active status.
Attendance Routes — /api/attendance
GET /api/attendance
Protected. Get attendance for a date (default: today).
Query: ?date=YYYY-MM-DD
Response:
{
"date": "2026-03-24",
"records": [
{ "staff_id": 1, "staff_name": "Rajan Mehta", "status": "present" },
{ "staff_id": 2, "staff_name": "Suresh Kumar", "status": "absent" },
{ "staff_id": 3, "staff_name": "Vikram Patel", "status": null }
]
}
null status means not yet marked for today.
POST /api/attendance/bulk
Protected. Save attendance for multiple staff in one call.
Request:
{
"date": "2026-03-24",
"records": [
{ "staff_id": 1, "status": "present" },
{ "staff_id": 2, "status": "absent" },
{ "staff_id": 3, "status": "half" }
]
}
Response: { "message": "Attendance saved", "count": 3 }
Backend uses: INSERT INTO attendance ... ON DUPLICATE KEY UPDATE status = VALUES(status)
GET /api/attendance/summary/:staffId
Protected. Monthly attendance summary for one staff.
Query: ?month=3&year=2026
Response:
{
"staff_id": 1,
"month": "March 2026",
"present": 18,
"absent": 3,
"half": 2,
"records": [...]
}
Salary Routes — /api/salary
GET /api/salary
Protected. List all payments, filterable.
Query: ?staff_id=1&month=March 2026
POST /api/salary
Protected. Log a payment to a staff member.
Request:
{
"staff_id": 1,
"payment_date": "2026-03-24",
"payment_month": "March 2026",
"days_present": 22,
"calculated_salary": 15230.77,
"paid_amount": 15000,
"payment_type": "salary",
"payment_mode": "cash",
"notes": "March salary"
}
GET /api/salary/calculate/:staffId
Protected. Auto-calculate salary based on attendance.
Query: ?month=3&year=2026
Response:
{
"staff_id": 1,
"staff_name": "Rajan Mehta",
"monthly_salary": 18000,
"days_present": 22,
"calculated_salary": 15230.77
}
Formula: (18000 / 26) * 22 = 15230.77
Parts Routes — /api/parts
GET /api/parts
Protected. List all parts with stock info.
Query: ?category=Chemicals&low_stock=true
Response:
{
"data": [
{
"id": 1,
"part_code": "SAC-PRT-001",
"name": "Ceramic Coat 9H",
"category": "Chemicals",
"unit": "bottle",
"purchase_price": 1200,
"selling_price": 2500,
"stock_qty": 15,
"low_stock_alert": 5,
"is_low": false
}
]
}
POST /api/parts
Protected. Add new part. Auto-generates part_code.
PUT /api/parts/:id
Protected. Update part details (not stock — stock changes via sales).
PATCH /api/parts/:id/stock
Protected. Manual stock adjustment (restock).
Request: { "adjustment": 10, "reason": "New stock received" }
Parts Sales Routes — /api/parts-sales
GET /api/parts-sales
Protected. List all sales.
Query: ?date=YYYY-MM-DD&job_card_id=5
POST /api/parts-sales
Protected. Record a parts sale. Auto-deducts stock.
Request:
{
"part_id": 1,
"job_card_id": null,
"quantity": 2,
"unit_price": 2500,
"total_amount": 5000,
"customer_name": "Ankit Patel",
"payment_mode": "upi"
}
Backend must:
- Verify stock_qty >= quantity. If not:
{ "error": "Insufficient stock" } - Insert into parts_sales
UPDATE parts SET stock_qty = stock_qty - ? WHERE id = ?- Return sale record
Cash Ledger Routes — /api/cash-ledger
GET /api/cash-ledger
Protected. List entries with optional date filter.
Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD&type=in|out
POST /api/cash-ledger
Protected. Add cash in or out entry.
Request:
{
"entry_type": "out",
"amount": 500,
"category": "Utilities",
"description": "Electricity bill payment"
}
Accounts Routes — /api/accounts
GET /api/accounts/summary
Protected. Consolidated financial summary.
Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD (default: today)
Response:
{
"period": { "from": "2026-03-24", "to": "2026-03-24" },
"income": {
"job_revenue": 28500,
"parts_revenue": 7500,
"cash_in_other": 2000,
"total": 38000
},
"expense": {
"staff_payments": 15000,
"cash_out_other": 800,
"total": 15800
},
"net_balance": 22200
}
GET /api/accounts/transactions
Protected. All transactions in a date range (for drill-down).
Returns unified list of all financial movements with source type tag.
Reports Routes — /api/reports
GET /api/reports/daily
Protected. Get daily report data (JSON, for on-screen preview).
Query: ?date=YYYY-MM-DD (default: today)
GET /api/reports/daily/download
Protected. Download daily report as .xlsx file.
Query: ?date=YYYY-MM-DD
Response: Binary .xlsx stream with headers:
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="SwishGMS_DailyReport_24-03-2026.xlsx"
Export Routes — /api/exports
GET /api/exports/job-cards
Protected. Export all job cards as .xlsx.
Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD
GET /api/exports/staff-attendance
Protected. Export staff + attendance as .xlsx.
Query: ?month=3&year=2026
GET /api/exports/parts-inventory
Protected. Export parts inventory as .xlsx.
GET /api/exports/accounts
Protected. Export accounts/transactions as .xlsx.
Query: ?from=YYYY-MM-DD&to=YYYY-MM-DD
Error Response Format (Consistent Across All Routes)
{ "error": "Human-readable error message", "code": "OPTIONAL_ERROR_CODE" }
HTTP status codes used:
200OK201Created400Bad Request (validation errors)401Unauthorized (missing/invalid JWT)403Forbidden404Not Found409Conflict (e.g. duplicate attendance)500Internal Server Error