API Reference
Use this page when you need the current request, response, and schema details for the Bulk Fill Public API. This page is generated from the current Public API contract source.
Base URL
[
"https://api.doqlo.com"
]
Authentication
All public endpoints on this page require BF export API key Bearer auth.
Authorization: Bearer doqlo_bfexp_<public_id>.<secret>
Endpoints
POST /v1/bulkfill/export-jobs
Create a Bulk Fill export job.
Submit a Bulk Fill export request with a source PDF, a reusable .doqlo configuration package exported from the web Bulk Fill editor, exactly one row-data input, and a required failed-row threshold. Create requests require Idempotency-Key for logical replay and may include optional X-Request-Id for tracing. If X-Request-Id is missing or invalid, Doqlo generates one and returns it in the response header. .doqlo package validation remains strict for malformed, tampered, unsupported, and non-code schema-invalid packages, but accepted jobs execute best-effort against the submitted PDF. Static QR/barcode overlays that are empty, invalid, or malformed are skipped at execution time and reported in manifest.json instead of failing an accepted job. PDF-context differences are also reported in manifest.json instead of causing create-time rejection. Read Reuse .doqlo Project Files Across PDFs for the product rationale and practical examples behind this flexibility. Threshold evaluation is runtime-only: once failed rows exceed max_failed_row_percent, Doqlo aborts immediately, exposes no deliverable artifact, and does not debit quota.
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key | header | Yes | string | Caller-provided logical create key. After a request passes auth, security checks, and front-door rate limiting, the same Idempotency-Key plus the same effective request body returns the same logical job state for 24 hours. The same key plus a different effective request body returns 409 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH. The same key after 24 hours is treated as a new request. Exactly one case-sensitive value is accepted. Allowed characters: A-Z, a-z, 0-9, ., _, :, -. Length: 1..128. UUID v4 or another high-entropy random string is recommended. |
X-Request-Id | header | No | string | Optional tracing and support correlation ID. This header is not used for idempotency. If omitted or invalid, Doqlo generates a request ID and returns it in the response header. The same validation envelope is accepted: exactly one case-sensitive value, 1..128 characters, pattern ^[A-Za-z0-9._:-]+$. |
Multipart form fields:
| Field | Required | Type | Description |
|---|---|---|---|
pdf | Yes | string (binary) | Source PDF file to execute against. It does not need to exactly match .doqlo source metadata; compatible PDF-context differences are reported in manifest.json when execution still succeeds. Read Reuse .doqlo Project Files Across PDFs for practical examples of this changed-PDF behavior. |
doqlo_file | Yes | string (binary) | Server-produced Bulk Fill .doqlo package exported from the web Bulk Fill editor. The public API executes this reusable configuration package; it does not accept field placements or mapping definitions directly. |
max_failed_row_percent | Yes | string | Required integer percent from 0 to 100. This is your explicit acceptance boundary for failed rows. Threshold evaluation is strict failed_row_percent > max_failed_row_percent. 0 aborts on the first failed row. 100 allows all requested rows to fail without threshold failure if the manifest/container still completes. It does not switch billing to pay-per-produced-file semantics. |
rows_json | Conditional | string | JSON string containing an array of row objects. Provide exactly one of rows_json or csv_file. Use object keys such as column_0, column_1, and column_2 to match the positional column IDs from your Bulk Fill layout. |
csv_file | Conditional | string (binary) | CSV upload. Provide exactly one of rows_json or csv_file. The public CSV contract is positional and does not auto-detect headers, so keep your mapped columns aligned to column_0, column_1, and later positions. |
include_stickers | No | string | Optional boolean string. Current values are true or false. Omit to use false. Set this to true when you want exported PDFs to keep visual stickers or markers, including sign-related visual markers where applicable. Leave it false when you want only the generated document content without those visual markers. |
flatten_forms | No | string | Optional boolean string. Current values are true or false. Omit to use false. Some PDFs contain interactive form fields, and generated overlays or content can otherwise appear behind those form layers. Set this to true to flatten those fields into static content so they do not cover the generated output. |
delivery_mode | No | response, webhook | Optional delivery mode. Omit to use response. Use response when you want the create call to return a terminal result inline when it settles quickly. Use webhook when you want terminal completion or failure sent to your HTTPS receiver. This controls how terminal job results are delivered, not how threshold or billing semantics work. |
webhook_url | No | string (uri) | Required when delivery_mode=webhook. Must be a public HTTPS receiver that can accept Doqlo terminal event delivery. The URL must use HTTPS, must not include userinfo, must not target localhost or private network addresses, and must not put credentials or signatures in query parameters. |
webhook_secret | No | string | Required when delivery_mode=webhook. Used to sign webhook deliveries so your receiver can verify authenticity. Omit it when delivery_mode=response. |
Constraints: Exactly one of the following field sets is required: rows_json | csv_file
Responses:
200
The job settled inside the sync wait window. In response mode this can include an inline completed result or a failed job envelope. In webhook mode the body can still return a completed or failed terminal job state, but webhook delivery remains the notification channel for downstream systems.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Current state of one public export job. Completed jobs can still contain partial or failed rows; inspect manifest.json in the ZIP artifact for row-level details.
Example - completed:
{
"job_id": "<job_id>",
"status": "completed",
"created_at": "<timestamp>",
"started_at": "<timestamp>",
"completed_at": "<timestamp>",
"result": {
"delivery_mode": "direct",
"download_url": "/v1/bulkfill/export-jobs/<job_id>/download",
"expires_at": "<timestamp>",
"file_size_bytes": "<file_size_bytes>"
}
}
Example - webhook_acknowledgement:
{
"job_id": "<job_id>",
"status": "completed",
"created_at": "<timestamp>",
"started_at": "<timestamp>",
"completed_at": "<timestamp>"
}
Example - webhook_threshold_failed:
{
"job_id": "<job_id>",
"status": "failed",
"created_at": "<timestamp>",
"started_at": "<timestamp>",
"completed_at": "<timestamp>",
"error": {
"code": "FAILED_ROW_THRESHOLD_EXCEEDED",
"message": "The export job exceeded max_failed_row_percent and was aborted.",
"details": {
"failure_class": "threshold_failed",
"input_row_count": 3,
"produced_row_count": 0,
"failed_row_count": 1,
"failed_row_percent": 33.3333,
"max_failed_row_percent": 0
}
}
}
202
The job was accepted but is still queued or processing. Keep the job_id and poll or wait for the terminal webhook if you chose webhook mode.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Current state of one public export job. Completed jobs can still contain partial or failed rows; inspect manifest.json in the ZIP artifact for row-level details.
400
Validation or request-shape failure, including missing or invalid Idempotency-Key (INVALID_IDEMPOTENCY_KEY).
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
401
Missing or invalid BF export API key.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
403
The authenticated account or key is not eligible for this request.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
409
Idempotency payload mismatch for Idempotency-Key (IDEMPOTENCY_KEY_PAYLOAD_MISMATCH).
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
413
Uploaded input or generated output would exceed current limits.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
422
The input document or batch request could not be accepted as valid work.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: Standard Public API error envelope.
429
Rate limit exceeded, or new create requests are temporarily blocked after failure-heavy usage. These front-door protections run before idempotency replay lookup, so a retry can still return 429 before Doqlo evaluates a prior logical job.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - | |
Retry-After | integer | Seconds until the next create attempt is expected to succeed. Present for fixed rate limits and temporary safeguard cooldowns. |
Schema: GenericRateLimitedErrorResponse | CreateCooldownErrorResponse
500
Unexpected server-side failure, or a response-mode job that settled failed inside the sync wait window.
Response headers:
| Header | Type | Description |
|---|---|---|
X-Request-Id | - |
Schema: ExportJob | ErrorResponse
{
"job_id": "<job_id>",
"status": "failed",
"created_at": "<timestamp>",
"started_at": "<timestamp>",
"completed_at": "<timestamp>",
"error": {
"code": "FAILED_ROW_THRESHOLD_EXCEEDED",
"message": "The export job exceeded max_failed_row_percent and was aborted.",
"details": {
"failure_class": "threshold_failed",
"input_row_count": 3,
"produced_row_count": 0,
"failed_row_count": 1,
"failed_row_percent": 33.3333,
"max_failed_row_percent": 0
}
}
}
GET /v1/bulkfill/export-jobs/{job_id}
Read the current state of one export job.
Use this route to poll a running job or re-read the final completed or failed state. Completed jobs expose a ZIP artifact whose manifest.json reports top-level diagnostics and per-row success, partial, or failed results. Failed jobs remain readable and may include threshold diagnostics when the runtime aborted after exceeding max_failed_row_percent.
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
job_id | path | Yes | string (uuid) | UUID for the accepted export job. |
Responses:
200
Current job state for an owned export job.
Schema: Current state of one public export job. Completed jobs can still contain partial or failed rows; inspect manifest.json in the ZIP artifact for row-level details.
Example - completed:
{
"job_id": "<job_id>",
"status": "completed",
"created_at": "<timestamp>",
"started_at": "<timestamp>",
"completed_at": "<timestamp>",
"result": {
"delivery_mode": "direct",
"download_url": "/v1/bulkfill/export-jobs/<job_id>/download",
"expires_at": "<timestamp>",
"file_size_bytes": "<file_size_bytes>"
}
}
Example - failed:
{
"job_id": "<job_id>",
"status": "failed",
"created_at": "<timestamp>",
"completed_at": "<timestamp>",
"error": {
"code": "FAILED_ROW_THRESHOLD_EXCEEDED",
"message": "The export job exceeded max_failed_row_percent and was aborted.",
"details": {
"failure_class": "threshold_failed",
"input_row_count": 3,
"produced_row_count": 0,
"failed_row_count": 1,
"failed_row_percent": 33.3333,
"max_failed_row_percent": 0
}
}
}
400
Invalid job_id format.
Schema: Standard Public API error envelope.
401
Missing or invalid BF export API key.
Schema: Standard Public API error envelope.
403
The authenticated key is not active.
Schema: Standard Public API error envelope.
404
Job not found or not owned by the authenticated account.
Schema: Standard Public API error envelope.
429
Rate limit exceeded.
Schema: Standard Public API error envelope.
500
Unexpected server-side failure.
Schema: Standard Public API error envelope.
GET /v1/bulkfill/export-jobs/{job_id}/download
Redeem the Doqlo-controlled download handle for a completed job.
Use -L or equivalent redirect-following support in your client because Doqlo may stream the file directly or return a redirect, depending on the current delivery mode. The ZIP artifact contains one produced row PDF per successful or partial row plus manifest.json version 2 with row-level status, counts, warnings, and row-fatal errors. Threshold-failed jobs never expose this route as a deliverable artifact.
Parameters:
| Name | In | Required | Type | Description |
|---|---|---|---|---|
job_id | path | Yes | string (uuid) | UUID for the completed export job. |
Responses:
200
The ZIP archive is streamed directly from Doqlo.
Schema: string (binary)
302
Doqlo resolved the authenticated download and redirected the client to the current provider handoff URL.
Response headers:
| Header | Type | Description |
|---|---|---|
Location | string (uri) | Resolved provider download URL for the authenticated delivery. |
400
Invalid job_id format.
Schema: Standard Public API error envelope.
401
Missing or invalid BF export API key.
Schema: Standard Public API error envelope.
403
The authenticated key is not active.
Schema: Standard Public API error envelope.
404
No active delivery is currently available for that job.
Schema: Standard Public API error envelope.
429
Rate limit exceeded.
Schema: Standard Public API error envelope.
500
The delivery exists but the current handoff failed. Retry later.
Schema: Standard Public API error envelope.
Schemas
CreateExportJobRequest
Multipart form body for a Bulk Fill export-job create request. The request uploads a reusable .doqlo configuration package, declares an explicit failed-row threshold, and executes it best-effort against the submitted PDF. Read Reuse .doqlo Project Files Across PDFs for the product rationale and practical examples behind changed-PDF reuse.
| Field | Required | Type | Description |
|---|---|---|---|
pdf | Yes | string (binary) | Source PDF file to execute against. It does not need to exactly match .doqlo source metadata; compatible PDF-context differences are reported in manifest.json when execution still succeeds. Read Reuse .doqlo Project Files Across PDFs for practical examples of this changed-PDF behavior. |
doqlo_file | Yes | string (binary) | Server-produced Bulk Fill .doqlo package exported from the web Bulk Fill editor. The public API executes this reusable configuration package; it does not accept field placements or mapping definitions directly. |
max_failed_row_percent | Yes | string | Required integer percent from 0 to 100. This is your explicit acceptance boundary for failed rows. Threshold evaluation is strict failed_row_percent > max_failed_row_percent. 0 aborts on the first failed row. 100 allows all requested rows to fail without threshold failure if the manifest/container still completes. It does not switch billing to pay-per-produced-file semantics. |
rows_json | Conditional | string | JSON string containing an array of row objects. Provide exactly one of rows_json or csv_file. Use object keys such as column_0, column_1, and column_2 to match the positional column IDs from your Bulk Fill layout. |
csv_file | Conditional | string (binary) | CSV upload. Provide exactly one of rows_json or csv_file. The public CSV contract is positional and does not auto-detect headers, so keep your mapped columns aligned to column_0, column_1, and later positions. |
include_stickers | No | string | Optional boolean string. Current values are true or false. Omit to use false. Set this to true when you want exported PDFs to keep visual stickers or markers, including sign-related visual markers where applicable. Leave it false when you want only the generated document content without those visual markers. |
flatten_forms | No | string | Optional boolean string. Current values are true or false. Omit to use false. Some PDFs contain interactive form fields, and generated overlays or content can otherwise appear behind those form layers. Set this to true to flatten those fields into static content so they do not cover the generated output. |
delivery_mode | No | response, webhook | Optional delivery mode. Omit to use response. Use response when you want the create call to return a terminal result inline when it settles quickly. Use webhook when you want terminal completion or failure sent to your HTTPS receiver. This controls how terminal job results are delivered, not how threshold or billing semantics work. |
webhook_url | No | string (uri) | Required when delivery_mode=webhook. Must be a public HTTPS receiver that can accept Doqlo terminal event delivery. The URL must use HTTPS, must not include userinfo, must not target localhost or private network addresses, and must not put credentials or signatures in query parameters. |
webhook_secret | No | string | Required when delivery_mode=webhook. Used to sign webhook deliveries so your receiver can verify authenticity. Omit it when delivery_mode=response. |
Constraints: Exactly one of the following field sets is required: rows_json | csv_file
ExportJob
Current state of one public export job. Completed jobs can still contain partial or failed rows; inspect manifest.json in the ZIP artifact for row-level details.
| Field | Required | Type | Description |
|---|---|---|---|
job_id | Yes | string (uuid) | Accepted export-job identifier. |
status | Yes | queued, processing, completed, failed | Current export-job status. |
created_at | Yes | string (date-time) | When Doqlo created the job. |
started_at | No | string | null | When processing started, when available. |
completed_at | No | string | null | When the job reached a terminal state, when available. |
result | No | ExportJobResult | Present only when the job completed and a current delivery record is available. |
error | No | ExportJobError | Present only when the job reached a terminal failed state. |
ExportJobResult
Result payload returned for completed jobs. Use the ZIP artifact and manifest.json to understand produced, partial, failed, and skipped outcomes.
| Field | Required | Type | Description |
|---|---|---|---|
delivery_mode | No | direct, cloud | Current delivery handoff mode. |
download_url | No | string | null | Doqlo-controlled download handle for the completed job. |
expires_at | No | string | null | Current delivery expiry timestamp. |
file_size_bytes | No | integer | null | Current ZIP size in bytes. |
ExportJobError
Terminal error payload returned for failed jobs.
| Field | Required | Type | Description |
|---|---|---|---|
code | Yes | string | Terminal error code. |
message | Yes | string | Human-readable error message. |
details | No | ThresholdFailedJobErrorDetails | Threshold-failure diagnostics exposed when the job aborted after exceeding max_failed_row_percent. |
ThresholdFailedJobErrorDetails
Present when the job failed because failed rows exceeded the declared runtime threshold.
| Field | Required | Type | Description |
|---|---|---|---|
failure_class | Yes | threshold_failed | Structured failure class for jobs that aborted because the declared failed-row threshold was exceeded. |
input_row_count | Yes | integer | Total requested input rows in the job. |
produced_row_count | Yes | integer | Row PDFs produced before the job aborted. |
failed_row_count | Yes | integer | Rows that failed to produce an output PDF before or at the abort point. |
failed_row_percent | Yes | number | Observed failed-row percentage at the moment the threshold was exceeded. |
max_failed_row_percent | Yes | integer | The customer-declared failed-row threshold for this job. |
ErrorResponse
Standard Public API error envelope.
| Field | Required | Type | Description |
|---|---|---|---|
code | Yes | string | Stable error code. |
message | Yes | string | Human-readable explanation. |
GenericRateLimitedErrorResponse
Generic fixed-rate-limit denial envelope.
| Field | Required | Type | Description |
|---|---|---|---|
code | Yes | RATE_LIMITED | Stable fixed-rate-limit error code. |
message | Yes | string | Human-readable explanation. |
CreateCooldownErrorResponse
Create-only cooldown denial envelope returned after failure-heavy usage. Applies only to new create requests and does not affect status polling, downloads, or webhook delivery.
| Field | Required | Type | Description |
|---|---|---|---|
code | Yes | REPEATED_FAILED_JOBS_COOLDOWN, HIGH_FAIL_RATIO_COOLDOWN | Stable create-only cooldown error code. |
message | Yes | string | Human-readable explanation. |
retry_after_seconds | Yes | integer | Seconds until the next create attempt is expected to succeed if no new blocking conditions are introduced. |