Skip to main content

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 customItem field instead of bookId
  • Trade credit requires customerUserId to be provided
  • If inventoryId is 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 member
  • startDate: ISO8601 timestamp (optional) - Filter by date range
  • endDate: ISO8601 timestamp (optional) - Filter by date range
  • limit: 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 startDate and endDate for 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 range
  • endDate: 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 startDate or endDate not provided
  • Top books sorted by quantity sold (limit 10)
  • All monetary values in cents

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 customItem field
  • Receipts are formatted for 48-character thermal printers
  • Sale numbers follow format: STORE-TIMESTAMP-RANDOM (e.g., DOW-12345678-123)