Skip to content

Products & Prices

Products are the catalog items you sell in your SMBcrm account. Each product can have one or more prices, which set how much it costs and how it’s billed, one-time or recurring.

Base URL: https://services.smbcrm.com · Version header: v3 · Scopes: products.readonly / products.write for products, bulk updates, reviews, and online store visibility; products/prices.readonly / products/prices.write for prices and inventory; products/collection.readonly / products/collection.write for collections. See Scopes.

GET/products/

List the products in your account, paginated.

scope products.readonlyauth Location token or PIT

locationId is required. Use limit and offset to page through results, or search to filter by name. total in the response is an array with one object, [{ "total": n }].

Terminal window
curl "https://services.smbcrm.com/products/?locationId=<location_id>&limit=20&offset=0" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"products": [
{
"_id": "<product_id>",
"locationId": "<location_id>",
"name": "1-Hour Consultation",
"productType": "SERVICE",
"description": "A single 60-minute strategy session.",
"availableInStore": true,
"createdAt": "2026-06-01T12:00:00.000Z",
"updatedAt": "2026-06-01T12:00:00.000Z"
}
],
"total": [{ "total": 1 }]
}
Query param Type Required Description
locationId string Yes Your <location_id>.
limit number No Maximum number of products to return per page.
offset number No Number of products to skip, for pagination.
search string No Filter by product name.
collectionIds string No Comma-separated collection IDs to filter by.
collectionSlug string No Slug of a collection to filter by.
productIds array of strings No Return only these products.
availableInStore boolean No Filter by whether the product is available in your online store.
storeId string No Return products for this online store.
includedInStore boolean No Separate the products that are included in the store from those that aren’t.
sortOrder string No asc or desc. Sorts by date.
expand array of strings No Entities to return in full: tax, stripe, or paypal. Without tax, taxes holds IDs only.

Product objects can also include variants, image, statementDescriptor, collectionIds, isTaxesEnabled, taxes, automaticTaxCategoryId, label, and slug. These fields appear when they’re set. See Product collections for collectionIds.

GET/products/{productId}

Fetch a single product by ID or slug.

scope products.readonlyauth Location token or PIT

productId accepts the product’s ID or its slug. locationId is required. Add sendWishlistStatus=true to the query to include the product’s wishlist status.

Terminal window
curl "https://services.smbcrm.com/products/<product_id>?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"_id": "<product_id>",
"locationId": "<location_id>",
"name": "1-Hour Consultation",
"productType": "SERVICE",
"description": "A single 60-minute strategy session.",
"availableInStore": true,
"createdAt": "2026-06-01T12:00:00.000Z",
"updatedAt": "2026-06-01T12:00:00.000Z"
}
POST/products/

Create a product in your account's catalog.

scope products.writeauth Location token or PIT

locationId, name, and productType (DIGITAL, PHYSICAL, SERVICE, or PHYSICAL/DIGITAL) are required.

Terminal window
curl -X POST https://services.smbcrm.com/products/ \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"locationId": "<location_id>",
"name": "1-Hour Consultation",
"productType": "SERVICE",
"description": "A single 60-minute strategy session."
}'
201 Created
{
"_id": "<product_id>",
"locationId": "<location_id>",
"name": "1-Hour Consultation",
"productType": "SERVICE",
"description": "A single 60-minute strategy session.",
"availableInStore": false,
"createdAt": "2026-07-08T15:04:00.000Z",
"updatedAt": "2026-07-08T15:04:00.000Z"
}

Optional body fields:

Field Type Description
description string A short description of the product.
image string URL of the product image.
statementDescriptor string The statement descriptor for the product.
availableInStore boolean Whether the product is available in your online store.
medias array Media for the product. Each item needs id, url, and type (image or video). title, isFeatured, and priceIds are optional.
variants array Product variants. Each item has an id, a name, and options, an array of { id, name } objects.
collectionIds array of strings IDs of the collections the product belongs to.
slug string The slug used to navigate to the product.
seo object SEO preview data: title and description.
isTaxesEnabled boolean Defaults to false. When true, taxes can’t be empty.
taxes array of strings IDs of the taxes attached to the product. If you send taxes, set isTaxesEnabled to true.
taxInclusive boolean Defaults to false. Whether taxes are included in the purchase price.
automaticTaxCategoryId string Tax category ID for automatic tax calculation.
isLabelEnabled boolean Defaults to false. When true, label can’t be empty.
label object A product label with title (required), startDate, and endDate.
PUT/products/{productId}

Update fields on an existing product.

scope products.writeauth Location token or PIT

PUT replaces the product, so name, locationId, and productType are required even if you’re only changing one field. It accepts the same optional fields as Create a product, plus prices (an array of strings). productId can be the product’s ID or its slug.

