Home
Guide

Bulk & Async Jobs

How to submit and poll long-running operations: bulk actions and CSV exports.

Three classes of v2 action return a job handle instead of a synchronous result:

  • Bulk order actionsbulk_release, bulk_cancel, bulk_set_tags, bulk_send_payment_collection_url.
  • Bulk variant administrationbulk_recalculate_preorder_counts, bulk_reset_metafields, bulk_sync_metafields.
  • CSV exports — every report has a paired */export action.

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
}
  • progress is a percentage (0–100); total / processed are item counts.
  • error is present when the job failed.

status is one of:

StatusMeaning
runningQueued or being processed by a worker
completedDone (bulk jobs)
readyDone, download available (CSV exports)
failedJob failed — see error
cancelledOperator 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:

ResourceJob endpoint
preorders/orders/bulk_*GET /preorders/orders/jobs/:job_id
preorders/product_variants/bulk_*GET /preorders/product_variants/jobs/:job_id
preorders/reports/*/exportGET /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.