M15 · REST API reference

The extraction workflow,
endpoint by endpoint.

M15 ships five pre-built REST endpoints that form a complete async pipeline: stage raw bytes, batch them into a persistent document record, wait for background processing, submit extraction jobs, and retrieve structured results. Here is exactly what each call expects and returns.

At a glance

Five phases, one pipeline.

Endpoint paths are relative to their configured service base URLs. The media and PDF extraction services may have different base URLs, but both require the application's authenticated API client.

PhaseEndpointProduces
1 Stage file bytesPOST/media/stage-media-file-in-chunksclient-generated fileId, reused as stagedFileCode
2 Create upload batchPOST/pdf-extraction/upload-document-batchbatchId (upload batch)
3 Poll upload batchGET/pdf-extraction/batch/{batchId}blobId per uploaded item
4 Submit extraction jobsPOST/pdf-extraction/submit-batchbatchId (extraction batch)
5 Poll extraction batchGET/pdf-extraction/batch/{batchId}jobId per extraction item
01

Stage the selected file in binary chunks

POST/media/stage-media-file-in-chunks?fileId={fileId}&offset={byteOffset}

Render the CleenUI Dropzone and provide its onFileUpload callback. The callback generates a stable UUID for each file, splits the file into binary chunks, sends every chunk with its absolute byte offset, and reports upload progress through updateFile.

tsx
const CHUNK_SIZE = 4 * 1024 * 1024; // 4 MB chunks

const stageFile = async (fileEntry, updateFile) => {
  const stagedFileCode = crypto.randomUUID();
  const chunks = [];

  for (let offset = 0; offset < fileEntry.file.size; offset += CHUNK_SIZE) {
    chunks.push({
      body: fileEntry.file.slice(offset, offset + CHUNK_SIZE),
      offset,
    });
  }

  await Promise.all(
    chunks.map(async ({ body, offset }, index) => {
      await mediaApi.stageMediaFileInChunks({
        fileId: stagedFileCode,
        offset,
        chunk: body,    // raw bytes · Content-Type: application/octet-stream
      });
      updateFile?.({ progress: (index + 1) / chunks.length });
    })
  );

  return { ...fileEntry, id: stagedFileCode };
};

// Wire to the CleenUI Dropzone component:
<Dropzone
  accept=".pdf,image/png,image/jpeg"
  onFileUpload={stageFile}
  showUploadedFiles
/>

The staging endpoint stores bytes temporarily in memory only — no permanent record is created, no document is parsed, no extraction begins. The client owns the generated UUID; carry it alongside the selected file because it becomes stagedFileCode in step 2. Use a separate fileId per file and do not proceed until every chunk across every selected file has successfully uploaded.

02

Convert staged files into an upload batch

POST/pdf-extraction/upload-document-batch

After all files are staged, call this endpoint. It captures the temporary bytes, creates a persistent document batch, parses and encrypts each document in the background, stores successful files, and releases the staged in-memory bytes.

Request body
json
{
  "items": [
    {
      "extractionTypeCode": "YOUR_EXTRACTION_TYPE",
      "stagedFileCode": "78962f79-97d0-41a2-99ae-6eb758d13c5a",
      "password": null,
      "originalFilename": "TaxReturn2025.pdf",
      "hints": null
    }
  ]
}
Response — 202 Accepted
json
{
  "batchId": "8a14dc31-c6cb-4ecd-a7bf-2e7d42530c14",
  "status": "Pending",
  "totalItems": 1
}
extractionTypeCodeIdentifies the configured extraction workflow or document type.
stagedFileCodeThe UUID generated and used as fileId while staging in step 1.
passwordThe PDF password when required; null otherwise.
originalFilenameUser-visible filename, including extension.
hintsOptional extraction-specific metadata; null when not needed.

Persist batchId — it is the key for polling in step 3. The API responds with 202 Accepted because processing continues asynchronously in the background.

03

Poll the upload batch

GET/pdf-extraction/batch/{batchId}

Poll this endpoint until the batch reaches a terminal state. A typical client polls every eight seconds, stops polling when the view is abandoned, and enforces a maximum attempt count or overall timeout.

