Skip to content

API: Products

Endpoints for the product catalog.

Base path

/products

Endpoints

GET /products

List all products in the catalog with their photos and artisans.

Request:

No parameters.

Response:

StatusDescriptionBody
200Product list{ products: [...] }

Response body — products[]:

FieldTypeDescription
idnumberProduct ID
namestringProduct name
descriptionstring | nullOptional description
pricenumberPrice in BRL (e.g. 29.90)
photosobject[]List of photos: [{ id, url }]
artisansobject[]List of artisans: [{ id, name }]

Business rules:

  • Returns all non-deleted products.
  • Each product includes all its non-deleted photos and associated artisans.
  • Returns an empty array when no products exist.

POST /products

Register a new product in the catalog. The backend generates R2 object keys and presigned URLs for each photo. The client uploads files directly to R2 using the returned presigned URLs.

Request:

LocationFieldTypeRequiredDescription
bodynamestringyesProduct name (max 255 chars)
bodydescriptionstringnoOptional product description
bodypricenumberyesPrice in BRL, greater than zero
bodyartisanIdsnumber[]yesIDs of the artisans who make this product (min 1)
bodyphotosobject[]yesArray of photo objects (min 1): [{ mimeType }]
bodyphotos[].mimeTypestringyesimage/png or image/jpeg

Response:

StatusDescriptionBody
201Product created{ id, name, description, price, artisans: [{ id, name }], photos: [{ id, url, presignedUrl }] }
400Validation error{ message: string }
422One or more artisanIds not found{ message: string }

Business rules:

  • price must be greater than zero.
  • At least one photo is required.
  • At least one artisan ID is required.
  • All provided artisanIds must exist and not be soft-deleted; returns 422 if any are invalid.
  • photos[].url is the full public URL (R2_PUBLIC_URL + object_key).
  • photos[].presignedUrl is a temporary presigned PUT URL for direct R2 upload.
  • Photo object keys follow the pattern products/{product_id}/{uuid}.{ext}.