#Dashboards
GET /dashboards
List the organization's dashboards. Each row carries a chart count; the charts themselves come from the dashboard's detail endpoint.
Requires the analytics:read permission.
Query parameters
limitnumberThe number of records to return.
cursorstringA pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.
sortname | -name | createdAt | -createdAtThe sort order. Prefix a field with - to sort descending. Defaults to -createdAt.
filterstringA JSON-encoded filter document, for example {"createdAt":{"$gte":"2025-01-01T00:00:00Z"}}. Filterable fields: id, name, createdAt. See Filtering for the syntax.
curl \
"https://your-store.meisei.app/api/dashboards" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getDashboards } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getDashboards()require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
page = meisei.dashboards.listfrom meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
page = meisei.dashboards.list(){
"data": [
{
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}
],
"nextCursor": "string"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt"],
"additionalProperties": false
},
"description": "The page of records, in the requested sort order."
},
"nextCursor": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Pass this back as `cursor` to fetch the next page. Null once the last page has been returned."
}
},
"required": ["data", "nextCursor"],
"additionalProperties": false
}POST /dashboards
Create an empty dashboard. Charts are created onto it with POST /saved-charts.
Requires the analytics:write permission.
Body parameters
namestringrequiredThe dashboard's title.
curl \
-X POST \
"https://your-store.meisei.app/api/dashboards" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string"
}'import { client } from "@meisei/api/admin/client"
import { postDashboards } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await postDashboards({
body: {
name: "string",
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.dashboards.create(name: "string")from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.dashboards.create(name="string"){
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt"],
"additionalProperties": false,
"description": "The new dashboard."
}GET /dashboards/{id}
Get a single dashboard by ID, with its charts in reading order (by grid row, then column), ready to run against /analytics/query.
Requires the analytics:read permission.
Path parameters
idstringrequiredThe ID of the dashboard.
curl \
"https://your-store.meisei.app/api/dashboards/A4Ws1igz" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getDashboardsById } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getDashboardsById({
path: { id: "A4Ws1igz" },
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.dashboards.retrieve("A4Ws1igz")from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.dashboards.retrieve("A4Ws1igz"){
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z",
"charts": [
{
"id": "A4Ws1igz",
"dashboardId": "A4Ws1igz",
"name": "string",
"resource": "reviews",
"chartType": "stat",
"query": {
"measures": "...",
"groupBy": "...",
"granularity": "...",
"filter": "...",
"limit": "...",
"lastDays": "..."
},
"layout": {
"x": "...",
"y": "...",
"w": "...",
"h": "..."
},
"invalidReason": "string",
"feedCreatedAt": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}
]
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
},
"charts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the saved chart.",
"idCodec": "sqid"
},
"dashboardId": {
"type": "string",
"description": "The dashboard the chart belongs to, for its whole life.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The title shown above the chart."
},
"resource": {
"type": "string",
"enum": [
"reviews",
"review-answers",
"orders",
"customers",
"products",
"loyalty-members",
"loyalty-activity",
"loyalty-rewards"
],
"description": "The resource to aggregate. Call `/analytics/schema` for what each one offers."
},
"chartType": {
"type": "string",
"enum": ["stat", "line", "area", "bar", "donut", "stackedBar", "groupedBar", "table"],
"description": "How the chart is drawn. It has to suit the query it is saved with: a `donut` needs one counting measure grouped by one non-date dimension, a `stat` needs no grouping at all, and `table` always fits."
},
"query": {
"type": "object",
"properties": {
"measures": {
"minItems": 1,
"type": "array",
"items": {
"type": "string"
},
"description": "The measures to report, by name. They have to be ones the resource offers."
},
"groupBy": {
"description": "The dimensions to group by, by name, at most three and at most one of them a date. Omit for a single total row.",
"type": "array",
"items": {
"type": "string"
}
},
"granularity": {
"type": "string",
"enum": ["hour", "day", "week", "month", "quarter", "year"],
"description": "The bucket size for a date dimension. Defaults to `day`. Ignored when nothing in `groupBy` is a date."
},
"filter": {
"description": "The filter document to apply, in the shape the resource's list endpoint takes. It is validated against the fields that screen allows.",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"limit": {
"description": "How many distinct group-by combinations to return, from 1 to 500.",
"type": "integer",
"minimum": 1,
"maximum": 500
},
"lastDays": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "Only count records from the last this many days, up to now. It applies to `timeField` like `from` does, and an explicit `from` takes its place."
}
},
"required": ["measures"],
"additionalProperties": false,
"description": "What the chart asks for. Send it to `/analytics/query` alongside `resource` to draw it."
},
"layout": {
"type": "object",
"properties": {
"x": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The column the chart starts at, on a 12 column grid."
},
"y": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The row the chart starts at."
},
"w": {
"type": "integer",
"minimum": 2,
"maximum": 12,
"description": "How many columns the chart spans, at least 2."
},
"h": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How many rows tall the chart is. One row renders as 90 pixels."
}
},
"required": ["x", "y", "w", "h"],
"additionalProperties": false,
"description": "Where the chart sits on the dashboard's grid."
},
"invalidReason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the chart can no longer run, or null when it is fine. Definitions are validated on write, so this only fills in when a resource, measure or dimension the chart names was removed afterward."
},
"feedCreatedAt": {
"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 chart's data link was made, or null when it has none. The link itself is only shown once, when it is made."
},
"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 chart was saved."
},
"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 chart was last changed."
}
},
"required": [
"id",
"dashboardId",
"name",
"resource",
"chartType",
"query",
"layout",
"invalidReason",
"feedCreatedAt",
"createdAt",
"updatedAt"
],
"additionalProperties": false
},
"description": "The dashboard's charts, in reading order: by row first, then by column."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt", "charts"],
"additionalProperties": false,
"description": "The requested dashboard."
}PUT /dashboards/{id}
Rename a dashboard, or make it the one the app opens by default. Promoting a default demotes the dashboard that held it. Positions are changed through the layout endpoint.
Requires the analytics:write permission.
Path parameters
idstringrequiredThe ID of the dashboard to update.
Body parameters
namestringThe dashboard's title.
isDefaultbooleanSet to true to make this the dashboard the app opens by default, which demotes the one that held it. Set to false to leave the organization with no default.
curl \
-X PUT \
"https://your-store.meisei.app/api/dashboards/A4Ws1igz" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "string",
"isDefault": true
}'import { client } from "@meisei/api/admin/client"
import { putDashboardsById } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await putDashboardsById({
path: { id: "A4Ws1igz" },
body: {
name: "string",
isDefault: true,
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.dashboards.update("A4Ws1igz", name: "string", is_default: true)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.dashboards.update("A4Ws1igz", name="string", is_default=True){
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt"],
"additionalProperties": false,
"description": "The updated dashboard."
}DELETE /dashboards/{id}
Delete a dashboard and every chart on it. Each deletion is recorded in the audit log.
Requires the analytics:write permission.
Path parameters
idstringrequiredThe ID of the dashboard to delete.
curl \
-X DELETE \
"https://your-store.meisei.app/api/dashboards/A4Ws1igz" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { deleteDashboardsById } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await deleteDashboardsById({
path: { id: "A4Ws1igz" },
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.dashboards.delete("A4Ws1igz")from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.dashboards.delete("A4Ws1igz"){
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt"],
"additionalProperties": false,
"description": "The deleted dashboard."
}PUT /dashboards/{id}/layout
Replace the dashboard's whole grid layout in one write, so a drag session is one request. The payload has to place every chart on the dashboard exactly once, inside the 12 column grid.
Requires the analytics:write permission.
Path parameters
idstringrequiredThe ID of the dashboard.
Body parameters
dataobject[]requiredWhere every chart on the dashboard sits. The whole layout is replaced in one write, so one drag session is one request.
curl \
-X PUT \
"https://your-store.meisei.app/api/dashboards/A4Ws1igz/layout" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"data": [
{
"chartId": "string",
"x": 0,
"y": 0,
"w": 0,
"h": 0
}
]
}'import { client } from "@meisei/api/admin/client"
import { putDashboardsByIdLayout } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await putDashboardsByIdLayout({
path: { id: "A4Ws1igz" },
body: {
data: [
{
chartId: "string",
x: 0,
y: 0,
w: 0,
h: 0,
},
],
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.dashboards.update_layout(
"A4Ws1igz",
data: [{ chart_id: "string", x: 0, y: 0, w: 0, h: 0 }],
)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.dashboards.update_layout(
"A4Ws1igz",
data=[{"chart_id": "string", "x": 0, "y": 0, "w": 0, "h": 0}],
){
"id": "A4Ws1igz",
"name": "string",
"chartCount": 0,
"isDefault": true,
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z",
"charts": [
{
"id": "A4Ws1igz",
"dashboardId": "A4Ws1igz",
"name": "string",
"resource": "reviews",
"chartType": "stat",
"query": {
"measures": "...",
"groupBy": "...",
"granularity": "...",
"filter": "...",
"limit": "...",
"lastDays": "..."
},
"layout": {
"x": "...",
"y": "...",
"w": "...",
"h": "..."
},
"invalidReason": "string",
"feedCreatedAt": "2025-01-15T09:30:00Z",
"createdAt": "2025-01-15T09:30:00Z",
"updatedAt": "2025-01-15T09:30:00Z"
}
]
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the dashboard.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The dashboard's title."
},
"chartCount": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many charts the dashboard holds."
},
"isDefault": {
"type": "boolean",
"description": "Whether this is the dashboard the app opens by default. At most one dashboard per organization is the default."
},
"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 dashboard 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 dashboard was last changed."
},
"charts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the saved chart.",
"idCodec": "sqid"
},
"dashboardId": {
"type": "string",
"description": "The dashboard the chart belongs to, for its whole life.",
"idCodec": "sqid"
},
"name": {
"type": "string",
"description": "The title shown above the chart."
},
"resource": {
"type": "string",
"enum": [
"reviews",
"review-answers",
"orders",
"customers",
"products",
"loyalty-members",
"loyalty-activity",
"loyalty-rewards"
],
"description": "The resource to aggregate. Call `/analytics/schema` for what each one offers."
},
"chartType": {
"type": "string",
"enum": ["stat", "line", "area", "bar", "donut", "stackedBar", "groupedBar", "table"],
"description": "How the chart is drawn. It has to suit the query it is saved with: a `donut` needs one counting measure grouped by one non-date dimension, a `stat` needs no grouping at all, and `table` always fits."
},
"query": {
"type": "object",
"properties": {
"measures": {
"minItems": 1,
"type": "array",
"items": {
"type": "string"
},
"description": "The measures to report, by name. They have to be ones the resource offers."
},
"groupBy": {
"description": "The dimensions to group by, by name, at most three and at most one of them a date. Omit for a single total row.",
"type": "array",
"items": {
"type": "string"
}
},
"granularity": {
"type": "string",
"enum": ["hour", "day", "week", "month", "quarter", "year"],
"description": "The bucket size for a date dimension. Defaults to `day`. Ignored when nothing in `groupBy` is a date."
},
"filter": {
"description": "The filter document to apply, in the shape the resource's list endpoint takes. It is validated against the fields that screen allows.",
"type": "object",
"propertyNames": {
"type": "string"
},
"additionalProperties": {}
},
"limit": {
"description": "How many distinct group-by combinations to return, from 1 to 500.",
"type": "integer",
"minimum": 1,
"maximum": 500
},
"lastDays": {
"type": "integer",
"minimum": 1,
"maximum": 3650,
"description": "Only count records from the last this many days, up to now. It applies to `timeField` like `from` does, and an explicit `from` takes its place."
}
},
"required": ["measures"],
"additionalProperties": false,
"description": "What the chart asks for. Send it to `/analytics/query` alongside `resource` to draw it."
},
"layout": {
"type": "object",
"properties": {
"x": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The column the chart starts at, on a 12 column grid."
},
"y": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "The row the chart starts at."
},
"w": {
"type": "integer",
"minimum": 2,
"maximum": 12,
"description": "How many columns the chart spans, at least 2."
},
"h": {
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "How many rows tall the chart is. One row renders as 90 pixels."
}
},
"required": ["x", "y", "w", "h"],
"additionalProperties": false,
"description": "Where the chart sits on the dashboard's grid."
},
"invalidReason": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "Why the chart can no longer run, or null when it is fine. Definitions are validated on write, so this only fills in when a resource, measure or dimension the chart names was removed afterward."
},
"feedCreatedAt": {
"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 chart's data link was made, or null when it has none. The link itself is only shown once, when it is made."
},
"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 chart was saved."
},
"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 chart was last changed."
}
},
"required": [
"id",
"dashboardId",
"name",
"resource",
"chartType",
"query",
"layout",
"invalidReason",
"feedCreatedAt",
"createdAt",
"updatedAt"
],
"additionalProperties": false
},
"description": "The dashboard's charts, in reading order: by row first, then by column."
}
},
"required": ["id", "name", "chartCount", "isDefault", "createdAt", "updatedAt", "charts"],
"additionalProperties": false,
"description": "The dashboard with its charts in the new order."
}