Products
Concepts, endpoints, and media model for managing your catalog.
A product in Baseplate is a sellable thing in your store. Every product has one or more variants — even a "single" product has a hidden default variant under the hood, so pricing and stock are always carried on the variant, never on the product itself.
Mental model
product ← title, description, brand, SEO
├── variants[] ← sku, price_cents, stock, fulfillment_mode
│ ├── option_values[] ← e.g. size=M, color=blue
│ └── shipping_box ← physical box for freight calc
├── product_images[] ← gallery items (images and videos)
│ └── image_variants[] ← srcset sizes (thumbnail/small/medium/large)
├── highlight_video ← one short video → bottom-left widget on PDP
├── product_specs[] ← long-form specs (key/value, grouped)
└── reviews[]A few terms that matter:
- product_type —
"single"(one configuration) or"variable"(multiple variants with options). Drives the admin UI. - fulfillment_mode on the variant —
stocked,on_demand, orstocked_or_on_demand. Decides whether availability is computed from inventory or always treated as "in stock". - media_type on a gallery row —
"image"(default) or"video". Image rows go through the resize pipeline; video rows skip it and point straight at the URL.
Endpoints
All endpoints below live under /stores/{store_id}/products.
| Method | Path | Purpose |
|---|---|---|
GET | /products | List, paginated. ?limit=, ?offset=, ?search=. |
POST | /products | Create. Returns the new id + slug. |
GET | /products/{id} | Single product with variants and stock. |
PATCH | /products/{id} | Partial update. Any unset field is left alone. |
DELETE | /products/{id} | Hard delete. Cascades to variants and gallery. |
GET | /products/{id}/images | Full gallery with variants (sizes). |
POST | /products/{id}/images | Upload an image (multipart). |
POST | /products/{id}/images/associate | Attach an existing library file. |
POST | /products/{id}/videos | Attach a video by URL (next section). |
PATCH | /products/{id}/images/{img_id} | Reorder, set primary, swap alt text. |
DELETE | /products/{id}/images/{img_id} | Remove a gallery item. |
Create a product
curl -X POST "https://bp.mobicms.com.br/stores/$STORE_ID/products" \
-H "Authorization: Bearer $BP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Iced Matcha",
"description": "Stone-ground ceremonial grade.",
"product_type": "single",
"default_price_cents": 1890
}'Single products get a hidden "Default" variant created in the same
transaction when you pass default_price_cents. For variable products,
omit default_price_cents and create variants separately via
POST /stores/{id}/products/{id}/variants.
Attach a highlight video
A product can have one highlight video — a short clip that the storefront renders as a small floating widget at the bottom-left of the product page. Click it to expand to fullscreen with sound.
Set it on the product itself, not the gallery:
curl -X PATCH "https://bp.mobicms.com.br/stores/$STORE_ID/products/$PRODUCT_ID" \
-H "Authorization: Bearer $BP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"highlight_video_url": "https://youtu.be/abc123",
"highlight_video_poster_url": "https://files.example.com/poster.jpg"
}'The provider (youtube, vimeo, upload, external) is auto-detected
from the URL — you can override by setting highlight_video_provider
explicitly.
Add a gallery video
Gallery videos sit next to gallery images and are useful for product tours, "how it's made", or fit/sizing demos. Unlike the highlight video, they're click-to-play inside the gallery instead of an autoplay widget.
curl -X POST "https://bp.mobicms.com.br/stores/$STORE_ID/products/$PRODUCT_ID/videos" \
-H "Authorization: Bearer $BP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"url": "https://files.example.com/video.mp4",
"poster_url": "https://files.example.com/poster.jpg",
"position": 2
}'If you set product_variant_id on the request, the video only appears
when that variant is selected on the product page — same rule as
variant-scoped images.
Listing strategies
Default sort is updated_at DESC. Drafts are hidden unless you pass
?include_drafts=true (which requires products.read).
# Search by title or sku_prefix substring
curl "https://bp.mobicms.com.br/stores/$STORE_ID/products?search=matcha" \
-H "Authorization: Bearer $BP_TOKEN"Permission cheatsheet
| Action | Permission bit |
|---|---|
| List, get | products.read |
| Create | products.write |
| Update, attach media | products.edit |
| Delete | products.delete |
| Publish (status → live) | products.publish |