Market API
Complete e-commerce REST API for QA practice — grocery shopping simulation with products, basket, and orders.
No login required to read this documentation. Register at /profile.html to get your personal API key and start testing.
Quick Start
Description
The Market application is a grocery e-commerce API that simulates a real online supermarket. It is one of several practice applications in the qacloud platform, designed specifically for QA engineers to learn and practice API testing.
Each user gets their own isolated data environment: a personal product catalog pre-seeded with grocery items, an empty basket, and an empty order history. Your data is never mixed with other users' data. This makes it safe to run destructive tests (delete, reset) without affecting other testers.
What makes it interesting for QA?
- Stock validation — adding more items than available stock returns an error
- Price snapshot — once an order is placed,
price_at_purchaseis fixed even if the product price changes later - Basket accumulation — adding the same product twice merges quantities, not duplicates
- Order number format —
O+ 5 random digits; should be validated for format consistency - Data isolation — using another user's API key should return empty data, not an error
- Filter API — multi-value category filter, boolean weighted filter, sort order
- Reset endpoint — deterministic test setup: always start from a known product catalog state
Product Categories (default seed data)
| Category | Example products | Typical temperature zone |
|---|---|---|
| Dairy | Milk, Yogurt, Cheese, Butter | Chilled |
| Bakery | Bread, Croissants, Rolls | Dry / Room Temperature |
| Meat | Chicken, Beef, Pork | Chilled / Frozen |
| Produce | Apples, Tomatoes, Carrots | Chilled / Room Temperature |
| Beverages | Orange Juice, Sparkling Water | Chilled / Dry |
| Frozen | Ice Cream, Frozen Pizza | Frozen |
| Deli | Ham, Salami, Hummus | Chilled |
| Pantry | Pasta, Rice, Canned Beans | Dry |
UI Overview
The Market application ships with a built-in browser UI accessible at /market/<username> after login. It is divided into three tabs — Products, Basket, and Orders — with a live stats dashboard at the top of every screen.
Stats Dashboard
A persistent header bar displays four live counters, updated whenever you switch tabs or click Refresh:
| Counter | What it shows | When it updates |
|---|---|---|
| Products | Total number of products in your catalog | After creating or deleting a product |
| Basket Items | Total quantity of all items currently in basket | After adding, removing, or placing an order |
| Orders | Total number of orders placed | After placing or deleting an order |
| Total Value | Sum of (price × stock) across the entire product catalog | After any product price or stock change |
The Total Value stat (e.g. $9391.80) reflects the monetary worth of your full inventory — not the basket total or order total. It changes when product prices or stock levels change.
Products Tab
The default view after login. Shows your full grocery catalog as a scrollable card grid with filtering and sorting controls.
- Left sidebar — category filter links: All Products, Dairy, Produce, Beverages, Meat, Bakery, Pantry, Frozen, Deli, and any custom categories you create. Clicking a category instantly filters the grid.
- Product cards — each card shows a category-specific emoji icon, product name, a color-coded category badge, price (highlighted), temperature zone, and current stock level.
- Sort By dropdown — sort the grid alphabetically A→Z or Z→A by product name.
- Category dropdown — secondary filter showing "All Products" or a specific category; works in combination with the sidebar.
- Add a Product button (top right) — opens a form to create a new custom product directly in the UI.
Basket Tab
Shows all items currently in your shopping basket with full quantity management and a live order summary.
- Item rows — each row shows product name, unit price (e.g.
$6.50 each), available stock (e.g.Stock: 40 available), a quantity stepper (−and+buttons), and a REMOVE button. - Subtotal — per-item subtotal shown in accent color below the quantity stepper (e.g.
Subtotal: $19.50for qty 3 × $6.50). - REFRESH — re-fetches basket state from the API without reloading the page.
- CLEAR ALL — removes every item from the basket in a single action.
- Order Summary panel (right side) — shows total item count, computed order total, and the green PLACE ORDER button.
- Empty state — when the basket has no items (or after a successful order), shows a cart icon with the message: "Your basket is empty. Start marketing!"
Orders Tab
Lists all placed orders, newest first. Each order card is expandable to show line items and a status editor.
- Order number — format
O+ 5 digits (e.g.O40699), shown as the card heading. - Timestamp — date and time the order was placed (e.g.
4/14/2026, 7:11:41 PM). - Total — order total displayed in accent color (e.g.
$19.50). - Status badge — color-coded pill: yellow for
PENDING, green forDELIVERED, red forCANCELLED. - Items section — expanded view lists each item as
Product Name × quantity — $subtotal(e.g.100% Florida Orange Juice × 3 — $19.50). - Status dropdown — change order status directly in the UI; triggers a
PUT /api/orders/:idcall immediately. - DELETE ORDER button — permanently removes the order record; decrements the Orders stat counter.
Top Navigation Bar
Persistent across all three tabs:
- Reset — calls
POST /api/reset; wipes and re-seeds the product catalog to the default state. - Username badge — displays the currently logged-in user.
- API Docs — links to the Swagger UI at
/market/docs. - Data Viewer — links to the raw data viewer at
/market-viewer.html. - Profile — links to the user account page.
Products Flow
All product endpoints require the Authorization: qac_live_... header. Products are scoped to the authenticated user only.
POST /api/reset to restore the catalog to the default state (deletes all custom products first).GET /api/groceries/filter?category=Dairy,Meat&sort=desc
product_name, price, category. Optional: stock, temperature_zone, weighted, details.DELETE /api/groceries/:id
Basket Flow
DELETE /api/basket/clear
Order Flow
Once placed, stock is decremented immediately. There is no automatic stock restoration on order cancel or delete — this is intentional for testing stock-related scenarios.
order_items. Total is computed server-side. Basket is cleared automatically. Stock is decremented per item.GET /api/orders/:id
pending · processing · shipped · delivered · cancelled.Product Endpoints
All require Authorization: qac_live_... header.
Query Params
sort=asc(default) orsort=desc— sort by name
Success Response — 200
{ "products": [ { "id": "...", "product_name": "Organic Milk", "category": "Dairy", "price": 2.49, "stock": 100, ... } ] }
Query Params
category=Dairyorcategory=Dairy,Meattemperature_zone=Chilled— one of:Dry,Frozen,Chilled,Room Temperatureweighted=trueorweighted=falsesort=asc(default) orsort=desc
Request Body
{
"product_name": "Cheddar Cheese", // required
"price": 4.99, // required, positive number
"category": "Dairy", // required
"temperature_zone": "Chilled", // optional
"weighted": false, // optional, default false
"stock": 50, // optional, default 0
"details": { // optional JSONB
"brand": "Vintage Gold",
"weight": "400g"
}
}
Success — 201
{ "id": "...", "product_name": "Cheddar Cheese", ... }
Errors
- 400 — Missing required fields or invalid temperature_zone
// Only include fields you want to change
{ "price": 5.49, "stock": 30 }
- 404 — Product not found or belongs to different user
Deleting a product automatically removes it from all basket entries (CASCADE). Existing order items are not affected (they store a snapshot).
- 404 — Product not found
Deletes all existing products and re-seeds the default grocery catalog. Basket and orders are not affected. Useful in test setup/teardown scripts.
// No body required
POST /api/reset
Authorization: qac_live_...
→ 200 { "message": "Data reset successfully", "count": 28 }
Basket Endpoints
{ "product_id": "uuid", "quantity": 2 }
If the product is already in the basket, quantities are merged (existing + new). Combined quantity must not exceed stock.
- 400 — quantity < 1
- 400 — Not enough stock (includes current basket qty)
- 404 — Product not found
{ "product_id": "uuid", "quantity": 5 }
Sets the quantity to the specified value (not additive). Must be ≥ 1.
Removes all items. Returns 200 even if basket was already empty.
Removes the product row from the basket. Quantity removed entirely (not decremented).
Order Endpoints
{ "notes": "Leave at door" } // body is optional
- Basket must not be empty
- Items with deleted products are auto-cleaned before order creation
- Basket is cleared after successful order
- Stock is decremented per item
{ "status": "shipped" }
// Valid statuses: pending · processing · shipped · delivered · cancelled
Test Cases
PRODUCTS
{ "products": [...] }, array length ≥ 1product_name, price, category, temperature_zone, weighted, stock, detailstemperature_zone="Warm"GET /api/groceries/filter?category=Dairy,MeatAuthorization: invalid-keyPUT /api/groceries/:id { "price": 9.99 }BASKET
"Not enough stock. Available: 5""Not enough stock. Available: 5, Already in basket: 3""quantity must be at least 1"ORDERS
order_number matches /^O\d{5}$/, basket is empty after"Basket is empty"price_at_purchase unchanged (snapshot){ "status": "returned" }order_number matches regex /^O\d{5}$/UI Test Cases
These test cases target the browser UI at /market/<username>. Use a real browser — Chrome, Firefox, or Safari.
Stats Dashboard
Products Tab — UI
Basket Tab — UI
Orders Tab — UI
O40699)100% Florida Orange Juice × 3 — $19.50QA Tasks
Hands-on tasks for QA engineers — both manual and automation. Use these to explore the API, find edge cases, and build automation skills.
Register at /profile.html, grab your api_key, and keep it ready. Run POST /api/reset to get a clean, known starting state before each task.
Complete the end-to-end shopping flow manually using a REST client (Postman, Insomnia, or curl). Document each step and verify responses.
- Register a new account and capture the
api_key - List all products and find 3 different categories
- Add 2 different products to the basket
- Verify the basket GET shows exactly those 2 items
- Place the order and record the
order_number - Verify the basket is empty after the order
- Verify the product stock decreased by ordered quantity
- Update the order status to
delivered
Explore all the ways stock validation can be violated. Try to find edge cases the system handles (or doesn't handle).
- Find a product with stock = 0 and try to add it to the basket
- Set a product's stock to 5, add 3 to basket, then try to add 3 more
- Add the maximum stock amount to basket — verify it allows it
- Add stock + 1 — verify the error message is helpful
- Place an order, then try to add the same product quantity that should now be depleted
- Create a product with stock=0 and verify it appears but cannot be added to basket
Verify that the API correctly isolates data between users. Attempt cross-user data access and confirm it is properly blocked.
- Register two accounts — capture both API keys
- Create products with User A's key, verify User B cannot see them
- Use User B's key to GET User A's product ID directly — expect 404
- Try to update/delete User A's product using User B's key — expect 404
- Add items to User A's basket — verify User B's basket is empty
- Place an order as User A — verify it doesn't appear in User B's orders
Thoroughly test the product filter endpoint with all parameter combinations, ensuring accurate filtering and sorting behavior.
- Filter by each temperature_zone value and verify only correct products returned
- Filter by invalid temperature_zone — expect 400
- Filter by
weighted=true— all returned products must have weighted=true - Combine category + temperature_zone filters
- Filter by multiple categories:
category=Dairy,Meat - Test
sort=asc— verify alphabetical order (A→Z) - Test
sort=desc— verify reverse alphabetical order (Z→A) - Filter by a category that doesn't exist — expect empty array, not error
Write an automated test script that covers the full positive flow: register → get products → add to basket → place order → verify order.
- Auto-generate unique test credentials (e.g., timestamp-based username)
- Register and extract
api_keyfrom response - GET products and select the first one with stock > 0
- Add 1 unit to basket and verify 201 response
- GET basket and assert item count = 1
- POST /api/orders and assert
order_numbermatches/^O\d{5}$/ - Assert
total_amountequals product price × quantity - Assert basket is empty after order
Build a complete test suite covering Create, Read, Update, Delete for the products API with both positive and negative cases.
- Setup: register and reset data before suite runs
- Test POST with only required fields → expect 201
- Test POST with all fields including
detailsJSONB → expect 201 - Test POST missing
product_name→ expect 400 - Test POST with invalid
temperature_zone→ expect 400 - Test PUT partial update: only change price → other fields unchanged
- Test DELETE → product disappears from GET all
- Test DELETE nonexistent ID → expect 404
- Test GET with invalid API key → expect 401
- Teardown: POST /api/reset to restore catalog
Write automation that targets basket edge-cases, particularly around quantity merging, stock limits, and concurrent additions.
- Add product A (qty=2), add same product again (qty=3) → basket qty=5
- Add product with qty=0 → expect 400
- Add product with qty=-1 → expect 400
- Add product with qty exceeding stock → expect 400 with helpful message
- Add product with exact stock amount → expect 201
- Add product with stock+1 after item is in basket → expect 400
- Clear basket → GET basket → verify empty array
- Remove specific product → verify only that product is removed
Verify the price snapshot behavior — a placed order's items must retain the price at the time of purchase, even if the product is later modified or deleted.
- Create a product with price=10.00
- Add it to basket and place order — record order item's
price_at_purchase - Update product price to 99.99
- Fetch the order — verify
price_at_purchaseis still 10.00 - Delete the product entirely
- Fetch the order — verify order items still show product data
- Automate this as a regression test
Probe the authentication system for common vulnerabilities and verify security controls are in place.
- Attempt to register with SQL injection in username:
admin'; DROP TABLE users;-- - Attempt XSS in username field:
<script>alert(1)</script> - Try brute-force: 10 incorrect login attempts — verify system behaviour
- Attempt to access
GET /api/profilewithout any auth → expect 401 - Modify the JWT token payload (decode, change userId, re-encode) → expect 401
- Use an expired JWT if possible → expect 401
- Try registering with an empty string password
""
Build a complete, shareable Postman collection for the Market API with environment variables, pre-request scripts, and test scripts.
- Create environment variables:
base_url,api_key,product_id,order_id - Add register request with test script to extract and save
api_key - Add a pre-request script that calls
POST /api/resetbefore product tests - Add test assertions for status codes on every request
- Add test assertions for response body shape (required fields present)
- Chain requests: create product → save ID → use in basket → place order → save order ID
- Add a negative test folder with expected error scenarios
- Export collection and document how to import and run it