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

Bundles

A master agreement and its four amendments are one contract, and a table asking about it should have one row. A bundle is that: several files that answer as a single subject.

What a bundle changes

A row points at either a file or a bundle. When it points at a bundle, the question is put to every document in it at once and the answer resolves across them — so "what is the notice period" reads the amendment that changed it rather than the original that did not.

Order and effect are yours to set. sortOrder is the sequence, effectiveAt is when a document took effect, and isPrimary marks the master. The role is a free-text label — "Master agreement", "Amendment 3" — that shows up alongside the document.

Bundles cost more to run

Answering a bundle means reading several documents for one cell, so a bundled row is charged the column's rate plus 4 credits per member past the third. A five-document bundle answering a 4-credit column costs 4 + 8 = 12 credits per cell.

A compositional column is charged on a gentler curve — 4 credits per six members rather than per member past three — because it spreads one retrieval budget across the bundle instead of reading each document separately. Five members cost it nothing extra.

Price it before you commit with the free run preview, which accounts for this.

Changing a bundle makes its answers stale

Every bundle carries documentsVersion, which increments when its membership changes. Cells record the version they were answered against, and any cell whose recorded version is behind comes back with stale: true.

Nothing re-runs automatically. Adding an amendment marks the row's answers as questionable and leaves them readable; running it again is a deliberate act that costs credits. That is the same rule editing a column's prompt follows.

Fifteen files

A bundle holds at most 15 files, and POST …/files accepts between 1 and 15 ids per call. If a subject genuinely has more documents than that, it is usually two subjects.

List bundles

GET/v2/workspaces/:workspaceId/bundles

Requires Read on the workspace

Bundles in the workspace, without their members — fetch one to see what is in it.

Request
curl https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": [  {
    "id": "bndl_C6yT4gN8kM2vB5xQ",
    "workspaceId": "wks_7Kq2mB4nR8vXpL3d",
    "name": "Acme MSA (as amended)",
    "color": "#404040",
    "documentsVersion": 3,
    "archivedAt": null,
    "createdAt": 1756108800000,
    "updatedAt": 1756195200000
  }]
}

Get a bundle

GET/v2/workspaces/:workspaceId/bundles/:bundleId

Requires Read on the workspace

The bundle and its membership. This is the only place the file list appears — a bundle's own object never carries it.

Request
curl https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": {
    "bundle": {
    "id": "bndl_C6yT4gN8kM2vB5xQ",
    "workspaceId": "wks_7Kq2mB4nR8vXpL3d",
    "name": "Acme MSA (as amended)",
    "color": "#404040",
    "documentsVersion": 3,
    "archivedAt": null,
    "createdAt": 1756108800000,
    "updatedAt": 1756195200000
  },
    "files": [
      {
        "fileId": "ds_M3xJ8pQ1vK5nB7wT",
        "isPrimary": true,
        "role": "Master agreement",
        "effectiveAt": 1704067200000,
        "sortOrder": 0,
        "createdAt": 1756108800000,
        "updatedAt": 1756108800000
      },
      {
        "fileId": "ds_K2nV7cX4jL9bR1sD",
        "isPrimary": false,
        "role": "Amendment 1",
        "effectiveAt": 1727740800000,
        "sortOrder": 1,
        "createdAt": 1756195200000,
        "updatedAt": 1756195200000
      }
    ]
  }
}

Create a bundle

POST/v2/workspaces/:workspaceId/bundles

Requires Read & write on the workspace

Creates the bundle and, optionally, populates it in the same call. The response is the bundle alone — fetch it to see the members back.

Parameters

namestring · required1–120 characters.
fileIdsstring[]Up to 15 ids, each starting ds_. They take sortOrder in the order given, and the first becomes isPrimary.
colorstring | nullUp to 16 characters. Presentation only; nothing reads it.
Request
curl -X POST https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles \
  -H "x-api-key: $RAGEXTRACT_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "name": "Acme MSA (as amended)",
    "fileIds": ["ds_M3xJ8pQ1vK5nB7wT", "ds_K2nV7cX4jL9bR1sD"]
  }'
Response
{
  "success": true,
  "total": 1,
  "data": {
  "id": "bndl_C6yT4gN8kM2vB5xQ",
  "workspaceId": "wks_7Kq2mB4nR8vXpL3d",
  "name": "Acme MSA (as amended)",
  "color": "#404040",
  "documentsVersion": 1,
  "archivedAt": null,
  "createdAt": 1756108800000,
  "updatedAt": 1756108800000
}
}

Add files to a bundle

POST/v2/workspaces/:workspaceId/bundles/:bundleId/files

Requires Read & write on the workspace

