#Product question answers
PATCH /product-question-answers/{id}
Edit an answer, or publish and unpublish it. Publishing a shopper's answer is how it reaches the storefront.
Requires the reviews:write permission.
Path Parameters
idstring (uuid)requiredThe ID of the answer.
Body Parameters
bodystringWhat to tell the shopper who asked, up to 2000 characters.
authorNamestringThe name shown above the answer.
publishedbooleanWhether the answer is visible on the storefront. This is the moderation switch for answers shoppers wrote.
metadataobjectReplaces the answer's metadata wholesale. Omit to leave it alone.
Request
curl \
-X PATCH \
"https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"body": "string",
"authorName": "string",
"published": true,
"metadata": "..."
}'Request
import { client } from "@cascade-commerce/api/admin/client"
import { patchProductQuestionAnswersById } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await patchProductQuestionAnswersById({
path: { id: "550e8400-e29b-41d4-a716-446655440000" },
body: {
body: "string",
authorName: "string",
published: true,
metadata: "...",
},
})Request
require "net/http"
uri = URI("https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000")
req = Net::HTTP::Patch.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
req["Content-Type"] = "application/json"
req.body = <<~JSON
{
"body": "string",
"authorName": "string",
"published": true,
"metadata": "..."
}
JSON
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyRequest
import json
from urllib.request import Request, urlopen
body = """{
"body": "string",
"authorName": "string",
"published": true,
"metadata": "..."
}"""
req = Request(
"https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000",
data=body.encode(),
method="PATCH",
headers={
"Authorization": "Bearer sk_YOUR_SECRET_KEY",
"Content-Type": "application/json",
},
)
with urlopen(req) as res:
print(json.load(res))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"
}Response schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the answer."
},
"productQuestionId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The question this answers."
},
"body": {
"type": "string",
"description": "The answer text."
},
"authorType": {
"type": "string",
"enum": ["merchant", "shopper"],
"description": "Who wrote the answer. A `merchant` answer speaks for the store and is the accepted answer in the product page's structured data; a `shopper` answer is a suggested one."
},
"authorName": {
"type": "string",
"description": "The name shown above the answer on the storefront, such as the person or the store."
},
"userId": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{
"type": "null"
}
],
"description": "The team member who wrote it, for answers written in your dashboard."
},
"customerId": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{
"type": "null"
}
],
"description": "The customer who wrote it, for a shopper's answer."
},
"published": {
"type": "boolean",
"description": "Whether the answer is visible on the storefront. Answers you write are published by default; answers shoppers write wait for moderation."
},
"moderatedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When the answer was published or rejected, or null if nobody has decided on it yet."
},
"flagged": {
"type": "boolean",
"description": "Whether content screening flagged the answer on arrival."
},
"flags": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Machine-readable reason the review was flagged, such as `links` or `profanity`."
},
"detail": {
"type": "string",
"description": "Human-readable explanation shown in the moderation pane."
},
"score": {
"description": "The raw score behind the flag, from 0 to 1, for checks that produce one. The `aiGenerated` flag carries the AI-writing detector's confidence; the other checks carry no score.",
"type": "number"
}
},
"required": ["code", "detail"],
"additionalProperties": false
},
"description": "Why the answer was flagged. Empty for answers that passed screening."
},
"metadata": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Free-form string key/value pairs for your own data. Individual keys are filterable with a dot path, for example `metadata.category`."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the answer was written."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the answer was last changed."
}
},
"required": [
"id",
"productQuestionId",
"body",
"authorType",
"authorName",
"userId",
"customerId",
"published",
"moderatedAt",
"flagged",
"flags",
"metadata",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The updated answer."
}DELETE /product-question-answers/{id}
Delete an answer. The question and its other answers are untouched. To hide an answer without losing it, unpublish it instead.
Requires the reviews:write permission.
Path Parameters
idstring (uuid)requiredThe ID of the answer.
Request
curl \
-X DELETE \
"https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"Request
import { client } from "@cascade-commerce/api/admin/client"
import { deleteProductQuestionAnswersById } from "@cascade-commerce/api/admin"
client.setConfig({
baseUrl: "https://api.cascade.dev",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await deleteProductQuestionAnswersById({
path: { id: "550e8400-e29b-41d4-a716-446655440000" },
})Request
require "net/http"
uri = URI("https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000")
req = Net::HTTP::Delete.new(uri)
req["Authorization"] = "Bearer sk_YOUR_SECRET_KEY"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.bodyRequest
import json
from urllib.request import Request, urlopen
req = Request(
"https://api.cascade.dev/product-question-answers/550e8400-e29b-41d4-a716-446655440000",
method="DELETE",
headers={"Authorization": "Bearer sk_YOUR_SECRET_KEY"},
)
with urlopen(req) as res:
print(json.load(res))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"
}Response schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "Unique identifier for the answer."
},
"productQuestionId": {
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"description": "The question this answers."
},
"body": {
"type": "string",
"description": "The answer text."
},
"authorType": {
"type": "string",
"enum": ["merchant", "shopper"],
"description": "Who wrote the answer. A `merchant` answer speaks for the store and is the accepted answer in the product page's structured data; a `shopper` answer is a suggested one."
},
"authorName": {
"type": "string",
"description": "The name shown above the answer on the storefront, such as the person or the store."
},
"userId": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{
"type": "null"
}
],
"description": "The team member who wrote it, for answers written in your dashboard."
},
"customerId": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
},
{
"type": "null"
}
],
"description": "The customer who wrote it, for a shopper's answer."
},
"published": {
"type": "boolean",
"description": "Whether the answer is visible on the storefront. Answers you write are published by default; answers shoppers write wait for moderation."
},
"moderatedAt": {
"anyOf": [
{
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"
},
{
"type": "null"
}
],
"description": "When the answer was published or rejected, or null if nobody has decided on it yet."
},
"flagged": {
"type": "boolean",
"description": "Whether content screening flagged the answer on arrival."
},
"flags": {
"type": "array",
"items": {
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "Machine-readable reason the review was flagged, such as `links` or `profanity`."
},
"detail": {
"type": "string",
"description": "Human-readable explanation shown in the moderation pane."
},
"score": {
"description": "The raw score behind the flag, from 0 to 1, for checks that produce one. The `aiGenerated` flag carries the AI-writing detector's confidence; the other checks carry no score.",
"type": "number"
}
},
"required": ["code", "detail"],
"additionalProperties": false
},
"description": "Why the answer was flagged. Empty for answers that passed screening."
},
"metadata": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Free-form string key/value pairs for your own data. Individual keys are filterable with a dot path, for example `metadata.category`."
},
"createdAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the answer was written."
},
"updatedAt": {
"type": "string",
"format": "date-time",
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$",
"description": "When the answer was last changed."
}
},
"required": [
"id",
"productQuestionId",
"body",
"authorType",
"authorName",
"userId",
"customerId",
"published",
"moderatedAt",
"flagged",
"flags",
"metadata",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The deleted answer."
}