Bulk Create SKU Orders
POST/api/storefront/instances/:id/orders/create-sku-orders
Create SKU.io sales orders for mirrored orders that do not have one yet. Unlike an import run, this is never gated by the connection's automatic-creation setting — you asked for it explicitly. Orders that are cancelled, refunded, archived, an unpaid processor checkout, or already linked are skipped.
This endpoint currently requires session authentication; Personal Access Token scope support is in progress.
Request body (every field optional)
ids(array of integers) — create for exactly these mirrored orders.apply_to_all(boolean) — create for a whole set rather than a list.filters(object, nullable) — withapply_to_all, the set to target.
Three ways to call it:
apply_to_all: truewith nofilters(or an empty body) — every importable order without a SKU sales order.total_orderscomes backnullbecause the set is resolved inside the background task.apply_to_all: truewithfilters— only the orders those filters match;total_ordersis the resolved count.ids— only those orders.
At most 5000 orders are processed per run, whichever way you select them; call it again to continue.
Choosing the orders Send exactly one of the two selection shapes:
ids— an explicit list of mirrored order ids. Ids that belong to another connection are silently dropped.apply_to_all: trueplusfilters— the action targets every order the filters match, however many that is, not just a page of them. Thefiltersobject is resolved server-side against the same filter setGET /ordersaccepts, so what you saw in the list is exactly what is acted on.
Inside filters (every key optional, all bare column names — no filter[...] brackets needed, though filter[status] style keys and a nested filter object are both unwrapped for you):
search— the same free-text search as the list, honoured like any other filter.search_columns,search_strict_columns— narrow or tighten that search.status,payment_status,currency_code— comma-separated value lists.sku_order—with,without,abandoned,failedorheld.has_unmapped_items— boolean.archived—only/archived, orall. Leaving it out means active orders only, matching the list's own default, so a filter-less apply-to-all never sweeps archived orders.placed_from,placed_to— date bounds.ids— a comma-separated id list, as a filter rather than a selection.<column>.<operator>— any advanced operator key the list accepts (e.g.total.greater_than).filter_groups— a base64-encoded JSON condition tree.
Pagination and display keys (page, per_page, sort, included, total, query) are ignored if present.
Failing closed. A filters payload that cannot be parsed, a malformed filter_groups tree, or a legacy {conjunction, filterSet} payload returns 422 rather than being treated as "no filters" — silently matching every order would be the wrong guess for a bulk action.
Always asynchronous. Whenever there is work to do the response returns tracked_job_log_id, the handle to poll for progress and per-order failures. When nothing matches, nothing is queued and the response says so with tracked_job_log_id: null and total_orders: 0.
Requires the integrations.sync permission.
Authentication: Bearer token (session or PAT).
Request
Responses
- 200
- 401
- 403
- 404
- 422
- 429
OK
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.
Not found — no record with the given identifier (or the route does not exist). Verify the ID before retrying.
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.