Bulk & Async Jobs
How to submit and poll long-running operations: bulk order and variant actions.
BetaAPI v2 is in public beta: endpoints, fields and behaviour can change before general availability. See the changelog
Last updated
Two classes of v2 action return a job handle instead of a synchronous result:
- Bulk order actions —
bulk_release,bulk_open_scheduled_fulfillments,bulk_hold_fulfillments,bulk_split_fulfillment_orders,bulk_reschedule_fulfillment,bulk_reschedule_payment,bulk_collect_payment,bulk_send_confirmation,bulk_send_shipping_update. - Bulk variant administration —
bulk_recalculate_preorder_counts,bulk_reset_metafields,bulk_sync_metafields.
Both share one envelope, one polling URL pattern, and one terminal-state semantics.
Submission response — 202 Accepted
Section titled “Submission response — 202 Accepted”{ "job_id": "5b0c2e7e-8f6a-4d1e-9a51-2f3c4d5e6f70", "operation": "release", "status": "queued", "status_url": "/api/v2/external/preorders/orders/jobs/5b0c2e7e-8f6a-4d1e-9a51-2f3c4d5e6f70", "order_count": 47}job_id— opaque. Order jobs use a uuid; variant jobs are prefixedbulk_*.status_url— exactly where to GET to poll; never construct this yourself.order_count/variant_count— number of items the job will process (informational).
Polling
Section titled “Polling”curl https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/5b0c2e7e-8f6a-4d1e-9a51-2f3c4d5e6f70 \ -H "X-Auth-Token: $STOQ_API_KEY"{ "job_id": "5b0c2e7e-8f6a-4d1e-9a51-2f3c4d5e6f70", "operation": "release", "status": "running", "total": 47, "processed": 12, "succeeded_count": 12, "failed_count": 0, "succeeded": [ { "id": "d608978f-…", "shopify_order_id": "gid://shopify/Order/6123456789012", "name": "#1042" } ], "failed": []}total/processedare item counts. Variant jobs also reportprogress, a percentage (0–100).erroris present when the job failed.
status is one of:
| Status | Meaning |
|---|---|
queued |
Submitted, not started yet (order jobs) |
running |
Being processed by a worker |
completed |
Done |
failed |
Job failed — see error |
cancelled |
Operator cancelled (rare) |
Polling an unknown or expired job_id returns 404.
Terminal payloads
Section titled “Terminal payloads”Bulk order actions complete with each order’s result. One bad order doesn’t fail the batch; it lands in failed with its error:
{ "job_id": "...", "operation": "release", "status": "completed", "total": 47, "processed": 47, "succeeded_count": 46, "failed_count": 1, "succeeded": [ { "id": "…", "shopify_order_id": "gid://shopify/Order/…", "name": "#1042" } ], "failed": [ { "id": "…", "shopify_order_id": "gid://shopify/Order/…", "name": "#1043", "error": "…" } ] }id is our order id and shopify_order_id the Shopify gid.
Polling cadence
Section titled “Polling cadence”- Bulk actions: poll every 5s for the first minute, then every 15s. Most bulk jobs of <500 items complete in under 30s.
- Always check rate-limit headers; polling is a GET and costs 1 point.
Caps and behavior
Section titled “Caps and behavior”- Bulk order actions: max 1000 order ids per submission, each our id or a Shopify order id / gid. Exceeding the cap returns
422. - Bulk variant actions: max 5000 variant IDs per submission.
- Job retention: status records expire ~24h after completion.
Inventory of async endpoints
Section titled “Inventory of async endpoints”The pattern is the same across all of them — the table below is just so you can find the right one:
| Resource | Job endpoint |
|---|---|
preorders/orders/bulk_* |
GET /preorders/orders/jobs/:job_id |
preorders/product_variants/bulk_* |
GET /preorders/product_variants/jobs/:job_id |
The offer’s products/add_variants and products/bulk_toggle_inventory_policy return the same job: {job_id, status, status_url}, with a new job_id for every run; poll status_url (GET /preorders/product_variants/jobs/:job_id). add_variants can also answer 409 with code: "preflight_issues" before any job starts; see offer capabilities. See each resource page for the full list of bulk and export actions.
Thanks for letting us know.
Still stuck? Ask Quinn or chat with support