Products

GET /products/{id}/review-summary

Get the generated summary of what this product's reviewers say, along with its themes and what it was generated from. Returns null until the product has enough published reviews for one.

Requires the reviews:read permission.

Path Parameters

idstring (uuid)required

The ID of the product.

Request
curl \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/review-summary" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "summary": "string",
  "themes": [
    {
      "label": "string",
      "sentiment": "positive",
      "reviewCount": 0
    }
  ],
  "language": "string",
  "reviewCount": 0,
  "newestReviewAt": "2025-01-15T09:30:00Z",
  "modelId": "string",
  "promptVersion": 0,
  "generatedAt": "2025-01-15T09:30:00Z",
  "suppressedAt": "2025-01-15T09:30:00Z",
  "previous": {
    "summary": "string",
    "themes": [
      {
        "label": "...",
        "sentiment": "...",
        "reviewCount": "..."
      }
    ],
    "language": "string",
    "reviewCount": 0,
    "newestReviewAt": "2025-01-15T09:30:00Z",
    "modelId": "string",
    "promptVersion": 0,
    "generatedAt": "2025-01-15T09:30:00Z"
  }
}

PATCH /products/{id}/review-summary

Hide a product's review summary from your storefront, or put it back. A hidden summary is also left alone by the regeneration policy, so hiding it is not undone by the next batch of reviews.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the product.

Body Parameters

suppressedbooleanrequired

True hides the summary from your storefront and stops it being regenerated. False puts it back.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/review-summary" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "suppressed": true
}'
Response
{
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "summary": "string",
  "themes": [
    {
      "label": "string",
      "sentiment": "positive",
      "reviewCount": 0
    }
  ],
  "language": "string",
  "reviewCount": 0,
  "newestReviewAt": "2025-01-15T09:30:00Z",
  "modelId": "string",
  "promptVersion": 0,
  "generatedAt": "2025-01-15T09:30:00Z",
  "suppressedAt": "2025-01-15T09:30:00Z",
  "previous": {
    "summary": "string",
    "themes": [
      {
        "label": "...",
        "sentiment": "...",
        "reviewCount": "..."
      }
    ],
    "language": "string",
    "reviewCount": 0,
    "newestReviewAt": "2025-01-15T09:30:00Z",
    "modelId": "string",
    "promptVersion": 0,
    "generatedAt": "2025-01-15T09:30:00Z"
  }
}

POST /products/{id}/review-summary/regenerate

Queue a fresh summary for this product. The new one goes live as soon as it is written, and the one it replaces is kept so you can go back to it. A product can be regenerated once a day.

Requires the reviews:write permission.

Costs 5 rate limit tokens instead of the usual one. See Rate limits.

Path Parameters

idstring (uuid)required

The ID of the product.

Request
curl \
  -X POST \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/review-summary/regenerate" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "queued": true
}

POST /products/{id}/review-summary/accept

Keep the current summary and forget the one it replaced. After this there is nothing to revert to.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the product.

Request
curl \
  -X POST \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/review-summary/accept" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "summary": "string",
  "themes": [
    {
      "label": "string",
      "sentiment": "positive",
      "reviewCount": 0
    }
  ],
  "language": "string",
  "reviewCount": 0,
  "newestReviewAt": "2025-01-15T09:30:00Z",
  "modelId": "string",
  "promptVersion": 0,
  "generatedAt": "2025-01-15T09:30:00Z",
  "suppressedAt": "2025-01-15T09:30:00Z",
  "previous": {
    "summary": "string",
    "themes": [
      {
        "label": "...",
        "sentiment": "...",
        "reviewCount": "..."
      }
    ],
    "language": "string",
    "reviewCount": 0,
    "newestReviewAt": "2025-01-15T09:30:00Z",
    "modelId": "string",
    "promptVersion": 0,
    "generatedAt": "2025-01-15T09:30:00Z"
  }
}

POST /products/{id}/review-summary/revert

Put the previous summary back and discard the one that replaced it. Only the most recent regeneration can be undone.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the product.

Request
curl \
  -X POST \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/review-summary/revert" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "summary": "string",
  "themes": [
    {
      "label": "string",
      "sentiment": "positive",
      "reviewCount": 0
    }
  ],
  "language": "string",
  "reviewCount": 0,
  "newestReviewAt": "2025-01-15T09:30:00Z",
  "modelId": "string",
  "promptVersion": 0,
  "generatedAt": "2025-01-15T09:30:00Z",
  "suppressedAt": "2025-01-15T09:30:00Z",
  "previous": {
    "summary": "string",
    "themes": [
      {
        "label": "...",
        "sentiment": "...",
        "reviewCount": "..."
      }
    ],
    "language": "string",
    "reviewCount": 0,
    "newestReviewAt": "2025-01-15T09:30:00Z",
    "modelId": "string",
    "promptVersion": 0,
    "generatedAt": "2025-01-15T09:30:00Z"
  }
}

GET /products

List the organization's products, newest first by default. Supports search, filtering and cursor pagination.

Requires the products:read permission.

Query Parameters

limitnumber

The number of records to return.

cursorstring

A pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.

sorttitle | -title | createdAt | -createdAt | wishlistsCount | -wishlistsCount

The sort order. Prefix a field with - to sort descending. Defaults to -createdAt.

searchstring

A free-text search term, matched case-insensitively against the record's most identifying fields. Combined with filter using AND.

filterstring

