REST API
Transactions

Transactions (POS)

All routes under /api/v1/pos require authentication.

Complete a Sale

POST /pos/sale

Complete a sale with multiple line items. Automatically decrements stock.

Auth: Required

Request Body:

{
  "lines": [
    { "product_id": "uuid", "qty": 2 },
    { "product_id": "uuid", "qty": 1 }
  ],
  "payment_method": "Cash",
  "payment_reference": "REF123",
  "discount_pct": 5.0,
  "customer_name": "John Doe",
  "customer_phone": "+255712345678",
  "customer_id": "uuid",
  "till_number": "TILL-001",
  "notes": "Birthday discount applied"
}

Payment Methods: Cash, M-Pesa, Tigo Pesa, Bank, Credit

Response (201): Transaction object.

Side Effects:

  • Decrements stock for each line item
  • Fires transaction.created event (updates customer stats, auto-creates credit tab if Credit payment)

GET /pos/transactions

List transactions with filters and pagination.

Auth: Required

Query Parameters:

ParameterTypeDescription
statusstringcompleted, refunded, void
methodstringCash, M-Pesa, etc.
searchstringSearch by reference
customer_iduuidFilter by customer
date_fromstringISO date (YYYY-MM-DD)
date_tostringISO date (YYYY-MM-DD)
pageintPage number
page_sizeintItems per page

Response: Paginated transaction list.


GET /pos/transactions/:id

Get a single transaction with line items.

Auth: Required

Response: Transaction object with lines array:

{
  "id": "uuid",
  "status": "completed",
  "payment_method": "Cash",
  "subtotal": 4500,
  "tax": 810,
  "discount": 225,
  "total": 5085,
  "lines": [
    {
      "product_id": "uuid",
      "product_name": "Pepsi 500ml",
      "qty": 2,
      "unit_price": 1500,
      "line_total": 3000
    }
  ],
  "created_at": "2024-01-15T10:30:00Z"
}

POST /pos/transactions/:id/refund

Refund a completed transaction.

Auth: Required

Request Body:

{
  "reason": "Customer returned damaged product"
}

Response: Transaction with status: "refunded".

Side Effects:

  • Fires transaction.refunded event (restores stock, settles credit tab if applicable)

POST /pos/transactions/:id/void

Void a transaction.

Auth: Required

Request Body:

{
  "reason": "Incorrect amount entered"
}

Response: Transaction with status: "void".

Side Effects:

  • Fires transaction.voided event

GET /pos/summary

Daily sales summary KPIs.

Auth: Required

Query Parameters:

ParameterTypeDefault
date_fromstringStart of today
date_tostringEnd of today

Response (200):

{
  "success": true,
  "data": {
    "total_sales": 525000,
    "transaction_count": 45,
    "average_ticket": 11667,
    "items_sold": 120,
    "cash_total": 300000,
    "mpeca_total": 200000,
    "credit_total": 25000,
    "refund_count": 2,
    "refund_total": 5000
  }
}

GET /pos/summary/hourly

Hourly sales breakdown for a specific date.

Auth: Required

Query: date (YYYY-MM-DD, default: today)

Response: Array of hourly data:

{
  "success": true,
  "data": [
    { "hour": 8, "sales": 15000, "count": 3 },
    { "hour": 9, "sales": 45000, "count": 8 },
    ...
  ]
}