Skip to content
SoundSyncAudio software platform

API reference

Review Import API

Preview mapped review rows, confirm an import, and inspect private product review records.

Preview before saving

Parse your review export into JSON rows. Use rows with product, rating, body and optional title, customerName, customerEmail, createdAt, source, status and verifiedClaim. product is the owned product name or supported catalog key, not an entitlement. For different source headings, mapping maps these canonical field names to source column names; array rows use zero-based column indexes.

Preview returns counts and a result for each processed row: ready, invalid or duplicate, with messages and the resolved product. Review the product match rather than accepting a close-name suggestion as an exact match. Only the first 1,000 rows are processed; split larger imports intentionally. Invalid dates normalize to no supplied date. Private names and email addresses must not be copied into public examples.

SoundSync

Illustrative preview request

Preview fictional review data for an owned product
curl --fail-with-body -sS -X POST "$SOUNDSYNC_API_BASE/api/developer/reviews/import/preview" \
  -H "Authorization: Bearer $DEVELOPER_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"rows":[{"product":"Example Instrument","rating":5,"body":"Useful controls and clear sound.","customerName":"Example"}]}'

Confirmation is a separate write

POST the original rows, mapping and confirm:true to /api/developer/reviews/import. Do not send previewRows as the request. Commit runs validation again and saves ready rows only. Inspect importedCount, skippedCount, counts and previewRows; HTTP 201 does not mean every row was saved.

Reviews default to pending. allowPublished:true permits the mapped review status, so use it only after reviewing publication rights and content. Imported reviews retain unverified_import metadata; a source verifiedClaim is not a SoundSync verified-purchase badge. This does not create purchases, entitlements or marketing permission. A batch is not an atomic or idempotency-key operation; after an uncertain failure, preview again before resubmitting.

Private records stay private

Preview and listing require reviews.view. Commit additionally requires reviews.respond. Product assignment limits all three workflows. The product-specific listing uses the route productId even if another ID appears in the query. Private results can include unpublished reviews, customer email and moderation information. Use the public storefront review endpoint for public display.

SoundSync

Review workflows

Reviews guide

Import preparation and moderation.

Brand, Domain and Review API

Existing review listing and response operations.

SoundSync

Requests and responses

POST /api/developer/reviews/import/preview

Validate mapped review rows without saving reviews

Auth
Account Bearer JWT
Scope
reviews.view and assigned-product scope.
Request fields
  • rows: array (required)
  • mapping: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
  • allowPublished: boolean
Returns
HTTP 200: counts, previewRows, products.
Notes
JSON rows only; parse CSV/XLSX before this request. Mapping values are object column names or zero-based array indexes. Only the first 1,000 rows are processed; chunk deliberately. Matches owned products and existing fingerprints. Invalid and duplicate rows are separate outcomes, not saved reviews. Imported claims of verification do not create a verified purchase. allowPublished defaults false.
Request, response and error reference

Request (application/json)

{
  "type": "object",
  "properties": {
    "rows": {
      "type": "array",
      "minItems": 1,
      "maxItems": 1000,
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "product": {
                "type": "string"
              },
              "rating": {
                "type": [
                  "number",
                  "string"
                ]
              },
              "title": {
                "type": "string"
              },
              "body": {
                "type": "string"
              },
              "customerName": {
                "type": "string"
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              },
              "customerEmail": {
                "type": "string"
              },
              "createdAt": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "verifiedClaim": {
                "type": [
                  "boolean",
                  "string",
                  "number"
                ]
              }
            },
            "additionalProperties": true
          },
          {
            "type": "array",
            "items": {}
          }
        ]
      }
    },
    "mapping": {
      "type": "object",
      "additionalProperties": true,
      "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
    },
    "allowPublished": {
      "type": "boolean"
    }
  },
  "required": [
    "rows"
  ],
  "additionalProperties": true
}

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "counts": {
      "type": "object",
      "properties": {
        "ready": {
          "type": "integer"
        },
        "invalid": {
          "type": "integer"
        },
        "duplicate": {
          "type": "integer"
        }
      },
      "additionalProperties": true
    },
    "previewRows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "rowNumber": {
            "type": "integer"
          },
          "status": {
            "enum": [
              "ready",
              "invalid",
              "duplicate"
            ]
          },
          "productId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "productName": {
            "type": "string"
          },
          "rating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string"
          },
          "importedCreatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "reviewStatus": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "verifiedClaim": {
            "type": "boolean"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      }
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            ]
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ]
          },
          "imageUrl": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "additionalProperties": true
      }
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 404, 500, 503.

Operation errors: REVIEW_IMPORT_EMPTY.

POST /api/developer/reviews/import

Save confirmed valid non-duplicate review rows

Auth
Account Bearer JWT
Scope
reviews.view plus reviews.respond and assigned-product scope.
Request fields
  • rows: array (required)
  • mapping: object. Operation-specific extension data; do not put credentials or unnecessary personal information here.
  • allowPublished: boolean
  • confirm: boolean
  • confirmed: boolean
  • importBatchId: string
Returns
HTTP 201: importBatchId, importedCount, skippedCount, counts, reviews, previewRows.
Notes
Send the original rows and mapping again, not the previewRows response. Revalidates at commit and skips invalid/duplicate rows. Defaults to pending; allowPublished:true permits mapped publication status. Does not create an entitlement or verified-purchase badge. Inspect all outcomes; this is not an atomic batch or an idempotency-key API. Re-preview uncertain results before replay.
Request, response and error reference