A JSON-encoded filter document, for example {"createdAt":{"$gte":"2025-01-01T00:00:00Z"}}. Filterable fields: id, slug, title, metadata, createdAt, tags.name, variants.id, variants.title, variants.slug, variants.metadata. See Filtering for the syntax.

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: importJob, reviewsCount, wishlistsCount, variantsCount, tags, variants.

Request
curl \
  "https://api.cascade.dev/products" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "string",
      "title": "string",
      "description": "string",
      "imageUrl": "string",
      "url": "string",
      "metadata": "...",
      "notes": "string",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "importJob": {
        "id": "...",
        "type": "...",
        "action": "...",
        "row": "...",
        "createdAt": "..."
      },
      "reviewsCount": 0,
      "wishlistsCount": 0,
      "variantsCount": 0,
      "tags": ["..."],
      "variants": ["..."]
    }
  ],
  "nextCursor": "string"
}

PATCH /products/bulk-update

Add or remove tags and metadata across every product matching a filter, in one request. Sending no filter applies the changes to every product in the organization.

Requires the products:write permission.

Costs 5 rate limit tokens instead of the usual one. See Rate limits.

Query Parameters

filterstring

A JSON-encoded filter document selecting the products to update. Omit it and every product in the organization is updated. See Filtering for the syntax.

searchstring

A free-text search term, matched case-insensitively against the record's most identifying fields. Combined with filter using AND.

Body Parameters

addTagsstring[]

Tag names to add. Tags that do not exist yet are created.

removeTagsstring[]

Tag names to remove.

addMetadataobject

Metadata keys to set, merged onto whatever each product already has.

removeMetadataKeysstring[]

Metadata keys to delete.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/products/bulk-update" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "addTags": [
    "string"
  ],
  "removeTags": [
    "string"
  ],
  "addMetadata": "...",
  "removeMetadataKeys": [
    "string"
  ]
}'
Response
{
  "count": 0
}

POST /products/import

Create or update products in bulk, matching on slug. Variants and site links are replaced with exactly what you send, so include the full set for each product. Rows naming a site that doesn't exist are skipped and returned in skipped; set strict to fail on the first such row instead.

Requires the products:write permission.

Costs 10 rate limit tokens instead of the usual one. See Rate limits.

Body Parameters

dataobject[]required

The products to create or update.

strictboolean

When true, a row that references something missing fails the whole import with an error. Off by default: rows whose references don't resolve are skipped and reported in skipped.

mergeMetadataboolean

When true, each row's metadata keys (and its variants' metadata keys) are merged onto whatever is already stored instead of replacing it.

Request
curl \
  -X POST \
  "https://api.cascade.dev/products/import" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "data": [
    {
      "slug": "string",
      "title": "string",
      "description": "string",
      "imageUrl": "string",
      "url": "string",
      "metadata": "...",
      "tags": [
        "..."
      ],
      "variants": [
        "..."
      ],
      "sites": [
        "..."
      ]
    }
  ],
  "strict": true,
  "mergeMetadata": true
}'
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "string",
      "title": "string",
      "description": "string",
      "imageUrl": "string",
      "url": "string",
      "metadata": "...",
      "notes": "string",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "importJob": {
        "id": "...",
        "type": "...",
        "action": "...",
        "row": "...",
        "createdAt": "..."
      },
      "reviewsCount": 0,
      "wishlistsCount": 0,
      "variantsCount": 0,
      "tags": ["..."],
      "variants": ["..."]
    }
  ],
  "skipped": [
    {
      "index": 0,
      "message": "string"
    }
  ]
}

GET /products/{id}

Get a single product by ID.

Requires the products:read permission.

Path Parameters

idstring (uuid)required

The ID of the product.

Query Parameters

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: importJob, reviewsCount, wishlistsCount, variantsCount, tags, variants.

Request
curl \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "metadata": "...",
  "notes": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "metadata": "..."
    }
  ]
}

PATCH /products/{id}

Update a product's metadata, notes or tags. Catalog fields such as the title and slug come from the store and cannot be edited here. Triggers the product.updated webhook.

Requires the products:write permission.

Path Parameters

idstring (uuid)required

The ID of the product to update.

Body Parameters

metadataobject

Replaces the product's metadata wholesale. Omit to leave it alone.

notesstring

Internal notes about the product.

tagsstring[]

The product's full set of tag names. Omit to leave the tags alone.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "metadata": "...",
  "notes": "string",
  "tags": [
    "string"
  ]
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "metadata": "...",
  "notes": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "metadata": "..."
    }
  ]
}

DELETE /products/{id}

Delete a product along with its variants, tags and site links. Its reviews are kept but unlinked and unpublished, unless the organization has cascadeDeleteReviews turned on. Triggers the product.deleted webhook.

Requires the products:write permission.

Path Parameters

idstring (uuid)required

The ID of the product to delete.

Request
curl \
  -X DELETE \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "metadata": "...",
  "notes": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "metadata": "..."
    }
  ]
}

PATCH /products/{productId}/variants/{variantId}

Update a variant's metadata. Triggers the productVariant.updated webhook.

Requires the products:write permission.

Path Parameters

productIdstring (uuid)required

The ID of the product the variant belongs to.

variantIdstring (uuid)required

The ID of the variant to update.

Body Parameters

metadataobject

Replaces the variant's metadata wholesale. Omit to leave it alone.

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/products/550e8400-e29b-41d4-a716-446655440000/variants/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "metadata": "..."
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "slug": "string",
  "title": "string",
  "imageUrl": "string",
  "priceCents": 0,
  "currencyCode": "string",
  "available": true,
  "metadata": "..."
}