Terminal window
curl -X PUT https://services.smbcrm.com/products/<product_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"name": "60-Minute Consultation",
"locationId": "<location_id>",
"productType": "SERVICE",
"description": "Updated description."
}'
200 OK
{
"_id": "<product_id>",
"locationId": "<location_id>",
"name": "60-Minute Consultation",
"productType": "SERVICE",
"description": "Updated description.",
"availableInStore": false,
"createdAt": "2026-07-08T15:04:00.000Z",
"updatedAt": "2026-07-09T10:30:00.000Z"
}
DELETE/products/{productId}

Permanently delete a product.

scope products.writeauth Location token or PIT

productId can be the product’s ID or its slug. locationId is required.

Terminal window
curl -X DELETE "https://services.smbcrm.com/products/<product_id>?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "status": true }
POST/products/bulk-update

Change the prices, availability, collections, or currency of several products at once, or delete them.

scope products.writeauth Location token or PIT

Send altId (your location ID), altType (location), a type, and the productIds to change. The type decides what the request does and which other field it uses:

type What it does Field to send
bulk-update-price Updates the prices of the products. price, and optionally compareAtPrice
bulk-update-availability Updates whether the products are available. availability (boolean)
bulk-update-product-collection Updates the collections the products belong to. collectionIds (array of strings)
bulk-delete-products Deletes the products. None
bulk-update-currency Updates the currency of the products. currency (for example, USD)

price and compareAtPrice are objects with the same shape. type and value are required; roundToWhole is an optional boolean that rounds the result to a whole number. type is one of INCREASE_BY_AMOUNT, REDUCE_BY_AMOUNT, SET_NEW_PRICE, INCREASE_BY_PERCENTAGE, or REDUCE_BY_PERCENTAGE, and value is the amount or the percentage, depending on type. You can also send a filters object with collectionIds, productType, availableInStore, and search.

Terminal window
curl -X POST https://services.smbcrm.com/products/bulk-update \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"type": "bulk-update-price",
"productIds": ["<product_id>", "<product_id>"],
"price": { "type": "INCREASE_BY_PERCENTAGE", "value": 10, "roundToWhole": true }
}'
201 Created
{ "status": true }
GET/products/{productId}/price

List the prices attached to a product.

scope products/prices.readonlyauth Location token or PIT

locationId is required. Optional: limit and offset to page through results, and ids (comma-separated price IDs) to return only specific prices.

Terminal window
curl "https://services.smbcrm.com/products/<product_id>/price?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"prices": [
{
"_id": "<price_id>",
"product": "<product_id>",
"name": "Standard rate",
"type": "one_time",
"amount": 149,
"currency": "USD"
}
],
"total": 1
}
GET/products/{productId}/price/{priceId}

Fetch a single price by ID.

scope products/prices.readonlyauth Location token or PIT
Terminal window
curl "https://services.smbcrm.com/products/<product_id>/price/<price_id>?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"_id": "<price_id>",
"product": "<product_id>",
"name": "Standard rate",
"type": "one_time",
"amount": 149,
"currency": "USD"
}

Price responses can also include recurring, compareAtPrice, trackInventory, availableQuantity, allowOutOfStockPurchases, membershipOffers, variantOptionIds, userId, and updatedAt. These fields appear when they’re set.

POST/products/{productId}/price

Create a price for a product.

scope products/prices.writeauth Location token or PIT

name, type (one_time or recurring), amount, currency, and locationId are required. amount can’t be negative. For a recurring price, also include a recurring object with interval (day, week, month, or year) and intervalCount.

Terminal window
curl -X POST https://services.smbcrm.com/products/<product_id>/price \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"name": "Standard rate",
"type": "one_time",
"amount": 149,
"currency": "USD",
"locationId": "<location_id>"
}'
201 Created
{
"_id": "<price_id>",
"product": "<product_id>",
"locationId": "<location_id>",
"name": "Standard rate",
"type": "one_time",
"amount": 149,
"currency": "USD",
"createdAt": "2026-07-08T15:04:00.000Z"
}

Optional body fields:

Field Type Description
description string A short description of the price.
trialPeriod number Length of the trial period, in days.
totalCycles number Total number of billing cycles. Minimum 1.
setupFee number A one-time setup fee.
compareAtPrice number The original price to show next to the current one.
trackInventory boolean Track the stock quantity of this price. See Inventory.
availableQuantity number Stock quantity available.
allowOutOfStockPurchases boolean Keep selling when the quantity reaches zero.
sku string The SKU for the price.
shippingOptions object Shipping details: weight (value and unit: kg, lb, g, or oz) and dimensions (height, width, length, and unit: cm, in, or m).
variantOptionIds array of strings IDs of the variant options this price applies to.
isDigitalProduct boolean Whether the price is for a digital product.
digitalDelivery array of strings Digital delivery options.
PUT/products/{productId}/price/{priceId}

