ShopEazydevelopers
API referenceMerchant API BetaProducts

Past product imports, newest first

Beta
Credentials
  • OAuth access token
Scopes
listings:read
GET
/v1/merchant/stores/{storeId}/product-imports

Runs started through the API and the console's imports; the newest 200 are listed.

Access: OAuth scope listings:read; not write-gated.

Paged: { items, nextCursor }, limit (default 20, at most 50) and an opaque cursor.

Authorization

merchantOAuth listings:read
headerAuthorizationBearer <token>

OAuth 2.1 (authorization code + PKCE S256, public clients, dynamic registration) for connected AI apps. Effective power is scopes granted AND the person's role today AND the plan. orders:refund, billing:write and team:write are opt-in on the consent screen. Write implies read for marketing:read and messages:read, so a grant holding marketing:write passes a marketing:read check, and messages:send passes messages:read.

Scope: listings:read

Path Parameters

storeId*string

A store the person can reach. Any other id answers 404, never 403.

Query Parameters

cursor?string

The nextCursor of the previous page, unchanged. A cursor that is not one we gave you is 400 bad_request.

limit?integer

Page size: default 20, at most 50 (more is 50; a missing or unusable value is 20).

Range1 <= value <= 50
Default20

Response Body

OK

application/json
  1. response
data*
Example Request
curl -X GET 'https://api.shopeazy.co/v1/merchant/stores/<storeId>/product-imports' \  -H 'Authorization: Bearer <access_token>'
Example Response
{  "data": {    "items": [],    "nextCursor": null  }}

Set the customisation groups on one listing PUT

The groups this listing offers, in order, each with its own prices: `prices` maps a choice id to a price, `variantPrices` maps a variant (or ticket tier) id and then a choice id. An override that repeats the inherited price, or names something the listing no longer has, is dropped. An empty list takes every group off. getProduct returns the same shape in `customisations`. Access: OAuth scope `listings:write`; write-gated by the subscription.

Start a bulk product import from an uploaded CSV POST

Upload the file first (createProductImportUploadLink, then PUT it) and pass its `uploadId`. Say how the columns map with a saved profile (`profileId`, listProductImportProfiles) or an inline `mapping`; one of the fields mapped has to be a product ID, SKU or barcode, so next month's file finds this month's products instead of creating them again. The file is read and staged here (a file with no rows, a missing column or over 20,000 rows is `422` and nothing starts), then a worker applies it in chunks: this answers `202` at once with the run, `status: queued`. Poll getProductImport until `status` is `applied` (written), `previewed` (a `dryRun`: the same run, nothing written) or `failed`. Rows with a match are updated (only what the file has a value for: an empty cell never clears a field) and the rest are created as drafts. New products count against the plan's listing cap as in the console: past it, those rows are refused with a reason. Rows that fail are listed in `errors` (the first 200) and counted in `summary.error`. The same `uploadId` is the same run: asking again returns the run that is there. Needs the Products kit (404 `kit_not_found`) and answers `501 not_available` where bulk import is not switched on. Access: OAuth scope `listings:write`; write-gated by the subscription.