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

idstringrequired

The ID of the product.

Request
curl \
  "https://your-store.meisei.app/api/products/A4Ws1igz/review-summary" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "A4Ws1igz",
  "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

idstringrequired

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://your-store.meisei.app/api/products/A4Ws1igz/review-summary" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "suppressed": true
}'
Response
{
  "productId": "A4Ws1igz",
  "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. Answers 409 while review summaries are switched off in the review settings.

Requires the reviews:write permission.

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

Path parameters

idstringrequired

The ID of the product.

Request
curl \
  -X POST \
  "https://your-store.meisei.app/api/products/A4Ws1igz/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

idstringrequired

The ID of the product.

Request
curl \
  -X POST \
  "https://your-store.meisei.app/api/products/A4Ws1igz/review-summary/accept" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "A4Ws1igz",
  "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

idstringrequired

The ID of the product.

Request
curl \
  -X POST \
  "https://your-store.meisei.app/api/products/A4Ws1igz/review-summary/revert" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "productId": "A4Ws1igz",
  "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 | string

The sort order. Prefix a field with - to sort descending. Defaults to -createdAt. A custom field sorts as metadata.<key>, records without a value last; GET /metadata-definitions lists the fields.

searchstring

A free-text search term. Every word has to match, from the start of a word, in any order and ignoring case and accents, 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, averageRating, ratingCount, createdAt, tags.name, variants.id, variants.title, variants.slug, variants.metadata, externalIds.externalId. A custom field's metadata.<key> path takes the operators its type supports: $gt, $gte, $lt and $lte for numbers and dates, $includes for text and pick-any fields, and $exists for any key. GET /metadata-definitions lists the fields. 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, externalId, externalIds, reviewsCount, wishlistsCount, variantsCount, tags, variants.

Request
curl \
  "https://your-store.meisei.app/api/products" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "A4Ws1igz",
      "slug": "string",
      "title": "string",
      "description": "string",
      "imageUrl": "string",
      "url": "string",
      "brand": "string",
      "metadata": "...",
      "notes": "string",
      "averageRating": 0,
      "ratingCount": 0,
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "importJob": {
        "id": "...",
        "type": "...",
        "action": "...",
        "row": "...",
        "createdAt": "..."
      },
      "externalId": "string",
      "externalIds": ["..."],
      "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, or an exact list of ids, in one request. Sending neither applies the changes to every product in the organization. Each product whose tags or metadata actually change triggers the product.updated webhook.

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. Every word has to match, from the start of a word, in any order and ignoring case and accents, against the record's most identifying fields. Combined with filter using AND.

Body parameters

idsstring[]

The ids of the products to update, for changing an exact list. Combined with filter and search using AND when those are sent too.

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://your-store.meisei.app/api/products/bulk-update" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "ids": [
    "string"
  ],
  "addTags": [
    "string"
  ],
  "removeTags": [
    "string"
  ],
  "addMetadata": "...",
  "removeMetadataKeys": [
    "string"
  ]
}'
Response
{
  "count": 0
}

POST /products/import

Create or update products in bulk, matching on externalIds first and then 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. Each new product triggers the product.created webhook and each existing one product.updated.

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.

followSlugChangesboolean

When a row's external ID is already linked to a product with a different slug, whether that product takes the row's slug (when no other product holds it). On by default; off keeps the product's slug.

Request
curl \
  -X POST \
  "https://your-store.meisei.app/api/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",
      "brand": "string",
      "metadata": "...",
      "tags": [
        "..."
      ],
      "variants": [
        "..."
      ],
      "externalId": "string",
      "externalIds": [
        "..."
      ]
    }
  ],
  "strict": true,
  "mergeMetadata": true,
  "followSlugChanges": true
}'
Response
{
  "data": [
    {
      "id": "A4Ws1igz",
      "slug": "string",
      "title": "string",
      "description": "string",
      "imageUrl": "string",
      "url": "string",
      "brand": "string",
      "metadata": "...",
      "notes": "string",
      "averageRating": 0,
      "ratingCount": 0,
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "importJob": {
        "id": "...",
        "type": "...",
        "action": "...",
        "row": "...",
        "createdAt": "..."
      },
      "externalId": "string",
      "externalIds": ["..."],
      "reviewsCount": 0,
      "wishlistsCount": 0,
      "variantsCount": 0,
      "tags": ["..."],
      "variants": ["..."]
    }
  ],
  "skipped": [
    {
      "index": 0,
      "message": "string"
    }
  ]
}

GET /products/{id}

Get a single product. The product may be named by Meisei's ID or by its ID on one of your sites, such as a Shopify ID: Meisei's is tried first, then every site. Send by to say which kind it is, and site when the same external ID is on more than one of your sites (otherwise that answers 400).

Requires the products:read permission.

Path parameters

idstringrequired

The product's ID, or its ID on one of your sites. URL-encode a gid:// one.

Query parameters

byid | externalId

What the ID in the path is: id for Meisei's own ID, externalId for its ID on one of your sites (such as a Shopify ID, in either form). Leave it out to try Meisei's ID first and then every site.

sitestring

The slug of the site an external ID belongs to. Only needed when the same ID is on more than one of your sites.

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, externalId, externalIds, reviewsCount, wishlistsCount, variantsCount, tags, variants.