Update an existing price.

scope products/prices.writeauth Location token or PIT

PUT replaces the price, so name, type, currency, amount, and locationId are required even if you’re only changing one field. It accepts the same optional fields as Create a price.

Terminal window
curl -X PUT https://services.smbcrm.com/products/<product_id>/price/<price_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"name": "Promo rate",
"type": "one_time",
"amount": 99,
"currency": "USD",
"locationId": "<location_id>"
}'
200 OK
{
"_id": "<price_id>",
"product": "<product_id>",
"locationId": "<location_id>",
"name": "Promo rate",
"type": "one_time",
"amount": 99,
"currency": "USD",
"updatedAt": "2026-07-09T10:30:00.000Z"
}
DELETE/products/{productId}/price/{priceId}

Permanently delete a price.

scope products/prices.writeauth Location token or PIT

locationId is required.

Terminal window
curl -X DELETE "https://services.smbcrm.com/products/<product_id>/price/<price_id>?locationId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "status": true }

Stock is tracked per price. Turn tracking on with trackInventory when you create or update a price, then use these endpoints to read and change the stock of many prices at once.

GET/products/inventory

List inventory items, paginated.

scope products/prices.readonlyauth Location token or PIT

Each item in inventory is a price. Its _id is the price ID and product is the ID of the product it belongs to. total is an object, { "total": n }.

Terminal window
curl "https://services.smbcrm.com/products/inventory?altId=<location_id>&altType=location&limit=20&offset=0" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"inventory": [
{
"_id": "<price_id>",
"name": "Medium",
"availableQuantity": 50,
"sku": "TSHIRT-MED-001",
"allowOutOfStockPurchases": false,
"product": "<product_id>",
"productName": "T-shirt",
"updatedAt": "2026-10-01T09:27:42.355Z"
}
],
"total": { "total": 1 }
}
Query param Type Required Description
altId string Yes Your <location_id>.
altType string Yes Always location.
limit number No Maximum number of items to return per page.
offset number No Number of items to skip, for pagination.
search string No Search term for finding a variant.
POST/products/inventory

Update the stock quantity and out-of-stock setting of several prices at once.

scope products/prices.writeauth Location token or PIT

Send altId, altType, and an items array. Each item needs a priceId; add availableQuantity and allowOutOfStockPurchases for the values you want to change.

Terminal window
curl -X POST https://services.smbcrm.com/products/inventory \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"items": [
{ "priceId": "<price_id>", "availableQuantity": 25, "allowOutOfStockPurchases": false }
]
}'
201 Created
{ "status": true }

Collections group products, for example a “Best Sellers” collection. Add a product to a collection with collectionIds when you create or update it. These endpoints take altId and altType instead of locationId.

GET/products/collections

List the product collections in your account, paginated.

scope products/collection.readonlyauth Location token or PIT

The response has data, the array of collections, and total, the number of collections.

Terminal window
curl "https://services.smbcrm.com/products/collections?altId=<location_id>&altType=location&limit=10&offset=0" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"data": [
{
"_id": "<collection_id>",
"altId": "<location_id>",
"name": "Best Sellers",
"slug": "best-sellers",
"image": "https://example.com/best-sellers.png",
"createdAt": "2026-10-01T09:27:19.728Z"
}
],
"total": 1
}
Query param Type Required Description
altId string Yes Your <location_id>.
altType string Yes Always location.
limit number No Maximum number of collections to return per page. Defaults to 10.
offset number No Number of collections to skip, for pagination. Defaults to 0.
collectionIds string No Comma-separated collection IDs to return.
name string No Search collections by name.
POST/products/collections

Create a product collection.

scope products/collection.writeauth Location token or PIT

altId, altType, name, and slug are required. The slug must be unique and can’t contain spaces or special characters. Optional fields are image (a thumbnail URL), seo (an object with title and description), and collectionId.

Terminal window
curl -X POST https://services.smbcrm.com/products/collections \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"name": "Best Sellers",
"slug": "best-sellers",
"image": "https://example.com/best-sellers.png",
"seo": {
"title": "Best Sellers",
"description": "Our most popular products."
}
}'
201 Created
{
"data": {
"_id": "<collection_id>",
"altId": "<location_id>",
"name": "Best Sellers",
"slug": "best-sellers",
"image": "https://example.com/best-sellers.png",
"seo": {
"title": "Best Sellers",
"description": "Our most popular products."
},
"createdAt": "2026-10-08T15:04:00.000Z"
}
}
GET/products/collections/{collectionId}

Fetch a single product collection by ID.

scope products/collection.readonlyauth Location token or PIT

altId is required. This request doesn’t take altType. The response has data, the collection, and a status boolean.

Terminal window
curl "https://services.smbcrm.com/products/collections/<collection_id>?altId=<location_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
PUT/products/collections/{collectionId}

