#Setup
GET /setup
Get the onboarding checklist: connect your store, set your branding, send review requests, set up a loyalty program, set up wishlists and install the widgets. Each step is done when the organization's own records show it (a connected store or a catalog, a site logo, the review request automation switched on, a loyalty program, a saved wishlist, a storefront that has loaded a widget) or when it was marked done. It also answers the signals those checks read, whether the checklist was hidden, the publishable key and widget URLs an install needs, and what Meisei learned by reading the first site's storefront, less the saved product page, which GET /setup/site-preview answers.
Requires the settings:read permission.
curl \
"https://your-store.meisei.app/api/setup" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getSetup } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getSetup()require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.setup.retrievefrom meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.setup.retrieve(){
"signals": {
"hasSite": true,
"hasPublishableKey": true,
"hasIntegration": true,
"hasProducts": true,
"hasBrandLogo": true,
"sendsReviewRequests": true,
"hasReview": true,
"hasLoyaltyProgram": true,
"loyaltyProgramOnSite": true,
"hasWishlist": true,
"widgetsSeen": true
},
"steps": {
"connectStore": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"branding": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"reviewRequests": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"loyalty": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"wishlists": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"widgets": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
}
},
"guideDismissedAt": "2025-01-15T09:30:00Z",
"widgetRequestHostname": "string",
"publishableKey": "string",
"embedScriptUrl": "string",
"apiBaseUrl": "string",
"siteAnalysis": {
"hostname": "string",
"status": "pending",
"platform": "shopify",
"brand": {
"siteName": "string",
"logoUrl": "string",
"fonts": {
"heading": "...",
"body": "..."
},
"theme": "..."
},
"productPageUrl": "string",
"pageKind": "product",
"insertionPoints": {
"rating": {
"selector": "...",
"position": "..."
},
"reviews": {
"selector": "...",
"position": "..."
},
"addToWishlist": {
"selector": "...",
"position": "..."
},
"wishlistNav": {
"selector": "...",
"position": "..."
}
},
"error": "string",
"requestedAt": "string",
"finishedAt": "string"
},
"siteAnalysisHostname": "string",
"siteAnalysisApplied": true,
"shopifyAppStoreUrl": "string"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"signals": {
"type": "object",
"properties": {
"hasSite": {
"type": "boolean",
"description": "Whether the organization has at least one site."
},
"hasPublishableKey": {
"type": "boolean",
"description": "Whether a publishable key exists for the storefront widgets to authenticate with."
},
"hasIntegration": {
"type": "boolean",
"description": "Whether a store is connected, which today means a Shopify store."
},
"hasProducts": {
"type": "boolean",
"description": "Whether any products have arrived, from a connected store or an import. Without them a review request has nothing to ask about and a loyalty rule has nothing to measure."
},
"hasBrandLogo": {
"type": "boolean",
"description": "Whether any site has a logo in its branding."
},
"sendsReviewRequests": {
"type": "boolean",
"description": "Whether Meisei sends review requests on its own, which is whether the review request automation is switched on."
},
"hasReview": {
"type": "boolean",
"description": "Whether any review has arrived, however it got here."
},
"hasLoyaltyProgram": {
"type": "boolean",
"description": "Whether a loyalty program exists, draft or live."
},
"loyaltyProgramOnSite": {
"type": "boolean",
"description": "Whether a loyalty program is attached to a site, which is what puts it on a storefront."
},
"hasWishlist": {
"type": "boolean",
"description": "Whether any shopper has saved a wishlist."
},
"widgetsSeen": {
"type": "boolean",
"description": "Whether a storefront has loaded a widget with the organization's publishable key, from a shopper's browser."
}
},
"required": [
"hasSite",
"hasPublishableKey",
"hasIntegration",
"hasProducts",
"hasBrandLogo",
"sendsReviewRequests",
"hasReview",
"hasLoyaltyProgram",
"loyaltyProgramOnSite",
"hasWishlist",
"widgetsSeen"
],
"additionalProperties": false,
"description": "What the organization's own records say, read in one query."
},
"steps": {
"type": "object",
"properties": {
"connectStore": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"branding": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"reviewRequests": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"loyalty": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"wishlists": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"widgets": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
}
},
"required": ["connectStore", "branding", "reviewRequests", "loyalty", "wishlists", "widgets"],
"additionalProperties": false,
"description": "The onboarding checklist, one entry per step: connect the store, set the branding, send review requests, set up a loyalty program, set up wishlists and install the widgets."
},
"guideDismissedAt": {
"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 checklist was hidden. Null means it is shown."
},
"widgetRequestHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The storefront that first loaded a widget, which is how the install step is detected. Null until one has."
},
"publishableKey": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The organization's publishable key, so an install screen can show the storefront snippet already filled in. Null when none has been created yet."
},
"embedScriptUrl": {
"type": "string",
"description": "Where the storefront widget bundle is published."
},
"apiBaseUrl": {
"type": "string",
"description": "The base URL the widgets should call: this organization's own host, under /api."
},
"siteAnalysis": {
"anyOf": [
{
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "The storefront's hostname, lowercased."
},
"status": {
"type": "string",
"enum": ["pending", "running", "ready", "failed"],
"description": "Where the analysis is. Pending and running are still on their way."
},
"platform": {
"anyOf": [
{
"type": "string",
"enum": ["shopify", "other"]
},
{
"type": "null"
}
],
"description": "The platform the storefront runs on, once it is known."
},
"brand": {
"anyOf": [
{
"type": "object",
"properties": {
"siteName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The store's own name, when it could be read."
},
"logoUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An absolute URL to the store's logo, when one was found."
},
"fonts": {
"type": "object",
"properties": {
"heading": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's headings use."
},
"body": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's body text uses."
}
},
"required": ["heading", "body"],
"additionalProperties": false
},
"theme": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Widget theme values read off the store, keyed by widget theme property (fontFamily, text, surface, accent, accentText, radius and so on). Only what could be read with confidence."
}
},
"required": ["siteName", "logoUrl", "fonts", "theme"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "The store's brand, when it could be read."
},
"productPageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The page that was saved: a product page, or a collection or home page when no product page would load. Null when none was."
},
"pageKind": {
"anyOf": [
{
"type": "string",
"enum": ["product", "collection", "home"]
},
{
"type": "null"
}
],
"description": "What the saved page is, or null when no page was saved."
},
"insertionPoints": {
"anyOf": [
{
"type": "object",
"properties": {
"rating": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"reviews": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"addToWishlist": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"wishlistNav": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Where each storefront widget could go on the saved product page."
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the analysis failed, in a sentence a merchant can read, when it did."
},
"requestedAt": {
"type": "string",
"description": "When the analysis was asked for, as an ISO timestamp."
},
"finishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "When it finished, as an ISO timestamp."
}
},
"required": [
"hostname",
"status",
"platform",
"brand",
"productPageUrl",
"pageKind",
"insertionPoints",
"error",
"requestedAt",
"finishedAt"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "What Meisei learned by reading the organization's first site: its platform, its brand and where the widgets could go. Null when there is no site, or when nobody has asked for the store to be read yet."
},
"siteAnalysisHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The hostname the analysis was looked up by, taken from the first site's address. Ask for an analysis of exactly this host when `siteAnalysis` is null. Null when there is no site."
},
"siteAnalysisApplied": {
"type": "boolean",
"description": "Whether the analysis of `siteAnalysisHostname` has already been applied to the organization. Once it has, applying it again does nothing, so there is no need to call it."
},
"shopifyAppStoreUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where the Meisei app is listed on the Shopify App Store, for a store that has not installed it yet. Null when this deployment has no Shopify app."
}
},
"required": [
"signals",
"steps",
"guideDismissedAt",
"widgetRequestHostname",
"publishableKey",
"embedScriptUrl",
"apiBaseUrl",
"siteAnalysis",
"siteAnalysisHostname",
"siteAnalysisApplied",
"shopifyAppStoreUrl"
],
"additionalProperties": false,
"description": "Where setup stands afterward."
}PATCH /setup
Mark onboarding steps done or uncheck them, and hide or show the checklist. Only what is sent changes. A step the organization's records already show as done stays done when it is unchecked, because nothing was marked to clear.
Requires the settings:write permission.
Body parameters
stepsobjectSteps to mark done or to uncheck. A step the records already show as done stays done whatever is sent.
dismissedbooleanTrue hides the checklist, false brings it back. The steps are kept either way.
curl \
-X PATCH \
"https://your-store.meisei.app/api/setup" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"steps": {
"connectStore": true,
"branding": true,
"reviewRequests": true,
"loyalty": true,
"wishlists": true,
"widgets": true
},
"dismissed": true
}'import { client } from "@meisei/api/admin/client"
import { patchSetup } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await patchSetup({
body: {
steps: {
connectStore: true,
branding: true,
reviewRequests: true,
loyalty: true,
wishlists: true,
widgets: true,
},
dismissed: true,
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.setup.update(
steps: {
connect_store: true,
branding: true,
review_requests: true,
loyalty: true,
wishlists: true,
widgets: true,
},
dismissed: true,
)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.setup.update(
steps={
"connect_store": True,
"branding": True,
"review_requests": True,
"loyalty": True,
"wishlists": True,
"widgets": True,
},
dismissed=True,
){
"signals": {
"hasSite": true,
"hasPublishableKey": true,
"hasIntegration": true,
"hasProducts": true,
"hasBrandLogo": true,
"sendsReviewRequests": true,
"hasReview": true,
"hasLoyaltyProgram": true,
"loyaltyProgramOnSite": true,
"hasWishlist": true,
"widgetsSeen": true
},
"steps": {
"connectStore": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"branding": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"reviewRequests": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"loyalty": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"wishlists": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
},
"widgets": {
"completedAt": "2025-01-15T09:30:00Z",
"detected": true,
"done": true
}
},
"guideDismissedAt": "2025-01-15T09:30:00Z",
"widgetRequestHostname": "string",
"publishableKey": "string",
"embedScriptUrl": "string",
"apiBaseUrl": "string",
"siteAnalysis": {
"hostname": "string",
"status": "pending",
"platform": "shopify",
"brand": {
"siteName": "string",
"logoUrl": "string",
"fonts": {
"heading": "...",
"body": "..."
},
"theme": "..."
},
"productPageUrl": "string",
"pageKind": "product",
"insertionPoints": {
"rating": {
"selector": "...",
"position": "..."
},
"reviews": {
"selector": "...",
"position": "..."
},
"addToWishlist": {
"selector": "...",
"position": "..."
},
"wishlistNav": {
"selector": "...",
"position": "..."
}
},
"error": "string",
"requestedAt": "string",
"finishedAt": "string"
},
"siteAnalysisHostname": "string",
"siteAnalysisApplied": true,
"shopifyAppStoreUrl": "string"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"signals": {
"type": "object",
"properties": {
"hasSite": {
"type": "boolean",
"description": "Whether the organization has at least one site."
},
"hasPublishableKey": {
"type": "boolean",
"description": "Whether a publishable key exists for the storefront widgets to authenticate with."
},
"hasIntegration": {
"type": "boolean",
"description": "Whether a store is connected, which today means a Shopify store."
},
"hasProducts": {
"type": "boolean",
"description": "Whether any products have arrived, from a connected store or an import. Without them a review request has nothing to ask about and a loyalty rule has nothing to measure."
},
"hasBrandLogo": {
"type": "boolean",
"description": "Whether any site has a logo in its branding."
},
"sendsReviewRequests": {
"type": "boolean",
"description": "Whether Meisei sends review requests on its own, which is whether the review request automation is switched on."
},
"hasReview": {
"type": "boolean",
"description": "Whether any review has arrived, however it got here."
},
"hasLoyaltyProgram": {
"type": "boolean",
"description": "Whether a loyalty program exists, draft or live."
},
"loyaltyProgramOnSite": {
"type": "boolean",
"description": "Whether a loyalty program is attached to a site, which is what puts it on a storefront."
},
"hasWishlist": {
"type": "boolean",
"description": "Whether any shopper has saved a wishlist."
},
"widgetsSeen": {
"type": "boolean",
"description": "Whether a storefront has loaded a widget with the organization's publishable key, from a shopper's browser."
}
},
"required": [
"hasSite",
"hasPublishableKey",
"hasIntegration",
"hasProducts",
"hasBrandLogo",
"sendsReviewRequests",
"hasReview",
"hasLoyaltyProgram",
"loyaltyProgramOnSite",
"hasWishlist",
"widgetsSeen"
],
"additionalProperties": false,
"description": "What the organization's own records say, read in one query."
},
"steps": {
"type": "object",
"properties": {
"connectStore": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"branding": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"reviewRequests": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"loyalty": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"wishlists": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"widgets": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
}
},
"required": ["connectStore", "branding", "reviewRequests", "loyalty", "wishlists", "widgets"],
"additionalProperties": false,
"description": "The onboarding checklist, one entry per step: connect the store, set the branding, send review requests, set up a loyalty program, set up wishlists and install the widgets."
},
"guideDismissedAt": {
"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 checklist was hidden. Null means it is shown."
},
"widgetRequestHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The storefront that first loaded a widget, which is how the install step is detected. Null until one has."
},
"publishableKey": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The organization's publishable key, so an install screen can show the storefront snippet already filled in. Null when none has been created yet."
},
"embedScriptUrl": {
"type": "string",
"description": "Where the storefront widget bundle is published."
},
"apiBaseUrl": {
"type": "string",
"description": "The base URL the widgets should call: this organization's own host, under /api."
},
"siteAnalysis": {
"anyOf": [
{
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "The storefront's hostname, lowercased."
},
"status": {
"type": "string",
"enum": ["pending", "running", "ready", "failed"],
"description": "Where the analysis is. Pending and running are still on their way."
},
"platform": {
"anyOf": [
{
"type": "string",
"enum": ["shopify", "other"]
},
{
"type": "null"
}
],
"description": "The platform the storefront runs on, once it is known."
},
"brand": {
"anyOf": [
{
"type": "object",
"properties": {
"siteName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The store's own name, when it could be read."
},
"logoUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An absolute URL to the store's logo, when one was found."
},
"fonts": {
"type": "object",
"properties": {
"heading": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's headings use."
},
"body": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's body text uses."
}
},
"required": ["heading", "body"],
"additionalProperties": false
},
"theme": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Widget theme values read off the store, keyed by widget theme property (fontFamily, text, surface, accent, accentText, radius and so on). Only what could be read with confidence."
}
},
"required": ["siteName", "logoUrl", "fonts", "theme"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "The store's brand, when it could be read."
},
"productPageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The page that was saved: a product page, or a collection or home page when no product page would load. Null when none was."
},
"pageKind": {
"anyOf": [
{
"type": "string",
"enum": ["product", "collection", "home"]
},
{
"type": "null"
}
],
"description": "What the saved page is, or null when no page was saved."
},
"insertionPoints": {
"anyOf": [
{
"type": "object",
"properties": {
"rating": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"reviews": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"addToWishlist": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"wishlistNav": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Where each storefront widget could go on the saved product page."
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the analysis failed, in a sentence a merchant can read, when it did."
},
"requestedAt": {
"type": "string",
"description": "When the analysis was asked for, as an ISO timestamp."
},
"finishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "When it finished, as an ISO timestamp."
}
},
"required": [
"hostname",
"status",
"platform",
"brand",
"productPageUrl",
"pageKind",
"insertionPoints",
"error",
"requestedAt",
"finishedAt"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "What Meisei learned by reading the organization's first site: its platform, its brand and where the widgets could go. Null when there is no site, or when nobody has asked for the store to be read yet."
},
"siteAnalysisHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The hostname the analysis was looked up by, taken from the first site's address. Ask for an analysis of exactly this host when `siteAnalysis` is null. Null when there is no site."
},
"siteAnalysisApplied": {
"type": "boolean",
"description": "Whether the analysis of `siteAnalysisHostname` has already been applied to the organization. Once it has, applying it again does nothing, so there is no need to call it."
},
"shopifyAppStoreUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where the Meisei app is listed on the Shopify App Store, for a store that has not installed it yet. Null when this deployment has no Shopify app."
}
},
"required": [
"signals",
"steps",
"guideDismissedAt",
"widgetRequestHostname",
"publishableKey",
"embedScriptUrl",
"apiBaseUrl",
"siteAnalysis",
"siteAnalysisHostname",
"siteAnalysisApplied",
"shopifyAppStoreUrl"
],
"additionalProperties": false,
"description": "Where setup stands afterward."
}GET /setup/site-preview
Get the product page Meisei saved from the first site's storefront, with the places the widgets could go on it, so the widgets can be previewed on the store's own page. It is a 404 when there is no site, when the store has not been read, or when the read is still running or found no product page.
Requires the settings:read permission.
curl \
"https://your-store.meisei.app/api/setup/site-preview" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getSetupSitePreview } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getSetupSitePreview()require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.setup.site_previewfrom meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.setup.site_preview(){
"hostname": "string",
"productPageUrl": "string",
"pageKind": "product",
"html": "string",
"insertionPoints": {
"rating": {
"selector": "string",
"position": "before"
},
"reviews": {
"selector": "string",
"position": "before"
},
"addToWishlist": {
"selector": "string",
"position": "before"
},
"wishlistNav": {
"selector": "string",
"position": "before"
}
}
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "The storefront's hostname, lowercased."
},
"productPageUrl": {
"type": "string",
"description": "The address of the page that was saved: a product page, or a collection or home page when no product page would load."
},
"pageKind": {
"type": "string",
"enum": ["product", "collection", "home"],
"description": "What the saved page is: product, collection or home."
},
"html": {
"type": "string",
"description": "The saved page, with scripts and event handlers taken out and a base address pointing back at the store, so its styles and images still load."
},
"insertionPoints": {
"anyOf": [
{
"type": "object",
"properties": {
"rating": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"reviews": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"addToWishlist": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"wishlistNav": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Where each storefront widget could go on the saved page. Null when no places were found."
}
},
"required": ["hostname", "productPageUrl", "pageKind", "html", "insertionPoints"],
"additionalProperties": false,
"description": "One of the store's own pages (a product page when one would load), saved so the widgets can be previewed on it."
}POST /setup/apply-site-analysis
Copy what Meisei learned from the first site's storefront onto your records. The store's colors, font and corner radius become the site's widget appearance, but only while that appearance is untouched: anything you have already changed is left alone. With rename, the site and the organization also take the store's own name. It applies once per storefront address: after the first call for that address, calling it again changes nothing, even if you have since reset the appearance, and GET /setup reports siteAnalysisApplied.
Requires the settings:write permission.
Body parameters
renamebooleanWhether to rename the first site and the organization to the store's own name, when it could be read. Leave it off once the organization has a name somebody chose.
curl \
-X POST \
"https://your-store.meisei.app/api/setup/apply-site-analysis" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"rename": false
}'import { client } from "@meisei/api/admin/client"
import { postSetupApplySiteAnalysis } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await postSetupApplySiteAnalysis({
body: {
rename: false,
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.setup.apply_site_analysis(rename: false)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.setup.apply_site_analysis(rename=False){
"data": {
"signals": {
"hasSite": true,
"hasPublishableKey": true,
"hasIntegration": true,
"hasProducts": true,
"hasBrandLogo": true,
"sendsReviewRequests": true,
"hasReview": true,
"hasLoyaltyProgram": true,
"loyaltyProgramOnSite": true,
"hasWishlist": true,
"widgetsSeen": true
},
"steps": {
"connectStore": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"branding": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"reviewRequests": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"loyalty": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"wishlists": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"widgets": {
"completedAt": "...",
"detected": "...",
"done": "..."
}
},
"guideDismissedAt": "2025-01-15T09:30:00Z",
"widgetRequestHostname": "string",
"publishableKey": "string",
"embedScriptUrl": "string",
"apiBaseUrl": "string",
"siteAnalysis": {
"hostname": "string",
"status": "pending",
"platform": "shopify",
"brand": {
"siteName": "...",
"logoUrl": "...",
"fonts": "...",
"theme": "..."
},
"productPageUrl": "string",
"pageKind": "product",
"insertionPoints": {
"rating": "...",
"reviews": "...",
"addToWishlist": "...",
"wishlistNav": "..."
},
"error": "string",
"requestedAt": "string",
"finishedAt": "string"
},
"siteAnalysisHostname": "string",
"siteAnalysisApplied": true,
"shopifyAppStoreUrl": "string"
},
"themeApplied": true,
"renamed": true
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"signals": {
"type": "object",
"properties": {
"hasSite": {
"type": "boolean",
"description": "Whether the organization has at least one site."
},
"hasPublishableKey": {
"type": "boolean",
"description": "Whether a publishable key exists for the storefront widgets to authenticate with."
},
"hasIntegration": {
"type": "boolean",
"description": "Whether a store is connected, which today means a Shopify store."
},
"hasProducts": {
"type": "boolean",
"description": "Whether any products have arrived, from a connected store or an import. Without them a review request has nothing to ask about and a loyalty rule has nothing to measure."
},
"hasBrandLogo": {
"type": "boolean",
"description": "Whether any site has a logo in its branding."
},
"sendsReviewRequests": {
"type": "boolean",
"description": "Whether Meisei sends review requests on its own, which is whether the review request automation is switched on."
},
"hasReview": {
"type": "boolean",
"description": "Whether any review has arrived, however it got here."
},
"hasLoyaltyProgram": {
"type": "boolean",
"description": "Whether a loyalty program exists, draft or live."
},
"loyaltyProgramOnSite": {
"type": "boolean",
"description": "Whether a loyalty program is attached to a site, which is what puts it on a storefront."
},
"hasWishlist": {
"type": "boolean",
"description": "Whether any shopper has saved a wishlist."
},
"widgetsSeen": {
"type": "boolean",
"description": "Whether a storefront has loaded a widget with the organization's publishable key, from a shopper's browser."
}
},
"required": [
"hasSite",
"hasPublishableKey",
"hasIntegration",
"hasProducts",
"hasBrandLogo",
"sendsReviewRequests",
"hasReview",
"hasLoyaltyProgram",
"loyaltyProgramOnSite",
"hasWishlist",
"widgetsSeen"
],
"additionalProperties": false,
"description": "What the organization's own records say, read in one query."
},
"steps": {
"type": "object",
"properties": {
"connectStore": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"branding": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"reviewRequests": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"loyalty": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"wishlists": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"widgets": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
}
},
"required": [
"connectStore",
"branding",
"reviewRequests",
"loyalty",
"wishlists",
"widgets"
],
"additionalProperties": false,
"description": "The onboarding checklist, one entry per step: connect the store, set the branding, send review requests, set up a loyalty program, set up wishlists and install the widgets."
},
"guideDismissedAt": {
"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 checklist was hidden. Null means it is shown."
},
"widgetRequestHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The storefront that first loaded a widget, which is how the install step is detected. Null until one has."
},
"publishableKey": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The organization's publishable key, so an install screen can show the storefront snippet already filled in. Null when none has been created yet."
},
"embedScriptUrl": {
"type": "string",
"description": "Where the storefront widget bundle is published."
},
"apiBaseUrl": {
"type": "string",
"description": "The base URL the widgets should call: this organization's own host, under /api."
},
"siteAnalysis": {
"anyOf": [
{
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "The storefront's hostname, lowercased."
},
"status": {
"type": "string",
"enum": ["pending", "running", "ready", "failed"],
"description": "Where the analysis is. Pending and running are still on their way."
},
"platform": {
"anyOf": [
{
"type": "string",
"enum": ["shopify", "other"]
},
{
"type": "null"
}
],
"description": "The platform the storefront runs on, once it is known."
},
"brand": {
"anyOf": [
{
"type": "object",
"properties": {
"siteName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The store's own name, when it could be read."
},
"logoUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An absolute URL to the store's logo, when one was found."
},
"fonts": {
"type": "object",
"properties": {
"heading": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's headings use."
},
"body": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's body text uses."
}
},
"required": ["heading", "body"],
"additionalProperties": false
},
"theme": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Widget theme values read off the store, keyed by widget theme property (fontFamily, text, surface, accent, accentText, radius and so on). Only what could be read with confidence."
}
},
"required": ["siteName", "logoUrl", "fonts", "theme"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "The store's brand, when it could be read."
},
"productPageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The page that was saved: a product page, or a collection or home page when no product page would load. Null when none was."
},
"pageKind": {
"anyOf": [
{
"type": "string",
"enum": ["product", "collection", "home"]
},
{
"type": "null"
}
],
"description": "What the saved page is, or null when no page was saved."
},
"insertionPoints": {
"anyOf": [
{
"type": "object",
"properties": {
"rating": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"reviews": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"addToWishlist": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"wishlistNav": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Where each storefront widget could go on the saved product page."
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the analysis failed, in a sentence a merchant can read, when it did."
},
"requestedAt": {
"type": "string",
"description": "When the analysis was asked for, as an ISO timestamp."
},
"finishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "When it finished, as an ISO timestamp."
}
},
"required": [
"hostname",
"status",
"platform",
"brand",
"productPageUrl",
"pageKind",
"insertionPoints",
"error",
"requestedAt",
"finishedAt"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "What Meisei learned by reading the organization's first site: its platform, its brand and where the widgets could go. Null when there is no site, or when nobody has asked for the store to be read yet."
},
"siteAnalysisHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The hostname the analysis was looked up by, taken from the first site's address. Ask for an analysis of exactly this host when `siteAnalysis` is null. Null when there is no site."
},
"siteAnalysisApplied": {
"type": "boolean",
"description": "Whether the analysis of `siteAnalysisHostname` has already been applied to the organization. Once it has, applying it again does nothing, so there is no need to call it."
},
"shopifyAppStoreUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where the Meisei app is listed on the Shopify App Store, for a store that has not installed it yet. Null when this deployment has no Shopify app."
}
},
"required": [
"signals",
"steps",
"guideDismissedAt",
"widgetRequestHostname",
"publishableKey",
"embedScriptUrl",
"apiBaseUrl",
"siteAnalysis",
"siteAnalysisHostname",
"siteAnalysisApplied",
"shopifyAppStoreUrl"
],
"additionalProperties": false,
"description": "Where setup stands afterward."
},
"themeApplied": {
"type": "boolean",
"description": "Whether this call wrote the store's theme onto the site's widget appearance."
},
"renamed": {
"type": "boolean",
"description": "Whether this call renamed the site or the organization to the store's name."
}
},
"required": ["data", "themeApplied", "renamed"],
"additionalProperties": false
}POST /setup/loyalty
Set a loyalty program up from a handful of answers. Every answer writes a working example rather than only turning a section on: points bring an earning rule, a welcome bonus and one redemption, and offers bring an offer. The program is attached to every site you have, and is created as a draft, so publish it when you are ready for shoppers to see it. Members are enrolled the first time they do something the program rewards.
Requires the settings:write permission.
Body parameters
pointsbooleanrequiredWhether the program runs on points. With points off members still get offers, and nothing accrues a balance.
pointsPerDollarnumberHow many points a whole unit of order value earns. Ignored when points are off.
offersbooleanrequiredWhether members can claim offers. Turning this on shows the offers section and creates one offer to start from.
curl \
-X POST \
"https://your-store.meisei.app/api/setup/loyalty" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"points": true,
"pointsPerDollar": 1,
"offers": true
}'import { client } from "@meisei/api/admin/client"
import { postSetupLoyalty } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await postSetupLoyalty({
body: {
points: true,
pointsPerDollar: 1,
offers: true,
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.setup.loyalty(points: true, points_per_dollar: 1, offers: true)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.setup.loyalty(points=True, points_per_dollar=1, offers=True){
"data": {
"signals": {
"hasSite": true,
"hasPublishableKey": true,
"hasIntegration": true,
"hasProducts": true,
"hasBrandLogo": true,
"sendsReviewRequests": true,
"hasReview": true,
"hasLoyaltyProgram": true,
"loyaltyProgramOnSite": true,
"hasWishlist": true,
"widgetsSeen": true
},
"steps": {
"connectStore": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"branding": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"reviewRequests": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"loyalty": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"wishlists": {
"completedAt": "...",
"detected": "...",
"done": "..."
},
"widgets": {
"completedAt": "...",
"detected": "...",
"done": "..."
}
},
"guideDismissedAt": "2025-01-15T09:30:00Z",
"widgetRequestHostname": "string",
"publishableKey": "string",
"embedScriptUrl": "string",
"apiBaseUrl": "string",
"siteAnalysis": {
"hostname": "string",
"status": "pending",
"platform": "shopify",
"brand": {
"siteName": "...",
"logoUrl": "...",
"fonts": "...",
"theme": "..."
},
"productPageUrl": "string",
"pageKind": "product",
"insertionPoints": {
"rating": "...",
"reviews": "...",
"addToWishlist": "...",
"wishlistNav": "..."
},
"error": "string",
"requestedAt": "string",
"finishedAt": "string"
},
"siteAnalysisHostname": "string",
"siteAnalysisApplied": true,
"shopifyAppStoreUrl": "string"
},
"program": {
"id": "A4Ws1igz",
"name": "string",
"autoMembership": "off",
"settings": {
"previousPointsNames": null
},
"sectionsEnabled": {
"rules": true,
"offers": true
},
"pointsNames": {
"singular": "string",
"plural": "string"
},
"pointsExpiresAfterDays": 0,
"pointsBalancesExpireAt": "2025-01-15T09:30:00Z",
"rewardsExpireAfterDays": 0,
"expiringSoonDays": 0,
"pausedAt": "2025-01-15T09:30:00Z",
"publishedAt": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
},
"rules": [
{
"id": "A4Ws1igz",
"loyaltyProgramId": "A4Ws1igz",
"section": "rules",
"name": "string",
"trigger": {
"type": "..."
},
"reward": {
"type": "...",
"amount": "..."
},
"maxRedemptionsPerCustomer": 0,
"maxAvailableCount": 0,
"availableCount": 0,
"availableFrom": "2025-01-15T09:30:00Z",
"availableTo": "2025-01-15T09:30:00Z",
"filter": "...",
"metadata": "...",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}
],
"sites": [
{
"id": "A4Ws1igz",
"siteId": "A4Ws1igz",
"siteName": "string",
"siteSlug": "string",
"loyaltyProgramId": "A4Ws1igz",
"programUrl": "string",
"createdAt": "2025-01-15T09:30:00Z"
}
]
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"signals": {
"type": "object",
"properties": {
"hasSite": {
"type": "boolean",
"description": "Whether the organization has at least one site."
},
"hasPublishableKey": {
"type": "boolean",
"description": "Whether a publishable key exists for the storefront widgets to authenticate with."
},
"hasIntegration": {
"type": "boolean",
"description": "Whether a store is connected, which today means a Shopify store."
},
"hasProducts": {
"type": "boolean",
"description": "Whether any products have arrived, from a connected store or an import. Without them a review request has nothing to ask about and a loyalty rule has nothing to measure."
},
"hasBrandLogo": {
"type": "boolean",
"description": "Whether any site has a logo in its branding."
},
"sendsReviewRequests": {
"type": "boolean",
"description": "Whether Meisei sends review requests on its own, which is whether the review request automation is switched on."
},
"hasReview": {
"type": "boolean",
"description": "Whether any review has arrived, however it got here."
},
"hasLoyaltyProgram": {
"type": "boolean",
"description": "Whether a loyalty program exists, draft or live."
},
"loyaltyProgramOnSite": {
"type": "boolean",
"description": "Whether a loyalty program is attached to a site, which is what puts it on a storefront."
},
"hasWishlist": {
"type": "boolean",
"description": "Whether any shopper has saved a wishlist."
},
"widgetsSeen": {
"type": "boolean",
"description": "Whether a storefront has loaded a widget with the organization's publishable key, from a shopper's browser."
}
},
"required": [
"hasSite",
"hasPublishableKey",
"hasIntegration",
"hasProducts",
"hasBrandLogo",
"sendsReviewRequests",
"hasReview",
"hasLoyaltyProgram",
"loyaltyProgramOnSite",
"hasWishlist",
"widgetsSeen"
],
"additionalProperties": false,
"description": "What the organization's own records say, read in one query."
},
"steps": {
"type": "object",
"properties": {
"connectStore": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"branding": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"reviewRequests": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"loyalty": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"wishlists": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
},
"widgets": {
"type": "object",
"properties": {
"completedAt": {
"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 step was marked done, by hand or by saving the settings it is about. Null means it has not been. Unchecking the step clears it."
},
"detected": {
"type": "boolean",
"description": "Whether the organization's records show the step is done, whatever was marked. A detected step cannot be unchecked."
},
"done": {
"type": "boolean",
"description": "Whether the step is done: detected, or marked done."
}
},
"required": ["completedAt", "detected", "done"],
"additionalProperties": false,
"description": "Where one onboarding step stands."
}
},
"required": [
"connectStore",
"branding",
"reviewRequests",
"loyalty",
"wishlists",
"widgets"
],
"additionalProperties": false,
"description": "The onboarding checklist, one entry per step: connect the store, set the branding, send review requests, set up a loyalty program, set up wishlists and install the widgets."
},
"guideDismissedAt": {
"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 checklist was hidden. Null means it is shown."
},
"widgetRequestHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The storefront that first loaded a widget, which is how the install step is detected. Null until one has."
},
"publishableKey": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The organization's publishable key, so an install screen can show the storefront snippet already filled in. Null when none has been created yet."
},
"embedScriptUrl": {
"type": "string",
"description": "Where the storefront widget bundle is published."
},
"apiBaseUrl": {
"type": "string",
"description": "The base URL the widgets should call: this organization's own host, under /api."
},
"siteAnalysis": {
"anyOf": [
{
"type": "object",
"properties": {
"hostname": {
"type": "string",
"description": "The storefront's hostname, lowercased."
},
"status": {
"type": "string",
"enum": ["pending", "running", "ready", "failed"],
"description": "Where the analysis is. Pending and running are still on their way."
},
"platform": {
"anyOf": [
{
"type": "string",
"enum": ["shopify", "other"]
},
{
"type": "null"
}
],
"description": "The platform the storefront runs on, once it is known."
},
"brand": {
"anyOf": [
{
"type": "object",
"properties": {
"siteName": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The store's own name, when it could be read."
},
"logoUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "An absolute URL to the store's logo, when one was found."
},
"fonts": {
"type": "object",
"properties": {
"heading": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's headings use."
},
"body": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The font family the store's body text uses."
}
},
"required": ["heading", "body"],
"additionalProperties": false
},
"theme": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"type": "string"
},
"description": "Widget theme values read off the store, keyed by widget theme property (fontFamily, text, surface, accent, accentText, radius and so on). Only what could be read with confidence."
}
},
"required": ["siteName", "logoUrl", "fonts", "theme"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "The store's brand, when it could be read."
},
"productPageUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The page that was saved: a product page, or a collection or home page when no product page would load. Null when none was."
},
"pageKind": {
"anyOf": [
{
"type": "string",
"enum": ["product", "collection", "home"]
},
{
"type": "null"
}
],
"description": "What the saved page is, or null when no page was saved."
},
"insertionPoints": {
"anyOf": [
{
"type": "object",
"properties": {
"rating": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"reviews": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"addToWishlist": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
},
"wishlistNav": {
"type": "object",
"properties": {
"selector": {
"type": "string",
"description": "A CSS selector that matches exactly one element of the saved product page."
},
"position": {
"type": "string",
"enum": ["before", "after", "prepend", "append"],
"description": "Where the widget goes relative to that element."
}
},
"required": ["selector", "position"],
"additionalProperties": false
}
},
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Where each storefront widget could go on the saved product page."
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the analysis failed, in a sentence a merchant can read, when it did."
},
"requestedAt": {
"type": "string",
"description": "When the analysis was asked for, as an ISO timestamp."
},
"finishedAt": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "When it finished, as an ISO timestamp."
}
},
"required": [
"hostname",
"status",
"platform",
"brand",
"productPageUrl",
"pageKind",
"insertionPoints",
"error",
"requestedAt",
"finishedAt"
],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "What Meisei learned by reading the organization's first site: its platform, its brand and where the widgets could go. Null when there is no site, or when nobody has asked for the store to be read yet."
},
"siteAnalysisHostname": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The hostname the analysis was looked up by, taken from the first site's address. Ask for an analysis of exactly this host when `siteAnalysis` is null. Null when there is no site."
},
"siteAnalysisApplied": {
"type": "boolean",
"description": "Whether the analysis of `siteAnalysisHostname` has already been applied to the organization. Once it has, applying it again does nothing, so there is no need to call it."
},
"shopifyAppStoreUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Where the Meisei app is listed on the Shopify App Store, for a store that has not installed it yet. Null when this deployment has no Shopify app."
}
},
"required": [
"signals",
"steps",
"guideDismissedAt",
"widgetRequestHostname",
"publishableKey",
"embedScriptUrl",
"apiBaseUrl",
"siteAnalysis",
"siteAnalysisHostname",
"siteAnalysisApplied",
"shopifyAppStoreUrl"
],
"additionalProperties": false,
"description": "Where setup stands afterward."
},
"program": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the loyalty program.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The program's display name, shown to members."
},
"autoMembership": {
"type": "string",
"enum": ["off", "onFirstActivity"],
"description": "When customers are enrolled in the program automatically. `off` means they join only when enrolled explicitly; `onFirstActivity` enrolls them the first time they do something the program rewards."
},
"settings": {
"type": "object",
"properties": {
"previousPointsNames": {
"default": null,
"description": "The names the points had before they were switched off, kept so switching them back on restores them. Null when points have never been switched off.",
"anyOf": [
{
"type": "object",
"properties": {
"singular": {
"type": "string",
"minLength": 1,
"description": "The name of one point, such as `point`."
},
"plural": {
"type": "string",
"minLength": 1,
"description": "The name of several points, such as `points`."
}
},
"required": ["singular", "plural"],
"additionalProperties": false,
"description": "Unit names a balance is composed from, for example `12 points`."
},
{
"type": "null"
}
]
}
},
"required": ["previousPointsNames"],
"additionalProperties": false,
"description": "Program-level configuration: the points names kept from before points were switched off."
},
"sectionsEnabled": {
"type": "object",
"properties": {
"rules": {
"type": "boolean",
"description": "Whether the ways-to-earn section is shown to members."
},
"offers": {
"type": "boolean",
"description": "Whether the offers section is shown to members."
}
},
"required": ["rules", "offers"],
"additionalProperties": false,
"description": "Which optional sections members see in the loyalty widget."
},
"pointsNames": {
"anyOf": [
{
"type": "object",
"properties": {
"singular": {
"type": "string",
"minLength": 1,
"description": "The name of one point, such as `point`."
},
"plural": {
"type": "string",
"minLength": 1,
"description": "The name of several points, such as `points`."
}
},
"required": ["singular", "plural"],
"additionalProperties": false,
"description": "Unit names a balance is composed from, for example `12 points`."
},
{
"type": "null"
}
],
"description": "What the program calls its points, singular and plural. Null means the program has no points, so nothing earns, spends or displays them."
},
"pointsExpiresAfterDays": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Each earn expires this many days after it happened. Null means earns never age out. When `pointsBalancesExpireAt` is also set, the earlier of the two applies."
},
"pointsBalancesExpireAt": {
"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": "Every points balance in the program expires at this moment, the event-tickets case. Null means balances have no fixed end date. When `pointsExpiresAfterDays` is also set, the earlier of the two applies."
},
"rewardsExpireAfterDays": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Rewards issued in this program lapse this many days after a member gets them. Null means they stay redeemable until they are used. A rule that sets its own expiry wins over this."
},
"expiringSoonDays": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "How many days of warning members get before a reward or a points balance lapses. Null means no warning goes out."
},
"pausedAt": {
"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 program was paused. While it is set the program earns nothing, and members keep their balances, rewards and history."
},
"publishedAt": {
"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 program was published. Null means it is still a draft: no shopper can see it, join it or earn in it, and only a preview link reaches it. Publishing cannot be undone, so pause a program you want to take down."
},
"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 program was created."
},
"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 program was last changed."
}
},
"required": [
"id",
"name",
"autoMembership",
"settings",
"sectionsEnabled",
"pointsNames",
"pointsExpiresAfterDays",
"pointsBalancesExpireAt",
"rewardsExpireAfterDays",
"expiringSoonDays",
"pausedAt",
"publishedAt",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The program that was created, still a draft."
},
"rules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the rule.",
"idCodec": "sqid"
},
"loyaltyProgramId": {
"type": "string",
"description": "The loyalty program the rule belongs to.",
"idCodec": "sqid"
},
"section": {
"type": "string",
"enum": ["rules", "rewards", "offers"],
"description": "Which section of the loyalty widget the rule is presented in."
},
"name": {
"type": "string",
"description": "The rule's display name, shown to members."
},
"trigger": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "joinProgram",
"description": "Fires when a customer joins the loyalty program."
}
},
"required": ["type"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "pointsSpent",
"description": "Fires when a customer redeems points."
},
"unitAmount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many points make up one unit of the reward."
},
"variableAmount": {
"type": "boolean",
"description": "Whether the customer chooses how many points to spend."
}
},
"required": ["type", "unitAmount", "variableAmount"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "purchase",
"description": "Fires when a customer places an order."
},
"variableAmount": {
"type": "boolean",
"description": "Whether the reward scales with the amount spent rather than being flat."
},
"basis": {
"type": "string",
"enum": ["subtotal", "total"],
"description": "The order amount earning is computed from. `subtotal` is the discounted subtotal excluding shipping and tax, falling back to the total when an order does not carry one; `total` is the order total. Omitted means `subtotal`."
},
"productFilter": {
"anyOf": [
{
"type": "object",
"properties": {
"slugs": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product slugs the reward applies to."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product tag names the reward applies to."
}
},
"required": ["slugs", "tags"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Restricts the rule to matching products. Null means any product qualifies."
}
},
"required": ["type", "variableAmount", "productFilter"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "customEvent",
"description": "Fires when your own system reports a named event to `POST /loyalty-events`."
},
"eventName": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,99}$",
"description": "The name of the event that fires the rule. Several rules can listen for the same name."
},
"conditions": {
"description": "Conditions on the event's properties that have to hold, such as `{ \"rating\": { \"$gte\": 4 } }`. Omitted or null means every event with the name counts.",
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"anyOf": [
{
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
],
"description": "The property has to equal this value."
},
{
"type": "object",
"properties": {
"$eq": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"$ne": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
},
"$in": {
"minItems": 1,
"maxItems": 50,
"type": "array",
"items": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
}
]
}
},
"$gt": {
"type": "number"
},
"$gte": {
"type": "number"
},
"$lt": {
"type": "number"
},
"$lte": {
"type": "number"
},
"$exists": {
"type": "boolean"
}
},
"additionalProperties": false,
"description": "Operators the property has to satisfy, all of them: `$eq`, `$ne`, `$in`, `$gt`, `$gte`, `$lt`, `$lte` and `$exists`."
}
]
},
"description": "Conditions on the event's properties, keyed by property name. Every condition has to hold for the rule to fire. A value on its own means equality; numbers compare as numbers and strings as strings, so send each property with one type."
},
{
"type": "null"
}
]
},
"every": {
"description": "Fires on every Nth matching event the customer sends rather than on each one: 10 means the 10th, 20th and 30th. This is how a punch card works. Omitted means every matching event fires.",
"type": "integer",
"minimum": 1,
"maximum": 1000
},
"limit": {
"description": "Caps how often the rule fires for one customer within a calendar period. Omitted means no periodic cap.",
"type": "object",
"properties": {
"period": {
"type": "string",
"enum": ["day", "week", "month"],
"description": "The window the allowance resets on, in the organization's time zone."
},
"count": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How many times per period the rule can fire for one customer."
}
},
"required": ["period", "count"],
"additionalProperties": false
},
"variableAmount": {
"description": "Whether the reward scales with the `value` the event carries rather than being flat. Omitted means flat. Only points, fixed-amount coupons and gift cards can scale.",
"type": "boolean"
},
"defaultValue": {
"description": "The value used when an event leaves `value` out. Omitted means one, so the rule awards its reward once.",
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
}
},
"required": ["type", "eventName"],
"additionalProperties": false
}
],
"description": "What has to happen for the rule to award its reward."
},
"reward": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "points",
"description": "Credits the customer with loyalty points."
},
"amount": {
"type": "number",
"description": "How many points to credit."
}
},
"required": ["type", "amount"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "amountCoupon",
"description": "Issues a fixed-value discount coupon."
},
"amountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Face value of the coupon, in cents."
},
"productFilter": {
"anyOf": [
{
"type": "object",
"properties": {
"slugs": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product slugs the reward applies to."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product tag names the reward applies to."
}
},
"required": ["slugs", "tags"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Restricts the coupon to matching products. Null means it applies to anything."
},
"minimumOrderTotalCents": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Minimum order total, in cents, before the coupon can be used. Null for none."
},
"expiry": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "never",
"description": "The reward stays redeemable until it is used or withdrawn."
}
},
"required": ["type"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "daysAfterIssuance",
"description": "The reward lapses a set number of days after each member gets it."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "How many days after issuance the reward stops being redeemable."
}
},
"required": ["type", "days"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "fixedDate",
"description": "Every reward issued from this rule lapses at the same moment."
},
"expiresAt": {
"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": "The moment the reward stops being redeemable, as an ISO 8601 timestamp."
}
},
"required": ["type", "expiresAt"],
"additionalProperties": false
}
],
"description": "When a reward issued from this rule stops being redeemable. Omitted means the program's default applies."
}
},
"required": ["type", "amountCents", "productFilter", "minimumOrderTotalCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "percentageCoupon",
"description": "Issues a percentage-off discount coupon."
},
"percentageDiscount": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"description": "Percentage taken off the qualifying items, from 1 to 100."
},
"productFilter": {
"anyOf": [
{
"type": "object",
"properties": {
"slugs": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product slugs the reward applies to."
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Product tag names the reward applies to."
}
},
"required": ["slugs", "tags"],
"additionalProperties": false
},
{
"type": "null"
}
],
"description": "Restricts the coupon to matching products. Null means it applies to anything."
},
"minimumOrderTotalCents": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Minimum order total, in cents, before the coupon can be used. Null for none."
},
"expiry": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "never",
"description": "The reward stays redeemable until it is used or withdrawn."
}
},
"required": ["type"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "daysAfterIssuance",
"description": "The reward lapses a set number of days after each member gets it."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "How many days after issuance the reward stops being redeemable."
}
},
"required": ["type", "days"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "fixedDate",
"description": "Every reward issued from this rule lapses at the same moment."
},
"expiresAt": {
"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": "The moment the reward stops being redeemable, as an ISO 8601 timestamp."
}
},
"required": ["type", "expiresAt"],
"additionalProperties": false
}
],
"description": "When a reward issued from this rule stops being redeemable. Omitted means the program's default applies."
}
},
"required": [
"type",
"percentageDiscount",
"productFilter",
"minimumOrderTotalCents"
],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "freeShipping",
"description": "Waives shipping on the customer's next order."
},
"maximumValueCents": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "Cap on the shipping cost covered, in cents. Null means uncapped."
},
"expiry": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "never",
"description": "The reward stays redeemable until it is used or withdrawn."
}
},
"required": ["type"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "daysAfterIssuance",
"description": "The reward lapses a set number of days after each member gets it."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "How many days after issuance the reward stops being redeemable."
}
},
"required": ["type", "days"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "fixedDate",
"description": "Every reward issued from this rule lapses at the same moment."
},
"expiresAt": {
"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": "The moment the reward stops being redeemable, as an ISO 8601 timestamp."
}
},
"required": ["type", "expiresAt"],
"additionalProperties": false
}
],
"description": "When a reward issued from this rule stops being redeemable. Omitted means the program's default applies."
}
},
"required": ["type", "maximumValueCents"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "giftCard",
"description": "Issues a gift card."
},
"amountCents": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Value loaded onto the gift card, in cents."
},
"expirySeconds": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "How long the gift card's balance stays spendable, in seconds. Null means the balance never expires."
},
"expiry": {
"oneOf": [
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "never",
"description": "The reward stays redeemable until it is used or withdrawn."
}
},
"required": ["type"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "daysAfterIssuance",
"description": "The reward lapses a set number of days after each member gets it."
},
"days": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "How many days after issuance the reward stops being redeemable."
}
},
"required": ["type", "days"],
"additionalProperties": false
},
{
"type": "object",
"properties": {
"type": {
"type": "string",
"const": "fixedDate",
"description": "Every reward issued from this rule lapses at the same moment."
},
"expiresAt": {
"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": "The moment the reward stops being redeemable, as an ISO 8601 timestamp."
}
},
"required": ["type", "expiresAt"],
"additionalProperties": false
}
],
"description": "When a reward issued from this rule stops being redeemable. Omitted means the program's default applies."
}
},
"required": ["type", "amountCents", "expirySeconds"],
"additionalProperties": false
}
],
"description": "What the customer gets when the rule fires."
},
"maxRedemptionsPerCustomer": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "How many times one customer may earn this reward. Null means unlimited."
},
"maxAvailableCount": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "How many times the reward can be earned in total, across everyone. Null means unlimited."
},
"availableCount": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "How many are left out of `maxAvailableCount`. Null when there is no cap."
},
"availableFrom": {
"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 rule starts firing. Null means straight away."
},
"availableTo": {
"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 rule stops firing. Null means it stays open."
},
"filter": {
"anyOf": [
{
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
{
"type": "null"
}
],
"description": "Who the rule applies to: a filter document in the same shape `GET /loyalty-memberships` takes, for example `{\"tier.id\":{\"$in\":[\"...\"]}}` or `{\"tags.name\":\"vip\"}`. Null means every member qualifies."
},
"metadata": {
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "A metadata value: a string, a number, true or false, or a list of strings. A key with a metadata definition holds the type its definition names."
},
"description": "Key/value pairs for your own data. Keys you define with `/metadata-definitions` are typed and validated; any other key is free-form. 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 rule was created."
},
"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 rule was last changed."
}
},
"required": [
"id",
"loyaltyProgramId",
"section",
"name",
"trigger",
"reward",
"maxRedemptionsPerCustomer",
"maxAvailableCount",
"availableCount",
"availableFrom",
"availableTo",
"filter",
"metadata",
"createdAt",
"updatedAt"
],
"additionalProperties": false
},
"description": "The rules that were created."
},
"sites": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the link between the site and the program.",
"idCodec": "sqid"
},
"siteId": {
"type": "string",
"description": "The site the program is attached to.",
"idCodec": "sqid"
},
"siteName": {
"type": "string",
"description": "The site's display name."
},
"siteSlug": {
"type": "string",
"description": "The site's slug, which the widget identifies it by."
},
"loyaltyProgramId": {
"type": "string",
"description": "The loyalty program the site is attached to.",
"idCodec": "sqid"
},
"programUrl": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "The page on the site that shows the loyalty program, used by the links in the member emails. Null means the site's base URL, where the launcher embed is expected to be."
},
"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 program was attached to the site."
}
},
"required": [
"id",
"siteId",
"siteName",
"siteSlug",
"loyaltyProgramId",
"programUrl",
"createdAt"
],
"additionalProperties": false
},
"description": "The sites the program was attached to."
}
},
"required": ["data", "program", "rules", "sites"],
"additionalProperties": false
}