Request
curl \
  "https://your-store.meisei.app/api/products/A4Ws1igz" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "A4Ws1igz",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "brand": "string",
  "metadata": "...",
  "notes": "string",
  "averageRating": 0,
  "ratingCount": 0,
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "A4Ws1igz",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "externalId": "string",
  "externalIds": [
    {
      "site": "string",
      "id": "string"
    }
  ],
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "A4Ws1igz",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "gtin": "string",
      "mpn": "string",
      "metadata": "...",
      "externalId": "string",
      "externalIds": ["..."]
    }
  ]
}

PATCH /products/{id}

Update a product's metadata, notes, tags or brand. Catalog fields such as the title and slug come from the store and cannot be edited here. Triggers the product.updated webhook. The product may be named by Meisei's ID or by its ID on one of your sites, such as a Shopify ID: Meisei's is tried first, then every site. Send by to say which kind it is, and site when the same external ID is on more than one of your sites (otherwise that answers 400).

Requires the products:write permission.

Path parameters

idstringrequired

The product's ID, or its ID on one of your sites. URL-encode a gid:// one.

Query parameters

byid | externalId

What the ID in the path is: id for Meisei's own ID, externalId for its ID on one of your sites (such as a Shopify ID, in either form). Leave it out to try Meisei's ID first and then every site.

sitestring

The slug of the site an external ID belongs to. Only needed when the same ID is on more than one of your sites.

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.

brandstring | null

The product's brand. Send null to clear it, or omit it to leave it alone.

Request
curl \
  -X PATCH \
  "https://your-store.meisei.app/api/products/A4Ws1igz" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "metadata": "...",
  "notes": "string",
  "tags": [
    "string"
  ],
  "brand": "string"
}'
Response
{
  "id": "A4Ws1igz",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "brand": "string",
  "metadata": "...",
  "notes": "string",
  "averageRating": 0,
  "ratingCount": 0,
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "A4Ws1igz",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "externalId": "string",
  "externalIds": [
    {
      "site": "string",
      "id": "string"
    }
  ],
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "A4Ws1igz",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "gtin": "string",
      "mpn": "string",
      "metadata": "...",
      "externalId": "string",
      "externalIds": ["..."]
    }
  ]
}

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. The product may be named by Meisei's ID or by its ID on one of your sites, such as a Shopify ID: Meisei's is tried first, then every site. Send by to say which kind it is, and site when the same external ID is on more than one of your sites (otherwise that answers 400).

Requires the products:write permission.

Path parameters

idstringrequired

The product's ID, or its ID on one of your sites. URL-encode a gid:// one.

Query parameters

byid | externalId

What the ID in the path is: id for Meisei's own ID, externalId for its ID on one of your sites (such as a Shopify ID, in either form). Leave it out to try Meisei's ID first and then every site.

sitestring

The slug of the site an external ID belongs to. Only needed when the same ID is on more than one of your sites.

Request
curl \
  -X DELETE \
  "https://your-store.meisei.app/api/products/A4Ws1igz" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "A4Ws1igz",
  "slug": "string",
  "title": "string",
  "description": "string",
  "imageUrl": "string",
  "url": "string",
  "brand": "string",
  "metadata": "...",
  "notes": "string",
  "averageRating": 0,
  "ratingCount": 0,
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "importJob": {
    "id": "A4Ws1igz",
    "type": "customers",
    "action": "created",
    "row": 0,
    "createdAt": "2025-01-15T09:30:00Z"
  },
  "externalId": "string",
  "externalIds": [
    {
      "site": "string",
      "id": "string"
    }
  ],
  "reviewsCount": 0,
  "wishlistsCount": 0,
  "variantsCount": 0,
  "tags": ["string"],
  "variants": [
    {
      "id": "A4Ws1igz",
      "slug": "string",
      "title": "string",
      "imageUrl": "string",
      "priceCents": 0,
      "currencyCode": "string",
      "available": true,
      "gtin": "string",
      "mpn": "string",
      "metadata": "...",
      "externalId": "string",
      "externalIds": ["..."]
    }
  ]
}

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

Update a variant's metadata, GTIN or manufacturer part number. Triggers the productVariant.updated webhook.

Requires the products:write permission.

Path parameters

productIdstringrequired

The ID of the product the variant belongs to.

variantIdstringrequired

The ID of the variant to update.

Body parameters

metadataobject

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

gtinstring | null

The variant's GTIN: the 8, 12, 13 or 14 digits under its barcode. Send null to clear it, or omit it to leave it alone.

mpnstring | null

The variant's manufacturer part number. Send null to clear it, or omit it to leave it alone.

Request
curl \
  -X PATCH \
  "https://your-store.meisei.app/api/products/A4Ws1igz/variants/A4Ws1igz" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "metadata": "...",
  "gtin": "string",
  "mpn": "string"
}'
Response
{
  "id": "A4Ws1igz",
  "slug": "string",
  "title": "string",
  "imageUrl": "string",
  "priceCents": 0,
  "currencyCode": "string",
  "available": true,
  "gtin": "string",
  "mpn": "string",
  "metadata": "...",
  "externalId": "string",
  "externalIds": [
    {
      "site": "string",
      "id": "string"
    }
  ],
  "productId": "A4Ws1igz"
}