#Import jobs
GET /import-jobs
List the organization's CSV import jobs, newest first. Poll this or the single-job endpoint to follow an import's progress.
Requires the imports: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.
sortcreatedAt | -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, integrationId, type, status, createdAt. See Filtering for the syntax.
curl \
"https://your-store.meisei.app/api/import-jobs" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getImportJobs } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getImportJobs()require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
page = meisei.import_jobs.listfrom meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
page = meisei.import_jobs.list(){
"data": [
{
"id": "A4Ws1igz",
"userId": "uHKNC81a",
"integrationId": "A4Ws1igz",
"fileUrl": "string",
"type": "customers",
"format": "meisei",
"status": "pending",
"totalCount": 0,
"processedCount": 0,
"errors": ["..."],
"earnLoyalty": 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 import job.",
"idCodec": "sqid"
},
"userId": {
"type": "string",
"description": "The ID of the user who started the import.",
"idCodec": "controlPlane"
},
"integrationId": {
"anyOf": [
{
"type": "string",
"description": "The integration whose sync ran this import, such as a connected Shopify store, or null for an import someone started.",
"idCodec": "sqid"
},
{
"type": "null"
}
],
"description": "The integration whose sync ran this import, such as a connected Shopify store, or null for an import someone started."
},
"fileUrl": {
"type": "string",
"description": "A signed URL to download the source file the import ran against."
},
"type": {
"type": "string",
"enum": ["customers", "products", "orders", "wishlists", "reviews", "loyalty-members"],
"description": "What the file contains, which decides the columns the importer expects."
},
"format": {
"type": "string",
"enum": [
"meisei",
"loyaltylion",
"smile",
"rivo",
"yotpo",
"judgeme",
"okendo",
"stamped",
"loox",
"swym",
"wishlistking",
"growave",
"wishlisthero"
],
"description": "Whose column names the file uses. Anything other than `meisei` is remapped to Meisei's columns before the import runs."
},
"status": {
"type": "string",
"enum": ["pending", "processing", "completed", "failed", "cancelled"],
"description": "Where the import has got to."
},
"totalCount": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "How many rows the file holds. The file is counted before anything is imported, so this is null only until that count is done."
},
"processedCount": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "How many rows of the file have been read and imported so far."
},
"errors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"row": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The 1-based row in the CSV that was skipped, or null if the problem stopped the whole file."
},
"message": {
"type": "string",
"description": "What went wrong with that row."
},
"severity": {
"description": "`error` for something the import could not handle, `notice` for something it handled but wants to tell you about, such as a column a competitor format does not carry. Absent means `error`.",
"type": "string",
"enum": ["error", "notice"]
}
},
"required": ["row", "message"],
"additionalProperties": false
},
"description": "Rows the importer could not handle, and notices about the file as a whole. An import that skipped rows still completes, so check this even on a successful job. The first 1,000 problems are listed; past that, one final entry with a null `row` says how many more there were."
},
"earnLoyalty": {
"type": "boolean",
"description": "Whether orders created by this import earn loyalty points and stamps. Off by default, so importing history never mints points."
},
"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 import was started."
},
"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 import last made progress."
}
},
"required": [
"id",
"userId",
"integrationId",
"fileUrl",
"type",
"format",
"status",
"totalCount",
"processedCount",
"errors",
"earnLoyalty",
"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 /import-jobs
Queue a CSV import. Upload the file first with POST /files/upload-url using private access, then pass the key it returns. The import runs in the background, so poll the job to see how it is going. Imports of one type run one at a time, so a second waits as pending until the first finishes. Only session-authenticated requests can start one, since an import is attributed to a user.
Requires the imports:write permission.
Costs 10 rate limit tokens instead of the usual one. See Rate limits.
Body parameters
fileKeystringrequiredThe storage key returned by POST /files/upload-url for the uploaded CSV.
typecustomers | products | orders | wishlists | reviews | loyalty-membersrequiredWhat the file contains, which decides the columns the importer expects.
formatmeisei | loyaltylion | smile | rivo | yotpo | judgeme | okendo | stamped | loox | swym | wishlistking | growave | wishlistheroWhose column names the file uses. Defaults to meisei, which is the column set the guides document. A competitor format is remapped to Meisei's columns before the import runs, and the file is refused if its columns do not match that format.
earnLoyaltybooleanFor an orders import, whether imported orders earn loyalty points and stamps. Off by default, so importing history never mints points. Ignored for other types.
curl \
-X POST \
"https://your-store.meisei.app/api/import-jobs" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileKey": "string",
"type": "customers",
"format": "meisei",
"earnLoyalty": true
}'import { client } from "@meisei/api/admin/client"
import { postImportJobs } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await postImportJobs({
body: {
fileKey: "string",
type: "customers",
format: "meisei",
earnLoyalty: true,
},
})require "meisei"
meisei = Meisei::Client.new(
secret_key: "sk_YOUR_SECRET_KEY",
base_url: "https://your-store.meisei.app/api",
)
result = meisei.import_jobs.create(
file_key: "string",
type: "customers",
format: "meisei",
earn_loyalty: true,
)from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.import_jobs.create(
file_key="string",
type="customers",
format="meisei",
earn_loyalty=True,
){
"importJobId": "A4Ws1igz"
}{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"importJobId": {
"type": "string",
"description": "The ID of the queued import job.",
"idCodec": "sqid"
}
},
"required": ["importJobId"],
"additionalProperties": false,
"description": "A handle you can poll for progress."
}GET /import-jobs/{id}
Get a single import job by ID, including its progress counts and any rows it skipped.
Requires the imports:read permission.
Path parameters
idstringrequiredThe ID of the import job.
curl \
"https://your-store.meisei.app/api/import-jobs/A4Ws1igz" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getImportJobsById } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getImportJobsById({
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.import_jobs.retrieve("A4Ws1igz")from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.import_jobs.retrieve("A4Ws1igz"){
"id": "A4Ws1igz",
"userId": "uHKNC81a",
"integrationId": "A4Ws1igz",
"fileUrl": "string",
"type": "customers",
"format": "meisei",
"status": "pending",
"totalCount": 0,
"processedCount": 0,
"errors": [
{
"row": 0,
"message": "string",
"severity": "error"
}
],
"earnLoyalty": 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 import job.",
"idCodec": "sqid"
},
"userId": {
"type": "string",
"description": "The ID of the user who started the import.",
"idCodec": "controlPlane"
},
"integrationId": {
"anyOf": [
{
"type": "string",
"description": "The integration whose sync ran this import, such as a connected Shopify store, or null for an import someone started.",
"idCodec": "sqid"
},
{
"type": "null"
}
],
"description": "The integration whose sync ran this import, such as a connected Shopify store, or null for an import someone started."
},
"fileUrl": {
"type": "string",
"description": "A signed URL to download the source file the import ran against."
},
"type": {
"type": "string",
"enum": ["customers", "products", "orders", "wishlists", "reviews", "loyalty-members"],
"description": "What the file contains, which decides the columns the importer expects."
},
"format": {
"type": "string",
"enum": [
"meisei",
"loyaltylion",
"smile",
"rivo",
"yotpo",
"judgeme",
"okendo",
"stamped",
"loox",
"swym",
"wishlistking",
"growave",
"wishlisthero"
],
"description": "Whose column names the file uses. Anything other than `meisei` is remapped to Meisei's columns before the import runs."
},
"status": {
"type": "string",
"enum": ["pending", "processing", "completed", "failed", "cancelled"],
"description": "Where the import has got to."
},
"totalCount": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "How many rows the file holds. The file is counted before anything is imported, so this is null only until that count is done."
},
"processedCount": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
],
"description": "How many rows of the file have been read and imported so far."
},
"errors": {
"type": "array",
"items": {
"type": "object",
"properties": {
"row": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The 1-based row in the CSV that was skipped, or null if the problem stopped the whole file."
},
"message": {
"type": "string",
"description": "What went wrong with that row."
},
"severity": {
"description": "`error` for something the import could not handle, `notice` for something it handled but wants to tell you about, such as a column a competitor format does not carry. Absent means `error`.",
"type": "string",
"enum": ["error", "notice"]
}
},
"required": ["row", "message"],
"additionalProperties": false
},
"description": "Rows the importer could not handle, and notices about the file as a whole. An import that skipped rows still completes, so check this even on a successful job. The first 1,000 problems are listed; past that, one final entry with a null `row` says how many more there were."
},
"earnLoyalty": {
"type": "boolean",
"description": "Whether orders created by this import earn loyalty points and stamps. Off by default, so importing history never mints points."
},
"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 import was started."
},
"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 import last made progress."
}
},
"required": [
"id",
"userId",
"integrationId",
"fileUrl",
"type",
"format",
"status",
"totalCount",
"processedCount",
"errors",
"earnLoyalty",
"createdAt",
"updatedAt"
],
"additionalProperties": false,
"description": "The requested import job."
}GET /import-jobs/{id}/records
List the records an import wrote, in file order. A record deleted since the import keeps its place in the list and comes back with deleted set, so the history stays readable.
Requires the imports:read permission.
Path parameters
idstringrequiredThe ID of the import job.
Query parameters
limitnumberThe number of records to return.
cursorstringA pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.
sortcreatedAt | -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: action, recordTable. See Filtering for the syntax.
curl \
"https://your-store.meisei.app/api/import-jobs/A4Ws1igz/records" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"import { client } from "@meisei/api/admin/client"
import { getImportJobsByIdRecords } from "@meisei/api/admin"
client.setConfig({
baseUrl: "https://your-store.meisei.app/api",
headers: { Authorization: "Bearer sk_YOUR_SECRET_KEY" },
})
const { data, error } = await getImportJobsByIdRecords({
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.import_jobs.records("A4Ws1igz")from meisei import Client
meisei = Client(
secret_key="sk_YOUR_SECRET_KEY",
base_url="https://your-store.meisei.app/api",
)
result = meisei.import_jobs.records("A4Ws1igz"){
"data": [
{
"id": "A4Ws1igz",
"importJobId": "A4Ws1igz",
"recordTable": "customers",
"recordId": "A4Ws1igz",
"action": "created",
"row": 0,
"label": "string",
"deleted": true,
"createdAt": "2025-01-15T09:30:00Z"
}
],
"nextCursor": "string",
"counts": {
"created": 0,
"updated": 0,
"total": 0
}
}{
"$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 link between the import and the record.",
"idCodec": "sqid"
},
"importJobId": {
"type": "string",
"description": "The import job that wrote the record.",
"idCodec": "sqid"
},
"recordTable": {
"type": "string",
"enum": [
"customers",
"products",
"orders",
"wishlists",
"reviews",
"loyaltyMemberships"
],
"description": "Which resource the record is."
},
"recordId": {
"type": "string",
"description": "The record's ID. It is not a foreign key: a record deleted since the import keeps its place in the job's history.",
"idCodec": "sqid"
},
"action": {
"type": "string",
"enum": ["created", "updated"],
"description": "Whether the import created the record or updated one that was already there."
},
"row": {
"anyOf": [
{
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
{
"type": "null"
}
],
"description": "The 1-based row in the CSV that became this record, where the import knew it."
},
"label": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"description": "A short name for the record, or null when the record has been deleted since."
},
"deleted": {
"type": "boolean",
"description": "Whether the record has been deleted since the import wrote it."
},
"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 link was written."
}
},
"required": [
"id",
"importJobId",
"recordTable",
"recordId",
"action",
"row",
"label",
"deleted",
"createdAt"
],
"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."
},
"counts": {
"type": "object",
"properties": {
"created": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many records the import created."
},
"updated": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many records the import updated."
},
"total": {
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991,
"description": "How many records the import wrote in total."
}
},
"required": ["created", "updated", "total"],
"additionalProperties": false,
"description": "Totals for the whole job, not just this page."
}
},
"required": ["data", "nextCursor", "counts"],
"additionalProperties": false
}