Update a product collection.

scope products/collection.writeauth Location token or PIT

altId and altType are required. Send any of name, slug, image, and seo to change them.

Terminal window
curl -X PUT https://services.smbcrm.com/products/collections/<collection_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"name": "Top Sellers"
}'
200 OK
{ "status": true }
DELETE/products/collections/{collectionId}

Delete a product collection.

scope products/collection.writeauth Location token or PIT

altId and altType are required.

Terminal window
curl -X DELETE "https://services.smbcrm.com/products/collections/<collection_id>?altId=<location_id>&altType=location" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "status": true }

Read and moderate customer reviews of your products. These endpoints take altId and altType instead of locationId.

GET/products/reviews

List product reviews, with filters and sorting.

scope products.readonlyauth Location token or PIT

The response has data, the array of reviews, and total.

Terminal window
curl "https://services.smbcrm.com/products/reviews?altId=<location_id>&altType=location&sortField=createdAt&sortOrder=desc&limit=20" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
Query param Type Required Description
altId string Yes Your <location_id>.
altType string Yes Always location.
limit number No Maximum number of reviews to return per page.
offset number No Number of reviews to skip, for pagination.
sortField string No createdAt or rating.
sortOrder string No asc or desc.
rating number No Return reviews with this rating.
startDate string No Return reviews from this date.
endDate string No Return reviews up to this date.
productId string No Comma-separated product IDs.
storeId string No Comma-separated store IDs.
GET/products/reviews/count

Count reviews by status.

scope products.readonlyauth Location token or PIT

altId and altType are required. The optional rating, startDate, endDate, productId, and storeId filters work the same as on the review list. The response has a data array of review counts by status.

Terminal window
curl "https://services.smbcrm.com/products/reviews/count?altId=<location_id>&altType=location" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
PUT/products/reviews/{reviewId}

Update a review's status, rating, text, or replies.

scope products.writeauth Location token or PIT

altId, altType, productId, and status are required in the body. status sets the review’s status, for example approved. You can also send rating, headline, detail, and reply. Each reply item needs a headline (up to 200 characters), a comment (up to 5,000 characters), and a user object with a name and email; phone and isCustomer are optional.

Terminal window
curl -X PUT https://services.smbcrm.com/products/reviews/<review_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"productId": "<product_id>",
"status": "approved",
"reply": [
{
"headline": "Thanks for your review",
"comment": "We are glad it worked out for you.",
"user": { "name": "Support Team", "email": "support@example.com", "isCustomer": false }
}
]
}'
200 OK
{ "status": true }
DELETE/products/reviews/{reviewId}

Delete a review.

scope products.writeauth Location token or PIT

altId, altType, and productId are required query parameters.

Terminal window
curl -X DELETE "https://services.smbcrm.com/products/reviews/<review_id>?altId=<location_id>&altType=location&productId=<product_id>" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{ "status": true }
POST/products/reviews/bulk-update

Set the status of several reviews at once.

scope products.writeauth Location token or PIT

altId, altType, reviews, and status are required. Each item in reviews needs a reviewId, a productId, and a storeId.

Terminal window
curl -X POST https://services.smbcrm.com/products/reviews/bulk-update \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"reviews": [
{ "reviewId": "<review_id>", "productId": "<product_id>", "storeId": "<store_id>" }
],
"status": "approved"
}'
201 Created
{ "status": true }

Choose which products appear in your online store. storeId is the ID of your online store. These endpoints take altId and altType instead of locationId.

GET/products/store/{storeId}/stats

Count the products in your catalog, and how many are included in or excluded from the store.

scope products.readonlyauth Location token or PIT

altId and altType are required. Add search to filter by product name and collectionIds (comma-separated) to filter by collection.

Terminal window
curl "https://services.smbcrm.com/products/store/<store_id>/stats?altId=<location_id>&altType=location" \
-H "Authorization: Bearer <token>" \
-H "Version: v3"
200 OK
{
"totalProducts": 100,
"includedInStore": 80,
"excludedFromStore": 20
}
POST/products/store/{storeId}

Include products in the store, or exclude them.

scope products.writeauth Location token or PIT

altId, altType, action (include or exclude), and productIds are all required.

Terminal window
curl -X POST https://services.smbcrm.com/products/store/<store_id> \
-H "Authorization: Bearer <token>" \
-H "Version: v3" \
-H "Content-Type: application/json" \
-d '{
"altId": "<location_id>",
"altType": "location",
"action": "include",
"productIds": ["<product_id>"]
}'
201 Created
{ "status": true }
  • Payments: orders, transactions, subscriptions, and invoices built on top of your product catalog.
  • Subscriptions: recurring billing tied to a price.
  • Invoices & Estimates: add a price as a line item on an invoice or estimate.
  • Scopes: request only the product/price scopes your integration needs.