While processing
json
{
  "batchId": "8a14dc31-c6cb-4ecd-a7bf-2e7d42530c14",
  "batchType": "UPLOAD_DOCUMENTS",
  "status": "Pending",
  "totalItems": 1,
  "completedItems": 0,
  "succeededItems": 0,
  "failedItems": 0,
  "createdUtc": "2026-07-15T01:00:28.1055312",
  "completedUtc": null,
  "items": [
    {
      "index": 0,
      "status": "Running",
      "blobId": null,
      "jobId": null,
      "errorCode": null,
      "errorMessage": null
    }
  ]
}
On completion
json
{
  "batchId": "8a14dc31-c6cb-4ecd-a7bf-2e7d42530c14",
  "batchType": "UPLOAD_DOCUMENTS",
  "status": "Completed",
  "totalItems": 1,
  "completedItems": 1,
  "succeededItems": 1,
  "failedItems": 0,
  "createdUtc": "2026-07-15T01:00:28.1055312",
  "completedUtc": "2026-07-15T01:00:30.0046745",
  "items": [
    {
      "index": 0,
      "status": "Completed",
      "blobId": 121387,
      "jobId": null,
      "errorCode": null,
      "errorMessage": null
    }
  ]
}

Batch status values

Pending
The batch exists; not all background work has started yet.
Running
At least one item is actively processing.
Completed
All items completed successfully.
CompletedWithErrors
Processing stopped; one or more items failed.

The batch-level status describes the aggregate state. Each item also carries its own status, so an item can be Running while the aggregate batch still reports Pending.

Only proceed to step 4 with items whose status is Completed and whose blobId is populated. For partial failures, surface the failed filename with its errorMessage and allow the user to retry or continue with the successful items.

04

Submit extraction jobs

POST/pdf-extraction/submit-batch

After the upload batch completes, submit the extraction jobs. Create one request item per successfully uploaded file and copy that item's blobId into extractionUploadBlobId.

Request body
json
[
  {
    "responseSetId": 1025,
    "extractionTypeCode": "YOUR_EXTRACTION_TYPE",
    "forEntityTypeId": 56,
    "forEntityId": 1025,
    "hints": null,
    "extractionUploadBlobId": 121387
  }
]
Response — 202 Accepted
json
{
  "batchId": "7cb27722-3e91-4e8b-8468-ed632bf719c2",
  "status": "Pending",
  "totalItems": 1
}
responseSetIdThe response set that will receive the extracted values.
extractionTypeCodeThe extraction workflow to execute. Must match the code used during upload.
forEntityTypeIdThe type ID of the domain entity associated with this extraction job.
forEntityIdThe ID of the specific domain entity.
hintsOptional workflow-specific hints such as a known form type; null when not needed.
extractionUploadBlobIdThe blobId from the completed upload item in step 3.

This call produces a second, distinct batchId. The first tracked document upload and produced blobId values. This one tracks extraction-job creation and produces jobId values. Keep the two batch identifiers separate — they refer to different async processes.

05

Poll the extraction batch and retrieve results

GET/pdf-extraction/batch/{batchId}

Poll the same batch endpoint, this time with the extraction batchId. For this batch, batchType is SUBMIT_JOBS. A successfully completed item has a jobId. Pass each jobId to the status endpoint to retrieve the extracted field values.

GET/pdf-extraction/status/{jobId}

UI state ↔ API condition

What the user seesAPI condition
Upload progressChunks are being sent to stage-media-file-in-chunks
ProcessingEither batch is Pending or Running
Review extracted valuesExtraction jobs completed and returned extracted values
Partial failureBatch is CompletedWithErrors; at least one item has errorCode
Apply / saveUser confirmed the values; product persisted them to the backend
Implementation notes

Safeguards built into the workflow.

These constraints separate a reliable document pipeline from one that silently drops files or duplicates submissions.

01

Authenticated client only

Use the application's authenticated API client. Do not place tokens in component code or Storybook stories.

02

Five separate identifiers

Keep the file's stagedFileCode, upload-batch batchId, blobId, extraction-batch batchId, and jobId as distinct values.

03

Gate Continue on full upload

Disable the Continue button until every selected file is fully staged across all chunks.

04

Cancel polling on unmount

Cancel the polling cycle when the component unmounts or the user cancels the flow.

05

Two terminal states

Treat both Completed and CompletedWithErrors as terminal. Do not wait for a state that will never arrive.

06

Never pass a missing blobId

Only submit extraction jobs for items whose blobId is present and whose upload status is Completed.

07

Surface errors per file

Show errorCode and errorMessage per failed file. Do not discard successful items because one item failed.

08

Prevent duplicate submission

Disable batch submission while a request or poll cycle is active.

This workflow ships with the license.

Every endpoint, the chunked-upload React component, the batch-polling logic, and the C# controller code behind each call — all included in M15 on day one of your engagement.