Create Drafts in Bulk
POST/api/v2/listing-drafts/bulk
Create one create-purpose draft per product on a sales channel and return them, then pass the returned ids to Bulk Publish Drafts. Each draft is resolved and validated on creation.
products:writeGrant this scope to your token under Settings → Developer → Personal Access Tokens.
Send either products[] (per-product category, template and provenance — typically what Resolve Draft Categories returned) or plain product_ids[], or both; a product in product_ids that has no products[] row uses the top-level sales_channel_category_id / sales_channel_product_template_id. A product that ends up with no category at all is resolved like a single draft: its override on the channel, else its product type's mapped category, with that category's default template.
Products the channel's catalog excludes do not fail the request — they are returned in skipped with a reason and the remaining drafts are still created.
Authentication: Requires Bearer token.
Fields:
sales_channel_id(required, integer)products(required unlessproduct_idsis sent, array, 1–500)products[].product_id(required, integer)products[].sales_channel_category_id(nullable, integer)products[].sales_channel_product_template_id(nullable, integer)products[].category_provenance(nullable,override|type_map|manual) — where that row's category came from; a supplied category without it is recorded asmanualproduct_ids(required unlessproductsis sent, array of integers, 1–500)sales_channel_category_id(nullable, integer) — fallback category for rows that do not set their ownsales_channel_product_template_id(nullable, integer) — fallback templatesales_channel_listing_profile_id(nullable, integer) — applied to every draft
The returned drafts are the compact form (no fields, field_overrides or resolved_values); read a draft to get those. skipped[] rows carry product_id, sku, name, reason.
Requires permission: listings.create
Request
Responses
- 201
- 401
- 403
- 422
- 429
Created
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Validation failed — the body is a field → messages map (Laravel shape) or the platform envelope with a stable machine-readable code. Fix the payload and resubmit.
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.