Skip to main content

Job Lifecycle

Use this page when you need to understand how an accepted export request moves from creation to a terminal result.

What A Job Represents

The Public API is job-based because Bulk Fill exports do not always settle inside one request window. Once Doqlo accepts a request, the accepted work is represented by one job_id that you can poll or track by webhook.

Current Job States

StatusMeaningWhat you should do
queuedThe job was accepted but has not started processing yetKeep the job_id and poll or wait for a webhook
processingThe job is currently being generatedKeep polling or wait for a webhook
completedThe export artifact is readyRead result.download_url and download the ZIP
failedThe job ended without a usable resultRead error.code and error.message, then retry or investigate

completed means the ZIP artifact exists. It does not require every requested row to have produced a PDF.

Threshold note:

  • Doqlo evaluates max_failed_row_percent during runtime, not after the whole batch finishes.
  • Threshold accounting uses failed rows only.
  • When failed rows exceed the declared threshold, the job aborts immediately, stays failed, exposes no result artifact, and does not debit quota.

Typical Success Flow

  1. Submit POST /v1/bulkfill/export-jobs.
  2. Record the returned job_id.
  3. If the create response is already completed, download immediately.
  4. If the create response is queued or processing, poll GET /v1/bulkfill/export-jobs/{job_id} or wait for a webhook.
  5. When the job becomes completed, redeem /v1/bulkfill/export-jobs/{job_id}/download.

Create Idempotency

Idempotency-Key identifies one logical create request within a fixed 24-hour window.

  • same Idempotency-Key + same effective body returns the current/latest state of the same logical job_id
  • same Idempotency-Key + different effective body returns 409 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH
  • same Idempotency-Key after 24 hours is treated as a new request

Front-door auth, security checks, and create-side rate limiting run before that replay lookup. A retry can still return 429 before Doqlo reaches the idempotency layer.

X-Request-Id is separate tracing only. If you omit it, Doqlo generates one and returns it in the response header.

Typical Failure Flow

  1. Submit the create request.
  2. Record the job_id.
  3. Poll or wait for the webhook.
  4. If the job becomes failed, inspect the structured error payload.
  5. Fix the request or operational issue, then submit a new request with a new Idempotency-Key.

Response Mode Versus Webhook Mode

delivery_mode changes how you learn about terminal results. It does not change the job states.

  • response mode returns the result payload inline when the job settles inside the sync wait window.
  • webhook mode omits result from the create response and sends terminal completion or failure to your webhook target.

In both modes:

  • GET /v1/bulkfill/export-jobs/{job_id} stays available
  • GET /v1/bulkfill/export-jobs/{job_id}/download is only valid after completed
  • delivery_mode does not change billing or quota semantics
  • GET and download redemption do not emit new terminal webhook events
  • polling and download redemption do not create a new generation charge

What The ZIP Contains

Completed jobs download a ZIP artifact with:

  • one produced row PDF for each success or partial row
  • manifest.json version 2

manifest.json reports:

  • top-level diagnostics when .doqlo source metadata differs from the submitted PDF
  • summary.produced_rows, success_rows, partial_rows, and failed_rows
  • one row_results[] entry per requested row

Read Reuse .doqlo Project Files Across PDFs for the product rationale and practical examples behind this changed-PDF behavior.

Row status rules:

  • success: row PDF produced and no overlays were skipped
  • partial: row PDF produced and at least one overlay was skipped, or zero overlays were applied
  • failed: no row PDF was produced

Common partial cases include QR/barcode overlays that were skipped because a static value was invalid or because a mapped row value was blank, missing, or invalid for the selected code format.

Important Notes

  • A later request can complete immediately from a same-account reuse hit. You still get a new job_id.
  • A same-key replay does not create a new job_id; it returns the latest state of the original logical job.
  • The same logical job can still have different tracing request_id values across repeated HTTP retries.
  • A completed job can remain completed even after the active delivery is no longer available. In that case, result.download_url becomes null.
  • Failed jobs stay readable through GET so you can inspect the terminal error state.
  • A completed job can still include partial or failed rows. Use manifest.json to inspect what happened before deciding whether the archive is acceptable for your workflow.
  • Threshold-failed jobs may include error.details with input_row_count, produced_row_count, failed_row_count, failed_row_percent, and max_failed_row_percent.
  • Produced rows and billed rows are different concepts. Completed jobs remain billed by requested rows, while manifest.summary.produced_rows reports the row PDFs that were actually written.