Request (application/json)

{
  "type": "object",
  "properties": {
    "rows": {
      "type": "array",
      "minItems": 1,
      "maxItems": 1000,
      "items": {
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "product": {
                "type": "string"
              },
              "rating": {
                "type": [
                  "number",
                  "string"
                ]
              },
              "title": {
                "type": "string"
              },
              "body": {
                "type": "string"
              },
              "customerName": {
                "type": "string"
              },
              "firstName": {
                "type": "string"
              },
              "lastName": {
                "type": "string"
              },
              "customerEmail": {
                "type": "string"
              },
              "createdAt": {
                "type": "string"
              },
              "source": {
                "type": "string"
              },
              "status": {
                "type": "string"
              },
              "verifiedClaim": {
                "type": [
                  "boolean",
                  "string",
                  "number"
                ]
              }
            },
            "additionalProperties": true
          },
          {
            "type": "array",
            "items": {}
          }
        ]
      }
    },
    "mapping": {
      "type": "object",
      "additionalProperties": true,
      "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
    },
    "allowPublished": {
      "type": "boolean"
    },
    "confirm": {
      "type": "boolean"
    },
    "confirmed": {
      "type": "boolean"
    },
    "importBatchId": {
      "type": "string"
    }
  },
  "required": [
    "rows"
  ],
  "additionalProperties": true,
  "anyOf": [
    {
      "required": [
        "confirm"
      ],
      "properties": {
        "confirm": {
          "const": true
        }
      }
    },
    {
      "required": [
        "confirmed"
      ],
      "properties": {
        "confirmed": {
          "const": true
        }
      }
    }
  ]
}

HTTP 201 response (application/json)

{
  "type": "object",
  "properties": {
    "importBatchId": {
      "type": "string"
    },
    "importedCount": {
      "type": "integer"
    },
    "skippedCount": {
      "type": "integer"
    },
    "counts": {
      "type": "object",
      "properties": {
        "ready": {
          "type": "integer"
        },
        "invalid": {
          "type": "integer"
        },
        "duplicate": {
          "type": "integer"
        }
      },
      "additionalProperties": true
    },
    "reviews": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            ]
          },
          "productId": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            ]
          },
          "rating": {
            "type": "number"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "imported": {
            "type": "boolean"
          },
          "verified": {
            "type": "boolean"
          },
          "verifiedPurchase": {
            "type": "boolean"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
          }
        },
        "additionalProperties": true
      }
    },
    "previewRows": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "rowNumber": {
            "type": "integer"
          },
          "status": {
            "enum": [
              "ready",
              "invalid",
              "duplicate"
            ]
          },
          "productId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "productName": {
            "type": "string"
          },
          "rating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "customerName": {
            "type": "string"
          },
          "customerEmail": {
            "type": "string"
          },
          "importedCreatedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "reviewStatus": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "verifiedClaim": {
            "type": "boolean"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      }
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 404, 500, 503.

Operation errors: REVIEW_IMPORT_EMPTY, REVIEW_IMPORT_CONFIRM_REQUIRED, REVIEW_IMPORT_NO_READY_ROWS.

GET /api/developer/products/{productId}/reviews

Read private reviews for one assigned product

Auth
Account Bearer JWT
Scope
reviews.view and assigned-product scope. Route productId overrides query productId.
Request fields
  • query page: string
  • query limit: string
  • query search: string
  • query status: string
  • query rating: string
  • query dateRange: string
  • query sort: string
Returns
HTTP 200: reviews, pagination, counts, summary, filters.
Notes
Default limit 50, maximum 100. Private response can include hidden/pending reviews, customer email and moderation metadata; never publish it as the storefront review feed. Page is clamped to available pages.
Request, response and error reference

Query and header parameters

[
  {
    "name": "page",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "limit",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "search",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "status",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "rating",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "dateRange",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  },
  {
    "name": "sort",
    "in": "query",
    "schema": {
      "type": "string"
    },
    "required": false,
    "description": ""
  }
]

No request body fields are read by this operation.

HTTP 200 response (application/json)

{
  "type": "object",
  "properties": {
    "reviews": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            ]
          },
          "productId": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "string",
                "pattern": "^[1-9][0-9]*$"
              }
            ]
          },
          "rating": {
            "type": "number"
          },
          "title": {
            "type": "string"
          },
          "body": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "customerName": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerEmail": {
            "type": [
              "string",
              "null"
            ]
          },
          "customerId": {
            "type": [
              "integer",
              "null"
            ]
          },
          "imported": {
            "type": "boolean"
          },
          "verified": {
            "type": "boolean"
          },
          "verifiedPurchase": {
            "type": "boolean"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
          }
        },
        "additionalProperties": true
      }
    },
    "pagination": {
      "type": "object",
      "properties": {
        "page": {
          "type": "integer"
        },
        "pageSize": {
          "type": "integer"
        },
        "total": {
          "type": "integer"
        },
        "totalPages": {
          "type": "integer"
        }
      },
      "additionalProperties": true
    },
    "counts": {
      "type": "object",
      "additionalProperties": true,
      "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
    },
    "summary": {
      "type": "object",
      "additionalProperties": true,
      "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
    },
    "filters": {
      "type": "object",
      "additionalProperties": true,
      "description": "Operation-specific extension data; do not put credentials or unnecessary personal information here."
    }
  },
  "additionalProperties": true
}

Documented failures: 400, 401, 403, 404, 500, 503.