Happklaar API
string · binary · maxLength: 0 · required string · requiredstring · requiredstring[] · required string · uuid · requirednumber | null · min: 0 · max: 999999.999string | null · maxLength: 16string | null · enumstring | null · enumstring | null · date-timestring · requiredstring · requiredstring · requiredstring · requiredstring · requiredstring · requiredstring · requiredstring | nullstring | nullstring | null string[] · application/octet-stream · minItems: 1 · maxItems: 4 · required number | null · min: 0 · max: 999999.999string | null · maxLength: 16string | null · enumstring | null · enumstring | null · date-time
Pantry.AddScanSessionPhotoRequestData
Multipart request DTO for POST /v1/scan/sessions/{token}/photos.
Mirrors the MIME + size caps of {@see PantryPhotoScanRequestData} so the
two photo-upload surfaces share one trust-boundary contract. The 12 MB
cap leaves headroom for HEIC bursts beyond the per-photo cap on the
batch endpoint while still bounding worker memory per request.
photoPantry.BulkAddPantryItemsRequestData
Wire shape for POST /v1/pantry/items/bulk.
Carries 1..MAX_BULK_ITEMS rows; each row carries an ingredient_id plus
optional quantity / status / storage / expiry scalars (same shape as
{@see PantryItemRequestData}). Each row is validated against the same
enum + cap rules at 422 BEFORE the controller dispatches to the
repository.
Threat model:
- MAX_BULK_ITEMS bounds per-call memory + transaction footprint so a
hostile bulk-add cannot DoS the worker.
- Per-row enum validation rejects payloads that would otherwise hit
the storage-layer CHECK constraint and bubble up as a 500.
object[] · minItems: 1 · maxItems: 50 · required
Pantry.PantryIngredientSummaryData
idslugnamePantry.PantryItemRequestData
Add + partial-update request body for /v1/pantry/items[{id}].
`ingredient_id` is required on POST, omitted on PATCH (updates cannot move
an item to a different ingredient — that would invalidate the unique
(household_id, ingredient_id) constraint without an explicit delete + add).
Every other field is `Optional`: omitted means "leave unchanged on PATCH"
and "use the column default on POST".
Caps:
- MAX_QUANTITY_AMOUNT bounds the decimal so the worker cannot overflow
the decimal(10,3) column from a hostile payload.
- MAX_QUANTITY_UNIT_LENGTH matches the storage column width.
ingredient_idquantity_amountquantity_unitstatusEnum values:
ok
low
out
storage_locationEnum values:
cupboard
fridge
freezer
spices
expires_atPantry.PantryItemResponseData
idhousehold_idingredient_idstatusstorage_locationseed_sourceadded_atPantry.PantryIngredientSummaryData · required
quantity_amountquantity_unitexpires_atPantry.PantryPhotoScanRequestData
POST /v1/pantry/photo-scan — multipart request body DTO.
Carries 1–4 photos (jpeg / png / webp / heic) of pantry shelves. The
file caps + MIME allowlist are typed class constants per CLAUDE.md
"no magic numbers" rule. The Spatie\Data `rules()` override is what
gates malformed payloads at 422 BEFORE the controller resolves the
household or touches the service.
Threat model
- MAX_BYTES_PER_PHOTO bounds the per-request memory + Prism cost
ceiling so a hostile multipart submission can't DoS the worker.
- ALLOWED_MIME rejects `image/svg+xml` (the XSS-via-SVG vector) and
other non-photo content types.
- MAX_PHOTOS_PER_REQUEST bounds the per-call vision spend.
photosPantry.UpdatePantryItemRequestData
PATCH /v1/pantry/items/{id} request body.
Every field is Optional + nullable. Sending `null` for a nullable field
clears it; omitting the field entirely leaves it unchanged. `ingredient_id`
is absent — updates cannot move an item to a different ingredient (this
would invalidate the unique constraint without an explicit delete + add).
quantity_amountquantity_unitstatusEnum values:
ok
low
out
storage_locationEnum values:
cupboard
fridge
freezer
spices
expires_at