Redactions API — PDF & image

This document describes HTTP request/response shapes used by the RedactStripe app for PDF and image redactions, aligned with:

Unless noted, paths are under the API base (e.g. VITE_API_URL), typically /api/redactions. Requests use session/JWT as enforced by requireSession on the API.


Shared: save redactions (batch write)

POST /api/redactions/:docId

Path parameter

NameTypeDescription
docIdintegerNumeric batch document id (not file-… style).

Request body (JSON)

{
  "redactions": [ /* see PDF vs image item shapes below */ ],
  "versionInfo": {
    "versionId": "string | null"
  }
}
FieldTypeRequiredDescription
redactionsarrayYesNon-empty. All items in one request must share the same FOIA layer (B1–B7).
versionInfoobjectNoOptimistic concurrency: versionId should match the server’s latest version for that layer, or omit/null on first save.

Success response (201)

{
  "success": true,
  "message": "Saved N redaction(s)",
  "count": 0,
  "version_id": "string",
  "version": 0,
  "layer": "B7"
}

The web PDF flow reads version_id and stores it per layer for the next save (useRedactionState).

Common error responses

StatusMeaning (examples)
400Missing/invalid redactions, mixed layers, invalid coordinates, invalid layer/classification.
404Document not found or access denied.
409Version conflict (versionInfo.versionId does not match currentVersion in body).
423Layer locked by another user (locked_by, etc. in body).

PDF redaction items (implemented in web + API)

The web app builds each saved item with toApiRedaction in useRedactionState.js (flat PDF bounds, not a nested rect object).

Request: one PDF redaction object (inside redactions[])

FieldTypeRequiredNotes
redaction_idstring (UUID)YesClient-generated id; persisted as redaction_id.
page_numberintegerYes≥ 1.
redaction_typestringYesClient sends tool type; "full_page" is normalized to "rectangle" for the API payload.
layerstringYesFOIA layer, e.g. B1–B7.
redaction_reasonstring | nullNo
classification_typestring | nullIf layer B1Otherwise sent as null.
pdf_x1, pdf_y1, pdf_x2, pdf_y2numberYesPDF coordinate space; finite; must form a box with positive width/height.
pdf_polygon_pointsarrayFor polygon/lasso/freehandServer expects ≥ 3 points when polygon-like; client sends [] for rectangles.

Example (rectangle)

{
  "redaction_id": "550e8400-e29b-41d4-a716-446655440000",
  "page_number": 1,
  "redaction_type": "rectangle",
  "layer": "B7",
  "redaction_reason": null,
  "classification_type": null,
  "pdf_x1": 72,
  "pdf_y1": 120,
  "pdf_x2": 300,
  "pdf_y2": 200,
  "pdf_polygon_points": []
}

Web behavior (what actually gets POSTed)

GET /api/redactions/:docId

Query (optional)

Success (200)

{
  "success": true,
  "redactions": [ /* stored box documents: PDF + image collections merged */ ],
  "count": 0,
  "allowedLayers": ["B1", "B2", "B3", "B4", "B5", "B6", "B7"],
  "version_ids": ["string"]
}

Each element in redactions is a stored record (Mongo shape). The web app maps entries into client state via mapApiRedactionToClient (expects fields like redaction_id, page_number, redaction_type, pdf_x1…pdf_y2, pdf_polygon_points, layer, etc.).

GET /api/redactions/:docId/layer/:layer

Returns redactions for the latest version of that layer for the document. Body includes version_id for that snapshot.


Image redaction items (server contract; web save not implemented)

The API chooses PDF vs image validation based on the batch document type (isImageBatchDocument). Image saves use image_redaction_boxes and accept image pixel bounds (or x/y + width/height).

Request: one image redaction object (inside redactions[])

Either full bounds:

FieldTypeRequired
image_x1, image_y1, image_x2, image_y2numberYes (unless using x/y + size below)

Or origin + size (server derives corners):

FieldTypeNotes
x, ynumberTop-left
width / w, height / hnumberUsed to compute image_x2 / image_y2

Also expected / supported (typical)

FieldTypeNotes
redaction_idstringRequired for upsert key with version_id.
layerstringB1–B7
redaction_type / typestringDefaults to rectangle in storage.
page_numberintegerOptional in builder; stored, defaults to 1 if omitted.
redaction_reason, classification_type, polygon metadata, etc.variousSame family of fields as PDF where applicable.

Example (rectangle in image pixel space)

{
  "redaction_id": "image-redaction-xxxxxxxx",
  "layer": "B7",
  "redaction_type": "rectangle",
  "page_number": 1,
  "image_x1": 10,
  "image_y1": 20,
  "image_x2": 110,
  "image_y2": 80,
  "redaction_reason": null,
  "classification_type": null
}

Important: The current Fabric image redaction page does not yet serialize Fabric objects into this payload or call POST /redactions/:docId. When implemented, coordinates should be in stable image space (e.g. natural image pixels), consistent with how the server validates and stores image_x1…image_y2.


Update / delete single box

PUT /api/redactions/box/:redactionId

Body (single update — simplified path)

Body (batch form)

{
  "redactionList": [
    {
      "redaction_id": "pdf-redaction-… | image-redaction-…",
      "version_id": "string",
      "updates": { }
    }
  ]
}

Response: 200 with per-item { redaction_id, version_id, success, message } for list form, or single-update result per service.

redaction_id prefix rules:

DELETE /api/redactions/box/:redactionId

Optional JSON body with redactionList: [{ "redaction_id", "version_id" }, …] for batch deletes; otherwise single-delete semantics per service.


Delete all redactions for a document

DELETE /api/redactions/:docId

Success (200)

{
  "success": true,
  "message": "Deleted redactions for document",
  "deletedCount": 0
}

Restrictions: Non-admins may only clear if they are the batch owner (see service).


Redaction types catalog

GET /api/redactions/types

Returns the payload from getRedactionTypesPayload() (tool/metadata catalog for UI). Used by the web layer config (useRedactionLayerConfig / similar).


Image redaction — current status (web)

AreaStatus
Open image from dashboardUses authorized batch document download URL + fetch + Bearer → blob URL for Fabric (imageDocumentApi.js).
Draw rectanglesFabric scene; viewport zoom/rotate applied to canvas (not individual object angles for view).
Save / load redactionsNot connected to POST/GET /redactions/:docId yet (ImageRedactionPage save handler is a stub).
Shared API moduleimage-redaction/api/imageRedactionsApi.js re-exports the same redactionsApi.js as PDF for future use.

When image save is implemented, expect the same POST /api/redactions/:docId envelope (redactions + versionInfo), with each item satisfying validateImageItem on the server.


Quick reference — web client wrappers

MethodFunctionFile
GETloadRedactionsApi(docId, layers)pdf-redaction/api/redactionsApi.js
DELETE alldeleteAllRedactionsApi(docId)same
DELETE boxdeleteRedactionBoxApi(redactionId, body?)same
PUT boxupdateRedactionBoxApi(redactionId, body)same
POST saveapiRequest(\/redactions/${docId}\, { method: "POST", body })useRedactionState.js (not wrapped in redactionsApi.js)

*Generated from repository behavior as of the docs authoring date; adjust if the API evolves.*