POS API
The POS API enables in-store sales transactions, barcode lookups, receipt generation, and sales reporting.
Authentication
All POS endpoints require authentication with a user who has staff role at the store.
Endpoints
POST /api/pos/sales
Create a new in-store sale.
Authentication: Required (Staff role)
Request Body:
{
"storeId": "string",
"customerUserId": "string (optional)",
"items": [
{
"bookId": "string (optional)",
"customItem": {
"title": "string",
"authors": ["string"] (optional)
} (optional - either bookId OR customItem required),
"inventoryId": "string (optional)",
"quantity": "number",
"unitPriceCents": "number",
"isUsed": "boolean"
}
],
"paymentMethod": "cash | card | trade_credit | mixed",
"tradeCreditAppliedCents": "number (optional, default 0)"
}
Response (201 Created):
{
"id": "uuid",
"saleNumber": "string",
"storeId": "uuid",
"staffUserId": "uuid",
"customerUserId": "uuid | null",
"items": [
{
"id": "uuid",
"saleId": "uuid",
"bookId": "uuid",
"inventoryId": "uuid | null",
"quantity": "number",
"unitPrice": "number",
"isUsed": "boolean",
"book": {
"id": "uuid",
"isbn13": "string | null",
"isbn10": "string | null",
"title": "string",
"authors": ["string"]
}
}
],
"subtotalCents": "number",
"taxCents": "number",
"totalCents": "number",
"paymentMethod": "string",
"tradeCreditAppliedCents": "number",
"createdAt": "ISO8601 timestamp",
"customer": {
"id": "uuid",
"displayName": "string | null",
"email": "string | null"
} (optional)
}
Example:
curl -X POST https://api.bookwish.app/api/pos/sales \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"storeId": "store-uuid",
"items": [{
"bookId": "book-uuid",
"inventoryId": "inventory-uuid",
"quantity": 1,
"unitPriceCents": 1599,
"isUsed": false
}],
"paymentMethod": "card"
}'
Notes:
- Tax rate is automatically fetched from store configuration
- Custom items (non-inventory) can be added with
customItemfield instead ofbookId - Trade credit requires
customerUserIdto be provided - If
inventoryIdis provided, inventory quantity will be decremented - All monetary values are in cents (e.g., $15.99 = 1599)
GET /api/pos/lookup/:barcode
Look up book information by barcode (ISBN-10 or ISBN-13).
Authentication: Required (Staff role)
Path Parameters:
barcode: string - ISBN-10, ISBN-13, or UPC barcode
Query Parameters:
storeId: string (optional) - Store ID for inventory check
Response (200 OK):
{
"book": {
"id": "uuid",
"isbn13": "string | null",
"isbn10": "string | null",
"title": "string",
"authors": ["string"]
},
"inventory": {
"id": "uuid",
"quantity": "number",
"priceCents": "number",
"condition": "string",
"isUsed": "boolean"
} | null
}
Example:
curl https://api.bookwish.app/api/pos/lookup/9780451524935 \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"book": {
"id": "book-uuid",
"isbn13": "9780451524935",
"isbn10": "0451524934",
"title": "1984",
"authors": ["George Orwell"]
},
"inventory": {
"id": "inventory-uuid",
"quantity": 3,
"priceCents": 1299,
"condition": "new",
"isUsed": false
}
}
Notes:
- Returns 404 if book not found by ISBN
- Inventory is null if book exists but not in stock at the specified store
- Only returns in-stock items (quantity > 0)
GET /api/pos/sales
List sales for a store.
Authentication: Required (Staff role)
Query Parameters:
storeId: string (optional) - Store ID (defaults to staff user's store)staffUserId: string (optional) - Filter by staff memberstartDate: ISO8601 timestamp (optional) - Filter by date rangeendDate: ISO8601 timestamp (optional) - Filter by date rangelimit: number (optional, default 50) - Maximum number of results
Response (200 OK):
[
{
"id": "uuid",
"saleNumber": "string",
"storeId": "uuid",
"staffUserId": "uuid",
"customerUserId": "uuid | null",
"items": [...],
"subtotalCents": "number",
"taxCents": "number",
"totalCents": "number",
"paymentMethod": "string",
"tradeCreditAppliedCents": "number",
"createdAt": "ISO8601 timestamp",
"customer": {
"id": "uuid",
"displayName": "string | null",
"email": "string | null"
} (optional)
}
]
Example:
curl "https://api.bookwish.app/api/pos/sales?storeId=store-uuid&limit=10" \
-H "Authorization: Bearer YOUR_TOKEN"
Notes:
- Results are ordered by creation date (newest first)
- Maximum limit is 50 sales per request
- Use
startDateandendDatefor date range filtering
GET /api/pos/sales/:id
Get details of a specific sale.
Authentication: Required (Staff role)
Path Parameters:
id: string - Sale ID
Response (200 OK):
{
"id": "uuid",
"saleNumber": "string",
"storeId": "uuid",
"staffUserId": "uuid",
"customerUserId": "uuid | null",
"items": [
{
"id": "uuid",
"saleId": "uuid",
"bookId": "uuid",
"inventoryId": "uuid | null",
"quantity": "number",
"unitPrice": "number",
"isUsed": "boolean",
"book": {
"id": "uuid",
"isbn13": "string | null",
"isbn10": "string | null",
"title": "string",
"authors": ["string"]
}
}
],
"subtotalCents": "number",
"taxCents": "number",
"totalCents": "number",
"paymentMethod": "string",
"tradeCreditAppliedCents": "number",
"createdAt": "ISO8601 timestamp",
"customer": {
"id": "uuid",
"displayName": "string | null",
"email": "string | null"
} (optional)
}
Example:
curl https://api.bookwish.app/api/pos/sales/sale-uuid \
-H "Authorization: Bearer YOUR_TOKEN"
Notes:
- Returns 404 if sale not found
- Includes complete item details with book information
GET /api/pos/sales/:id/receipt
Generate and retrieve a receipt for a sale.
Authentication: Required (Staff role)
Path Parameters:
id: string - Sale ID
Response (200 OK):
- Content-Type:
text/plain; charset=utf-8 - Body: Formatted 48-character width receipt text
Example:
curl https://api.bookwish.app/api/pos/sales/sale-uuid/receipt \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
DOWNTOWN BOOKS
123 Main St, Columbus, OH 43215
(614) 555-0100
================================================
Sale #: DOW-12345678-123
Date: Dec 10, 2024, 3:45 PM
Customer: John Doe
Email: john@example.com
------------------------------------------------
1984 (Used)
by George Orwell
1 x $12.99 $12.99
The Great Gatsby
by F. Scott Fitzgerald
2 x $15.99 $31.98
------------------------------------------------
Subtotal: $44.97
Tax: $3.60
Trade Credit: -$5.00
TOTAL: $43.57
Payment Method: Card
================================================
Thank you for your purchase!
Please visit us again
Notes:
- Receipt formatted for 48-character thermal printers
- Returns 404 if sale not found
- Receipt includes store info, items, totals, and payment method
GET /api/pos/reports/summary
Get sales summary report for a store.
Authentication: Required (Staff role)
Query Parameters:
storeId: string (optional) - Store ID (defaults to staff user's store)startDate: ISO8601 timestamp (required) - Start of date rangeendDate: ISO8601 timestamp (required) - End of date range
Response (200 OK):
{
"totalSales": "number",
"totalRevenueCents": "number",
"averageSaleCents": "number",
"totalItemsSold": "number",
"salesByPaymentMethod": [
{
"paymentMethod": "string",
"count": "number",
"totalCents": "number"
}
],
"topBooks": [
{
"bookId": "uuid",
"title": "string",
"quantitySold": "number",
"revenueCents": "number"
}
]
}
Example:
curl "https://api.bookwish.app/api/pos/reports/summary?storeId=store-uuid&startDate=2024-12-01T00:00:00Z&endDate=2024-12-31T23:59:59Z" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"totalSales": 156,
"totalRevenueCents": 1234567,
"averageSaleCents": 7914,
"totalItemsSold": 423,
"salesByPaymentMethod": [
{
"paymentMethod": "card",
"count": 98,
"totalCents": 823456
},
{
"paymentMethod": "cash",
"count": 45,
"totalCents": 356789
},
{
"paymentMethod": "trade_credit",
"count": 13,
"totalCents": 54322
}
],
"topBooks": [
{
"bookId": "book-uuid-1",
"title": "The Great Gatsby",
"quantitySold": 15,
"revenueCents": 23985
},
{
"bookId": "book-uuid-2",
"title": "1984",
"quantitySold": 12,
"revenueCents": 15588
}
]
}
Notes:
- Returns 400 if
startDateorendDatenot provided - Top books sorted by quantity sold (limit 10)
- All monetary values in cents
Related Documentation
Notes
- All endpoints require staff authentication
- All monetary values are in cents (e.g., $15.99 = 1599)
- Tax rate is configured per store in store settings
- Custom items (non-inventory) can be added with
customItemfield - Receipts are formatted for 48-character thermal printers
- Sale numbers follow format:
STORE-TIMESTAMP-RANDOM(e.g., DOW-12345678-123)