Product questions

GET /product-questions

List the questions shoppers have asked about your products, newest first by default. Includes unpublished questions waiting on moderation. Supports search, filtering, sorting and cursor pagination, plus answered to see only what still needs a reply.

Requires the reviews: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.

sortcreatedAt | -createdAt | moderatedAt | -moderatedAt | answeredAt | -answeredAt

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, published, flagged, moderatedAt, answeredAt, source, metadata, createdAt, product.id, product.slug, product.title, product.metadata, product.createdAt, customer.id, customer.email, customer.firstName, customer.lastName, customer.metadata, customer.emailOptOut, customer.emailOptOutSource, customer.createdAt. 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: customer, product, answers.

answeredstring

True lists only questions with at least one published answer, false only those still waiting for one. Leave it out for both.

Request
curl \
  "https://api.cascade.dev/product-questions" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productId": "550e8400-e29b-41d4-a716-446655440000",
      "siteId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "askerName": "string",
      "askerEmail": "string",
      "notifyByEmail": true,
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "instantAnswerId": "550e8400-e29b-41d4-a716-446655440000",
      "answeredAt": "2025-01-15T09:30:00Z",
      "notifiedAt": "2025-01-15T09:30:00Z",
      "source": "widget",
      "answerCount": 0,
      "publishedAnswerCount": 0,
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "customer": {
        "id": "...",
        "email": "...",
        "phone": "...",
        "firstName": "...",
        "lastName": "...",
        "country": "...",
        "birthday": "...",
        "metadata": "...",
        "notes": "...",
        "emailOptOut": "...",
        "emailOptOutAt": "...",
        "emailOptOutSource": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "product": {
        "id": "...",
        "slug": "...",
        "title": "...",
        "description": "...",
        "imageUrl": "...",
        "url": "...",
        "metadata": "...",
        "notes": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "answers": ["..."]
    }
  ],
  "nextCursor": "string"
}

POST /product-questions

Record a question a shopper asked you somewhere else, such as by email or over the phone. It lands in the same queue as one asked on a product page.

Requires the reviews:write permission.

Body Parameters

productIdstring (uuid)required

The product the question is about.

bodystringrequired

The question, up to 500 characters.

askerNamestring | null

The name shown beside the question on the storefront. Leave it out for anonymous.

askerEmailstring (email) | null

Where to send the answer, if anywhere.

siteIdstring (uuid) | null

The site the question belongs to.

customerIdstring (uuid) | null

The customer who asked.

publishedboolean

Whether the question goes live right away. Leave it out to put it in the queue.

metadataobject

Free-form string key/value pairs for your own data.

Request
curl \
  -X POST \
  "https://api.cascade.dev/product-questions" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "askerName": "string",
  "askerEmail": "[email protected]",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "published": true,
  "metadata": "..."
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "askerName": "string",
  "askerEmail": "string",
  "notifyByEmail": true,
  "published": true,
  "moderatedAt": "2025-01-15T09:30:00Z",
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "instantAnswerId": "550e8400-e29b-41d4-a716-446655440000",
  "answeredAt": "2025-01-15T09:30:00Z",
  "notifiedAt": "2025-01-15T09:30:00Z",
  "source": "widget",
  "answerCount": 0,
  "publishedAnswerCount": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "product": {
    "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"
  },
  "answers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "authorType": "merchant",
      "authorName": "string",
      "userId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z"
    }
  ]
}

GET /product-questions/{id}/answers

List every answer to a question, published or not, oldest first. Answers shoppers wrote arrive unpublished and wait for you.

Requires the reviews:read permission.

Path Parameters

idstring (uuid)required

The ID of the question.

Request
curl \
  "https://api.cascade.dev/product-questions/550e8400-e29b-41d4-a716-446655440000/answers" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "authorType": "merchant",
      "authorName": "string",
      "userId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z"
    }
  ]
}

POST /product-questions/{id}/answers

Answer a question as the store. The answer is published straight away unless you send published: false, and publishing the first answer is what emails the shopper who asked, if they left an address.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the question to answer.

Body Parameters

bodystringrequired

What to tell the shopper who asked, up to 2000 characters.

publishedboolean

Whether the answer goes live right away. Defaults to true: an answer you wrote needs no moderation.

metadataobject

Free-form string key/value pairs for your own data.

