Skip to content
RagextractAPIStart freeSign-up and sign-in are temporarily unavailable — please check back shortly.

Jobs

Ingest is asynchronous. Uploading a document returns a job, and the document is not queryable until that job finishes. This is how you watch it.

Statuses

statusApp labelMeans
NOT_STARTEDPendingUploaded, not yet picked up. Also what a null status means.
IN_QUEUEQueuedWaiting for a free slot. The organisation's tier caps how many jobs run at once — 2 at Starter, 16 at Gold — and work over that cap waits. It is never refused: a tier governs how fast work drains, not whether it happens.
IN_PROGRESSProcessingBeing read, split and indexed. Credits are spent here, per page.
SUCCESSReadyDone. The file is queryable, and its pages exist.
ERRORFailedSomething went wrong — or the job was cancelled. statusText carries which; see below.

Uploading documents is the same vocabulary in customer language. Two things to build against: status can be null — the underlying column permits it, and an absent status means NOT_STARTED, never "finished" — and the two terminal states are SUCCESS and ERROR. There is no CANCELED status on an ingest job.

These three responses say datasetId

Everywhere else in v2, an uploaded document is a file and its id field is fileId. The three endpoints on this page are the exception: they answer datasetId, because they are the v1 handlers mounted unchanged. The value is the same ds_… id.

POST /files and POST /files/upload_session/end return a job through a different handler and do say fileId. So a client that uploads and then polls has to read both spellings for the same field.

List jobs

GET/v2/workspaces/:workspaceId/jobs

Requires Read on the workspace

Jobs in the workspace. The response echoes the statuses filter it applied, which is worth reading back if you are building a dashboard.

Filtering to the three unfinished statuses is the cheap way to answer "is anything still ingesting" without holding a list of job ids.

Query parameters

statusesstringComma-separated statuses to include. Omit for all.
offsetnumberRows to skip. Default 0.
limitnumberRows to return. Default 10, clamped to 100.
Request
curl "https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/jobs?statuses=NOT_STARTED,IN_QUEUE,IN_PROGRESS" \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": [  {
    "id": "dsj_L8vB2mQ6xR3kW9pZ",
    "datasetId": "ds_M3xJ8pQ1vK5nB7wT",
    "type": "extract",
    "status": "IN_PROGRESS",
    "statusText": null,
    "startedAt": 1756108830000,
    "finishedAt": null,
    "canceledAt": null,
    "createdAt": 1756108800000,
    "updatedAt": 1756108830000
  }],
  "offset": 0,
  "limit": 10,
  "statuses": ["NOT_STARTED", "IN_QUEUE", "IN_PROGRESS"]
}

Get a job

GET/v2/workspaces/:workspaceId/jobs/:jobId

Requires Read on the workspace

One job. This is what you poll after an upload. There is no webhook and no long-poll — poll on a back-off, and remember the read limit is 100 requests a minute per key, which is generous for one upload and not for a thousand.

A large document can sit at IN_QUEUE for a while on a low tier without anything being wrong.

Request
curl https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/jobs/dsj_L8vB2mQ6xR3kW9pZ \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": {
  "id": "dsj_L8vB2mQ6xR3kW9pZ",
  "datasetId": "ds_M3xJ8pQ1vK5nB7wT",
  "type": "extract",
  "status": "IN_PROGRESS",
  "statusText": null,
  "startedAt": 1756108830000,
  "finishedAt": null,
  "canceledAt": null,
  "createdAt": 1756108800000,
  "updatedAt": 1756108830000
}
}

Cancel a job

POST/v2/workspaces/:workspaceId/jobs/:jobId/cancel

Requires Read & write on the workspace

POST, not DELETE. v1 overloaded DELETE for this, which reads as destroying the record — the job row survives cancellation and is exactly what you poll afterwards, so v2 gave it its own verb.

A cancelled job comes back as ERROR with statusText: "Canceled", and finishedAt — not canceledAt, which stays null. There is no separate cancelled state, so a client distinguishing "failed" from "stopped on purpose" has to read statusText.

Pages already read have already been charged. Cancelling stops further work; it is not a refund.

An unknown job id answers 400 here rather than 404.

Request
curl -X POST https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/jobs/dsj_L8vB2mQ6xR3kW9pZ/cancel \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": {
    "id": "dsj_L8vB2mQ6xR3kW9pZ",
    "datasetId": "ds_M3xJ8pQ1vK5nB7wT",
    "type": "extract",
    "status": "ERROR",
    "statusText": "Canceled",
    "startedAt": 1756108830000,
    "finishedAt": 1756108900000,
    "canceledAt": null,
    "createdAt": 1756108800000,
    "updatedAt": 1756108900000
  }
}