Submit a job
Create jobs by posting one or more files to a pipeline. Each file becomes its own job; processing is asynchronous by default, and the response returns as soon as the job is queued.
Request
jobs:writeSend multipart/form-data. Every parameter is a form field; the text parameters are also accepted in the query string.
| Parameter | Type | Description |
|---|---|---|
files (required) | file | The document. Repeat the field to submit several files — each becomes a separate job. PDF, DOCX, PNG, JPEG, TIFF, BMP, GIF or WebP, up to 100 MB. A pipeline can accept a narrower set. |
pipeline_id | string | The pipeline to run. See Pipeline selection. |
pipeline_version | integer | Run a specific version of the pipeline, draft or published. Defaults to the latest published version. |
schema_id | string | The extraction schema to use. When omitted, the pipeline's catch-all routing rule decides. |
priority | string | standard (default) or high. |
client_reference_id | string | Your own reference. Stored on the job and echoed back; not used to detect duplicates. |
environment | string | production or test — which Jobs tab the job appears on. When omitted, the job is tagged production. See Authentication. |
mode | string | async (default) or sync. Any other value is treated as async. |
curl -X POST https://api.us.idpforge.cloud/v1/jobs \
-H "X-API-Key: $IDP_API_KEY" \
-F "files=@Globex-INV-4471.pdf" \
-F "pipeline_id=$PIPELINE_ID" \
-F "client_reference_id=ap-inbox-4471"Response
An async submission returns 202 Accepted with an array holding one object per uploaded file, in upload order.
| Field | Description |
|---|---|
job_id | The new job's id. |
status | queued for an async submission; processing for a sync job that is still running (see below). |
execution_mode | async, or sync for a sync job that is still running. |
status_url | Absolute URL of the job. GET it to poll status. |
result_url | The same URL with include=result. |
degradation_reason | Set when you asked for mode=sync but got this object back instead of a finished job. sync_budget_exceeded means the job took longer than the sync window and is still running — poll status_url. |
submitted_at | When the job was accepted. |
client_reference_id | Present when you sent one. |
A sync submission waits for each job to finish and returns 200 OK with an array of full job objects — the shape GET /v1/jobs/{job_id} returns with include=stages,result.
When a sync job takes too long
A sync request waits about 50 seconds in total, across all of its files. If processing runs longer, you get 202 Accepted instead of 200, and the job keeps running. Each entry in the array is then either a finished job or an accepted job whose status is processing and whose degradation_reason is sync_budget_exceeded — poll its status_url until it finishes. Files that hadn't started when the window closed are queued as async jobs with the same degradation_reason.
Files in a multi-file request are processed in order. If a later file is rejected, the jobs already created for earlier files stand, and the response is the error.
[
{
"job_id": "01a08dcc-a671-7a63-a2e2-dec7c6ecbb38",
"status": "queued",
"execution_mode": "async",
"status_url": "https://api.us.idpforge.cloud/v1/jobs/01a08dcc-a671-7a63-a2e2-dec7c6ecbb38",
"result_url": "https://api.us.idpforge.cloud/v1/jobs/01a08dcc-a671-7a63-a2e2-dec7c6ecbb38?include=result",
"submitted_at": "2026-09-11T00:09:55.315027355Z",
"client_reference_id": "ap-inbox-4471"
}
][
{
"job_id": "01a08dcc-a671-7a63-a2e2-dec7c6ecbb38",
"status": "processing",
"execution_mode": "sync",
"status_url": "https://api.us.idpforge.cloud/v1/jobs/01a08dcc-a671-7a63-a2e2-dec7c6ecbb38",
"result_url": "https://api.us.idpforge.cloud/v1/jobs/01a08dcc-a671-7a63-a2e2-dec7c6ecbb38?include=result",
"submitted_at": "2026-10-07T10:00:00Z",
"degradation_reason": "sync_budget_exceeded"
}
]Pipeline selection
The pipeline is chosen in this order:
pipeline_idon the request — it always wins, including over the key's own pipeline.- The pipeline the key is bound to. A key restricted to exactly one pipeline counts as bound to it.
- The workspace's default pipeline, and failing that a platform-provided parse pipeline.
Pass pipeline_id unless the key is bound to a single pipeline. In Studio, the API endpoint card on a pipeline's Versions tab shows its pipeline_id.
Errors
| Status | error | Meaning |
|---|---|---|
400 | MISSING_PART | No files field — for example, the file was sent as file. |
400 | MISSING_FILE | A files part was empty. |
400 | PIPELINE_NOT_PUBLISHED | The pipeline has no published version and no pipeline_version was given. |
402 | PAYMENT_REQUIRED | Not enough credits, or the job would exceed the workspace's spending cap. No job is created. |
404 | VERSION_NOT_FOUND | The requested pipeline_version does not exist. |
413 | FILE_TOO_LARGE | The upload exceeds the 100 MB limit. |
422 | UNSUPPORTED_FILE_TYPE | The file type is not accepted by the platform or by this pipeline. |
422 | FILE_TOO_LARGE | The file exceeds this pipeline's size limit. |
Credits
Submitting a job reserves credits before it is queued. If the balance is too low, the submission is rejected with 402 Payment Required and no job is created. The reservation settles to what the job actually used. Jobs tagged test reserve and consume credits exactly like production jobs. See Credits.
Job status
jobs:readinclude adds optional blocks, comma-separated:
| Value | Adds |
|---|---|
stages | stages — per-stage progress, timings and credits. |
result | result — the job's output, returned only when status is completed. |
A job moves through these statuses:
| Status | Meaning |
|---|---|
queued | Accepted and waiting to start. |
preprocessing | The file is being normalised. |
processing | Pipeline stages are running. |
awaiting_review | Paused for human review. |
completed | Every stage finished. include=result returns the output. |
completed_with_errors | Finished, but at least one stage failed. error names the first failing stage. |
failed | An unrecoverable error stopped the job. error carries code, message and stage. |
timed_out | A synchronous job exceeded its timeout. |
cancelled | Cancelled with POST /v1/jobs/{job_id}/cancel, which requires jobs:cancel. |
blocked | A failure that needs an operator parked the job. Not final — an operator fix re-runs it. |
partial | Some documents moved on while others are held for an operator. Not final. |
An unknown id returns 404 with the code job_not_found. A well-formed id for a job that has aged out of retention returns job_expired.
{
"job_id": "0191f3a2-7c4e-7b1d-9a55-3e0c8f2d6b41",
"status": "completed",
"api_type": "extract",
"execution_mode": "async",
"priority": "standard",
"input": {
"file_name": "Globex-INV-4471.pdf",
"mime_type": "application/pdf",
"page_count": 1
},
"created_at": "2026-09-11T06:12:44.318Z",
"completed_at": "2026-09-11T06:13:58.402Z",
"total_time_taken_ms": 74084,
"client_reference_id": "ap-inbox-4471"
}Retention
Jobs, their results and their documents are retained for 24 hours after submission. After that a job ages out: its result and documents are deleted, and GET /v1/jobs/{job_id} returns job_expired. Read or deliver what you need within that window, or subscribe to a webhook so the result reaches you as soon as it is ready.