Bulk & Async Jobs
Three classes of v2 action return a job handle instead of a synchronous result:
- Bulk order actions —
bulk_release,bulk_cancel,bulk_set_tags,bulk_send_payment_collection_url. - Bulk variant administration —
bulk_recalculate_preorder_counts,bulk_reset_metafields,bulk_sync_metafields. - CSV exports — every report has a paired
*/exportaction.
All three share one envelope, one polling URL pattern, and one terminal-state semantics.
Submission response — 202 Accepted
{
"job_id": "bulk_orders_release_a8c3f01b9d2e4471",
"status_url": "/api/v2/external/preorders/orders/jobs/bulk_orders_release_a8c3f01b9d2e4471",
"order_count": 47
}job_id— opaque, prefixed by action (bulk_orders_*for order jobs,bulk_*for variant jobs,exp_*for exports).status_url— exactly where to GET to poll; never construct this yourself.order_count/variant_count— number of items the job will process (informational; not present on export submissions).
Polling
curl https://app.stoqapp.com/api/v2/external/preorders/orders/jobs/bulk_orders_release_a8c3f01b9d2e4471 \
-H "X-Auth-Token: $STOQ_API_KEY"{
"job_id": "bulk_orders_release_a8c3f01b9d2e4471",
"status": "running",
"progress": 25,
"total": 47,
"processed": 12
}progressis a percentage (0–100);total/processedare item counts.erroris present when the job failed.
status is one of:
| Status | Meaning |
|---|---|
running | Queued or being processed by a worker |
completed | Done (bulk jobs) |
ready | Done, download available (CSV exports) |
failed | Job failed — see error |
cancelled | Operator cancelled (rare) |
Polling an unknown or expired job_id returns 404.
Terminal payloads
Bulk actions complete with no extra data:
{ "job_id": "...", "status": "completed", "progress": 100, "total": 47, "processed": 47 }Per-item errors are swallowed inside the job — one bad order doesn't poison the batch. Inspect via the audit log / Stoq Admin if needed.
CSV exports terminate as ready and add the download fields:
{
"job_id": "exp_a8c3f01b9d2e4471",
"status": "ready",
"download_url": "https://...s3.amazonaws.com/...",
"file_name": "preorders_revenue_2026-01-01_2026-05-28.csv",
"row_count": 22,
"progress": 100
}The download URL is a 7-day pre-signed S3 link.
Polling cadence
- Bulk actions: poll every 5s for the first minute, then every 15s. Most bulk jobs of <500 items complete in under 30s.
- CSV exports: poll every 10s. Large reports can take a few minutes.
- Always check rate-limit headers; polling is a GET and costs 1 point.
Caps and behavior
- Bulk order actions: max 1000 order IDs per submission. Exceeding the cap returns
422. - Bulk variant actions: max 5000 variant IDs per submission.
- Job retention: status records expire ~24h after completion. (Export download URLs stay valid for 7 days, but you can only fetch them from the status endpoint while the record exists.)
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 |
preorders/reports/*/export | GET /preorders/reports/exports/:job_id |
Some non-bulk writes are also asynchronous under the hood — e.g. the offer's products/add_variants and products/bulk_toggle_inventory_policy fan out to background jobs. See each resource page for the full list of bulk and export actions.