authorNamestring

The name shown above the answer on the storefront. Usually your store's name.

Request
curl \
  -X POST \
  "https://api.cascade.dev/product-questions/550e8400-e29b-41d4-a716-446655440000/answers" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "body": "string",
  "published": true,
  "metadata": "...",
  "authorName": "string"
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "authorType": "merchant",
  "authorName": "string",
  "userId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "published": true,
  "moderatedAt": "2025-01-15T09:30:00Z",
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z"
}

GET /product-questions/{id}

Get a single question by ID, with include=answers for its answers.

Requires the reviews:read permission.

Path Parameters

idstring (uuid)required

The ID of the question.

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: customer, product, answers.

Request
curl \
  "https://api.cascade.dev/product-questions/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "askerName": "string",
  "askerEmail": "string",
  "notifyByEmail": true,
  "published": true,
  "moderatedAt": "2025-01-15T09:30:00Z",
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "instantAnswerId": "550e8400-e29b-41d4-a716-446655440000",
  "answeredAt": "2025-01-15T09:30:00Z",
  "notifiedAt": "2025-01-15T09:30:00Z",
  "source": "widget",
  "answerCount": 0,
  "publishedAnswerCount": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "product": {
    "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"
  },
  "answers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "authorType": "merchant",
      "authorName": "string",
      "userId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z"
    }
  ]
}

PATCH /product-questions/{id}

Moderate a question. Set published to put it on the storefront or take it down; either decision takes it out of the queue. The question's own text is not editable: a question you cannot show as the shopper wrote it should be rejected instead.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the question.

Body Parameters

publishedboolean

Whether the question is visible on the storefront. This is the moderation switch: setting it either way takes the question out of the queue.

askerNamestring | null

The name shown beside the question. Set it to null to show the question anonymously.

metadataobject

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

Request
curl \
  -X PATCH \
  "https://api.cascade.dev/product-questions/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "published": true,
  "askerName": "string",
  "metadata": "..."
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "askerName": "string",
  "askerEmail": "string",
  "notifyByEmail": true,
  "published": true,
  "moderatedAt": "2025-01-15T09:30:00Z",
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "instantAnswerId": "550e8400-e29b-41d4-a716-446655440000",
  "answeredAt": "2025-01-15T09:30:00Z",
  "notifiedAt": "2025-01-15T09:30:00Z",
  "source": "widget",
  "answerCount": 0,
  "publishedAnswerCount": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "product": {
    "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"
  },
  "answers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "authorType": "merchant",
      "authorName": "string",
      "userId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z"
    }
  ]
}

DELETE /product-questions/{id}

Delete a question and every answer to it, along with the asker's email. To take a question off the storefront without losing it, unpublish it instead.

Requires the reviews:write permission.

Path Parameters

idstring (uuid)required

The ID of the question.

Request
curl \
  -X DELETE \
  "https://api.cascade.dev/product-questions/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "productId": "550e8400-e29b-41d4-a716-446655440000",
  "siteId": "550e8400-e29b-41d4-a716-446655440000",
  "customerId": "550e8400-e29b-41d4-a716-446655440000",
  "body": "string",
  "askerName": "string",
  "askerEmail": "string",
  "notifyByEmail": true,
  "published": true,
  "moderatedAt": "2025-01-15T09:30:00Z",
  "flagged": true,
  "flags": [
    {
      "code": "string",
      "detail": "string",
      "score": 0
    }
  ],
  "instantAnswerId": "550e8400-e29b-41d4-a716-446655440000",
  "answeredAt": "2025-01-15T09:30:00Z",
  "notifiedAt": "2025-01-15T09:30:00Z",
  "source": "widget",
  "answerCount": 0,
  "publishedAnswerCount": 0,
  "metadata": "...",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "product": {
    "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"
  },
  "answers": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "productQuestionId": "550e8400-e29b-41d4-a716-446655440000",
      "body": "string",
      "authorType": "merchant",
      "authorName": "string",
      "userId": "550e8400-e29b-41d4-a716-446655440000",
      "customerId": "550e8400-e29b-41d4-a716-446655440000",
      "published": true,
      "moderatedAt": "2025-01-15T09:30:00Z",
      "flagged": true,
      "flags": ["..."],
      "metadata": "...",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z"
    }
  ]
}