Adds one or more files and returns the bundle with its full membership. documentsVersion increments, which marks every cell on rows pointing at this bundle as stale.

role and effectiveAt apply to every id in the call, so send one request per distinct role. isPrimary is different — it applies to the first id only, because a bundle has at most one anchor.

The call is all-or-nothing on validation: an id that is not a file in this workspace, or a batch that would take the bundle past 15, is refused with 400 before anything is written. Re-adding a file that is already a member is a no-op rather than an error, so retrying a half-failed call is safe.

Parameters

fileIdsstring[] · required1 to 15 ids, each starting ds_.
isPrimarybooleanMarks these as the master document of the bundle.
rolestring | nullUp to 120 characters. Free text — "Master agreement", "Amendment 3".
effectiveAtnumber | nullEpoch milliseconds. When this document took effect, which is what lets a later amendment supersede an earlier one.
Request
curl -X POST https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ/files \
  -H "x-api-key: $RAGEXTRACT_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "fileIds": ["ds_W9fH3rY6tP1nA8mE"],
    "role": "Amendment 2",
    "effectiveAt": 1735689600000
  }'
Response
{
  "success": true,
  "total": 1,
  "data": {
    "bundle": { "id": "bndl_C6yT4gN8kM2vB5xQ", "documentsVersion": 4, ... },
    "files": [ ... ]
  }
}

Change a file's role in a bundle

PATCH/v2/workspaces/:workspaceId/bundles/:bundleId/files/:fileId

Requires Read & write on the workspace

Changes how a document sits inside the bundle without changing which documents are in it. Every field is optional; omitted ones are left alone.

Parameters

isPrimarybooleanMake this the master document.
rolestring | nullUp to 120 characters.
effectiveAtnumber | nullEpoch milliseconds.
sortOrdernumberInteger, 0 or above.
Request
curl -X PATCH https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ/files/ds_K2nV7cX4jL9bR1sD \
  -H "x-api-key: $RAGEXTRACT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"role": "Amendment 1 (superseded)", "sortOrder": 2}'
Response
{
  "success": true,
  "total": 1,
  "data": {
    "fileId": "ds_K2nV7cX4jL9bR1sD",
    "isPrimary": false,
    "role": "Amendment 1 (superseded)",
    "effectiveAt": 1727740800000,
    "sortOrder": 2,
    "createdAt": 1756195200000,
    "updatedAt": 1756281600000
  }
}

Remove a file from a bundle

DELETE/v2/workspaces/:workspaceId/bundles/:bundleId/files/:fileId

Requires Read & write on the workspace

Takes the file out of the bundle. The file itself is untouched — it stays in the workspace and stays indexed. documentsVersion increments, so the bundle's answers go stale.

Request
curl -X DELETE https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ/files/ds_K2nV7cX4jL9bR1sD \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1
}

Rename a bundle

PATCH/v2/workspaces/:workspaceId/bundles/:bundleId

Requires Read & write on the workspace

Name and colour only. Neither is read by extraction, so this does not make anything stale.

Parameters

namestring1–120 characters.
colorstring | nullUp to 16 characters.
Request
curl -X PATCH https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ \
  -H "x-api-key: $RAGEXTRACT_API_KEY" \
  -H "content-type: application/json" \
  -d '{"name": "Acme MSA (as amended to Dec 2026)"}'
Response
{
  "success": true,
  "total": 1,
  "data": {
  "id": "bndl_C6yT4gN8kM2vB5xQ",
  "workspaceId": "wks_7Kq2mB4nR8vXpL3d",
  "name": "Acme MSA (as amended to Dec 2026)",
  "color": "#404040",
  "documentsVersion": 3,
  "archivedAt": null,
  "createdAt": 1756108800000,
  "updatedAt": 1756195200000
}
}

Archive a bundle

DELETE/v2/workspaces/:workspaceId/bundles/:bundleId

Requires Read & write on the workspace

Archives rather than deletes — the response carries the archivedAt stamp it set. The files stay in the workspace.

Request
curl -X DELETE https://api.ragextract.com/v2/workspaces/wks_7Kq2mB4nR8vXpL3d/bundles/bndl_C6yT4gN8kM2vB5xQ \
  -H "x-api-key: $RAGEXTRACT_API_KEY"
Response
{
  "success": true,
  "total": 1,
  "data": {
  "id": "bndl_C6yT4gN8kM2vB5xQ",
  "workspaceId": "wks_7Kq2mB4nR8vXpL3d",
  "name": "Acme MSA (as amended)",
  "color": "#404040",
  "documentsVersion": 3,
  "archivedAt": 1756281600000,
  "createdAt": 1756108800000,
  "updatedAt": 1756195200000
}
}