Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/floriansalvi/HEIG-VD_Ocha-api/llms.txt

Use this file to discover all available pages before exploring further.

The create product endpoint adds a new product to the catalogue. Only administrators may call this endpoint — a valid JWT with admin privileges must be supplied in the Authorization header. Upon success, the server broadcasts a new_product WebSocket event to all connected clients so UIs can update in real time. The slug field must be unique; if a product with the same slug or name already exists, the request is rejected with a 409 conflict.

Endpoint

POST /api/v1/products
This endpoint requires an admin JWT. Requests without a valid token or without admin privileges are rejected with 401 or 403 respectively.

Request headers

Authorization
string
required
Bearer token for authentication, e.g. Bearer <JWT>.
Content-Type
string
required
Must be application/json.

Request body

slug
string
required
URL-friendly unique identifier for the product. Must be unique across all products (e.g. "matcha-latte").
name
string
required
Display name of the product. Must be unique across all products.
category
string
required
Category the product belongs to (e.g. "Hot drinks").
description
string
required
Full description of the product.
basePriceCHF
number
required
Base price in Swiss francs (CHF). Must be 0 or greater. The price a customer pays for a given size is basePriceCHF plus the relevant extra_chf surcharge.
image
string
required
URL of the product image. Must be a valid URL string.
isActive
boolean
default:"true"
Whether the product should be visible and available. Defaults to true if omitted.
size
string[]
default:"[\"S\", \"M\", \"L\"]"
Available sizes for this product. Each element must be one of "S", "M", or "L". Defaults to all three sizes if omitted.
extra_chf
object
default:"{\"S\": 0, \"M\": 2, \"L\": 3}"
Price surcharges in CHF added to basePriceCHF for each size.

Response

201 Created
message
string
A human-readable confirmation, e.g. "Product created".
product
object
The newly created product document, including all stored fields and MongoDB-generated _id, createdAt, and updatedAt timestamps.
After a successful creation, the server emits a new_product WebSocket event containing the full product object to all connected clients.

Error codes

StatusMeaning
400Missing required fields — slug, name, category, description, basePriceCHF, or image was not provided.
401Unauthorized — no token or an invalid token was supplied.
403Forbidden — the authenticated user does not have admin privileges.
409Conflict — a product with the same slug or name already exists.
422Unprocessable entity — the request body failed schema validation.
500Internal server error — an unexpected error occurred.

Example

Request:
curl https://api.example.com/api/v1/products \
  --request POST \
  --header "Authorization: Bearer <ADMIN_JWT>" \
  --header "Content-Type: application/json" \
  --data '{
    "slug": "matcha-latte",
    "name": "Matcha Latte",
    "category": "Hot drinks",
    "description": "Delicious matcha latte with a hint of sweetness.",
    "basePriceCHF": 5.00,
    "image": "https://res.cloudinary.com/example/image/upload/products/matcha-latte.jpg",
    "size": ["S", "M", "L"],
    "extra_chf": { "S": 0, "M": 2, "L": 3 }
  }'
201 response:
{
  "message": "Product created",
  "product": {
    "_id": "64f1c2e9a1b2c3d4e5f12345",
    "slug": "matcha-latte",
    "name": "Matcha Latte",
    "category": "Hot drinks",
    "description": "Delicious matcha latte with a hint of sweetness.",
    "basePriceCHF": 5.00,
    "isActive": true,
    "image": "https://res.cloudinary.com/example/image/upload/products/matcha-latte.jpg",
    "size": ["S", "M", "L"],
    "extra_chf": { "S": 0, "M": 2, "L": 3 },
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  }
}
409 response (name conflict):
{
  "message": "Name already in use"
}

Build docs developers (and LLMs) love