Template snapshot
{
"object": "okrapdf.workflow_template_snapshot",
"version": "okra.workflow_template_snapshot.v1",
"slug": "foia-redaction-workflow",
"template_id": "tpl_foia_redaction_workflow",
"name": "FOIA redaction workflow",
"vertical": "Government and public records",
"description": "Visual FOIA redaction workflow for PDFs: intake records, detect PII, review redactions, sanitize metadata, and publish an auditable link.",
"urls": {
"content": "https://workflows.okrapdf.com/workflows/foia-redaction-workflow",
"embed": "https://embed.okrapdf.com/workflows/foia-redaction-workflow",
"registry": "https://workflows.okrapdf.com/templates/foia-redaction-workflow",
"json": "https://workflows.okrapdf.com/templates/foia-redaction-workflow.json"
},
"execution_status": {
"label": "Schema-only template today",
"status": "schema_only",
"summary": "This FOIA redaction workflow can be created, inspected, embedded, and visualized today. It does not execute end-to-end yet because the deployed finite step runner only supports the invoice human-review subset.",
"createResult": "POST /v1/workflows with this definition returns object=workflow, execution_mode=step_definition, runnable=false, readiness.status=schema_only.",
"runResult": "POST /v1/runs against this workflow returns HTTP 409 with \"Workflow definition is schema-only; step execution is not deployed yet.\""
},
"example_runs": [
{
"id": "exrun_foia_county_email_release",
"title": "County email release package",
"summary": "A records team prepares a release package with staff emails, phone numbers, account numbers, and addresses that must be reviewed before publish.",
"status": "schema_only",
"visualArtifacts": [
{
"role": "before",
"label": "Before",
"title": "Source FOIA package PDF",
"badge": "Sensitive source",
"fileName": "county-email-release-source.pdf",
"pageLabel": "Page 2 of 6",
"pdfUrl": "https://workflows.okrapdf.com/workflow-assets/foia-redaction-workflow/examples/county-email-release/source.pdf",
"lines": [
{
"text": "County Public Works - Email Release",
"emphasis": true
},
{
"text": "From: Alex Chen <alex.chen@county.example>"
},
{
"text": "Phone: (555) 014-2198"
},
{
"text": "Resident account: ACCT-8842-19"
},
{
"text": "Address: 412 Oak Bend Road, Unit 7"
},
{
"text": "Decision: release after records-officer review"
}
]
},
{
"role": "after",
"label": "After",
"title": "Redacted derivative PDF",
"badge": "Publish candidate",
"fileName": "county-email-release-redacted.pdf",
"pageLabel": "Page 2 of 6",
"pdfUrl": "https://workflows.okrapdf.com/workflow-assets/foia-redaction-workflow/examples/county-email-release/redacted.pdf",
"lines": [
{
"text": "County Public Works - Email Release",
"emphasis": true
},
{
"text": "From: redacted staff email",
"redacted": true
},
{
"text": "Phone number redacted",
"redacted": true
},
{
"text": "Resident account redacted",
"redacted": true
},
{
"text": "Street address redacted",
"redacted": true
},
{
"text": "Decision: release after records-officer review"
}
]
}
],
"input": {
"pdf_url": "https://agency.example/records/foia-request-2026-019.pdf",
"redaction_policy": {
"pii": [
"ssn",
"email",
"phone",
"address",
"account_number"
],
"timing": "before_publish"
},
"reviewer": {
"role": "records_officer",
"approval_key": "foia-redaction"
},
"publish": {
"visibility": "signed",
"include_audit_manifest": true,
"include_proof_cards": true
}
},
"lifecycle": [
"create workflow definition",
"start run after the redaction/publish runner supports this step set",
"intake private source PDF",
"detect redaction candidates",
"wait for human.approval",
"apply true redactions",
"sanitize metadata, forms, and annotations",
"publish redacted derivative"
],
"output": {
"redacted_document_id": "doc_redacted_...",
"published_view": "https://app.okrapdf.com/view/...",
"redaction_decision_log": [
{
"page": 2,
"entity": "email",
"decision": "approved"
}
],
"audit_manifest": {
"source_document_id": "doc_source_...",
"derivative_document_id": "doc_redacted_...",
"reviewer": "records_officer"
}
},
"apiCalls": [
{
"label": "Create or import the workflow",
"method": "POST",
"path": "/v1/workflows",
"request": {
"name": "FOIA redaction workflow",
"definition": {
"steps": "see template snapshot"
}
},
"response": {
"object": "workflow",
"workflow_id": "wf_...",
"execution_mode": "step_definition",
"runnable": false,
"readiness": {
"status": "schema_only"
}
}
},
{
"label": "Attempt run today",
"method": "POST",
"path": "/v1/runs",
"request": {
"workflow_id": "wf_...",
"inputs": {
"pdf_url": "https://agency.example/records/foia-request-2026-019.pdf"
}
},
"response": {
"status": 409,
"error": "Workflow definition is schema-only; step execution is not deployed yet"
}
}
],
"notes": [
"This example run is attached to the FOIA workflow template for SEO, docs, and import screens.",
"It is not a standalone sample PDF and it is not a claim that the redaction/publish runner is live.",
"The same shape becomes executable when the deployed finite runner supports the redaction, approval, sanitize, and publish step set."
]
}
],
"definition": {
"object": "workflow_definition",
"version": "okra.workflow.definition.v1",
"steps": [
{
"id": "intake",
"type": "document.upload",
"name": "Intake private records",
"with": {
"file": "${inputs.pdf_file}",
"url": "${inputs.pdf_url}",
"visibility": "private"
}
},
{
"id": "detect",
"type": "document.redact",
"name": "Detect sensitive material",
"with": {
"document_id": "${steps.intake.document_id}",
"policy": {
"pii": [
"ssn",
"email",
"phone",
"address",
"account_number"
],
"timing": "before_publish"
},
"output": "redaction_plan"
},
"depends_on": [
"intake"
]
},
{
"id": "review",
"type": "human.approval",
"name": "Human review gate",
"with": {
"approval_key": "foia-redaction",
"prompt": "Approve redactions before publishing this public-records PDF.",
"event_type": "redaction-approval",
"timeout": "24 hours",
"on_timeout": "reject",
"context": {
"document_id": "${steps.intake.document_id}",
"redaction_plan": "${steps.detect.redaction_plan_id}"
}
},
"depends_on": [
"detect"
]
},
{
"id": "apply",
"type": "document.redact.apply",
"name": "Apply true redactions",
"with": {
"document_id": "${steps.intake.document_id}",
"redaction_plan": "${steps.detect.redaction_plan_id}",
"approval": "${steps.review.decision}",
"mode": "true_removal",
"output": "redacted_document"
},
"depends_on": [
"review"
]
},
{
"id": "sanitize",
"type": "document.sanitize",
"name": "Sanitize the derivative",
"with": {
"document_id": "${steps.apply.document_id}",
"remove_metadata": true,
"flatten_annotations": true,
"flatten_forms": true,
"output": "sanitized_document"
},
"depends_on": [
"apply"
]
},
{
"id": "publish",
"type": "document.publish.view",
"name": "Publish a safe view",
"with": {
"document_id": "${steps.sanitize.document_id}",
"source_document_id": "${steps.intake.document_id}",
"visibility": "signed",
"view_name": "FOIA redacted public view",
"include_audit_manifest": true,
"include_proof_cards": true
},
"depends_on": [
"sanitize"
]
}
]
},
"visualization": {
"object": "workflow_visualization",
"version": "okra.workflow.visualization.v1",
"projection": "data_pipeline_sequence_v1",
"source_ast_version": "okra.workflow.ast.v1",
"nodes": [
{
"id": "visual:start",
"ast_node_id": "start",
"kind": "start",
"title": "Start",
"rank": 0
},
{
"id": "visual:step:intake",
"ast_node_id": "step:intake",
"kind": "step",
"title": "Intake private records",
"subtitle": "document.upload",
"status": "defined",
"rank": 1,
"metadata": {
"category": "file_io",
"node_kind": "document.upload",
"output_contract": "private_source_document",
"output": "private_source_document",
"summary": "Upload the original PDF, URL, or folder batch as a private source. The original stays private and becomes the provenance root.",
"depends_on": [],
"input_keys": [
"file",
"url",
"visibility"
]
}
},
{
"id": "visual:step:detect",
"ast_node_id": "step:detect",
"kind": "step",
"title": "Detect sensitive material",
"subtitle": "document.redact",
"status": "defined",
"rank": 2,
"metadata": {
"category": "transformation",
"node_kind": "document.redact",
"output_contract": "redaction_plan",
"output": "redaction_plan",
"summary": "Scan text, OCR layers, form fields, annotations, and page images for PII, account numbers, addresses, and agency-specific policy targets.",
"depends_on": [
"intake"
],
"input_keys": [
"document_id",
"output",
"policy"
]
}
},
{
"id": "visual:step:review",
"ast_node_id": "step:review",
"kind": "wait",
"title": "Human review gate",
"subtitle": "human.approval",
"status": "defined",
"rank": 3,
"metadata": {
"category": "human_gate",
"node_kind": "human.approval",
"output_contract": "approval_decision",
"output": "approval_decision",
"summary": "Review every proposed redaction on a page overlay before export. Low-confidence detections remain unresolved until a reviewer decides.",
"depends_on": [
"detect"
],
"input_keys": [
"approval_key",
"context",
"event_type",
"on_timeout",
"prompt",
"timeout"
],
"event_type": "redaction-approval",
"timeout": "24 hours"
}
},
{
"id": "visual:step:apply",
"ast_node_id": "step:apply",
"kind": "step",
"title": "Apply true redactions",
"subtitle": "document.redact.apply",
"status": "defined",
"rank": 4,
"metadata": {
"category": "transformation",
"node_kind": "document.redact.apply",
"output_contract": "redacted_document",
"output": "redacted_document",
"summary": "Create a derivative with approved content removed rather than hidden by an overlay. Rejecting the gate blocks export.",
"depends_on": [
"review"
],
"input_keys": [
"approval",
"document_id",
"mode",
"output",
"redaction_plan"
]
}
},
{
"id": "visual:step:sanitize",
"ast_node_id": "step:sanitize",
"kind": "step",
"title": "Sanitize the derivative",
"subtitle": "document.sanitize",
"status": "defined",
"rank": 5,
"metadata": {
"category": "transformation",
"node_kind": "document.sanitize",
"output_contract": "sanitized_document",
"output": "sanitized_document",
"summary": "Remove metadata, flatten annotations and form fields, and prepare the redacted derivative for parsing and public delivery.",
"depends_on": [
"apply"
],
"input_keys": [
"document_id",
"flatten_annotations",
"flatten_forms",
"output",
"remove_metadata"
]
}
},
{
"id": "visual:step:publish",
"ast_node_id": "step:publish",
"kind": "step",
"title": "Publish a safe view",
"subtitle": "document.publish.view",
"status": "defined",
"rank": 6,
"metadata": {
"category": "output",
"node_kind": "document.publish.view",
"output_contract": "published_view",
"output": "published_view",
"summary": "Publish a signed or public link for the redacted derivative, with the original source id retained only in the audit trail.",
"depends_on": [
"sanitize"
],
"input_keys": [
"document_id",
"include_audit_manifest",
"include_proof_cards",
"source_document_id",
"view_name",
"visibility"
]
}
},
{
"id": "visual:end",
"ast_node_id": "end",
"kind": "end",
"title": "End",
"rank": 7
}
],
"edges": [
{
"id": "visual:edge:start->step:intake",
"ast_edge_id": "edge:start->step:intake",
"source": "visual:start",
"target": "visual:step:intake",
"kind": "sequence"
},
{
"id": "visual:edge:step:intake->step:detect",
"ast_edge_id": "edge:step:intake->step:detect",
"source": "visual:step:intake",
"target": "visual:step:detect",
"kind": "dependency"
},
{
"id": "visual:edge:step:detect->step:review",
"ast_edge_id": "edge:step:detect->step:review",
"source": "visual:step:detect",
"target": "visual:step:review",
"kind": "dependency"
},
{
"id": "visual:edge:step:review->step:apply",
"ast_edge_id": "edge:step:review->step:apply",
"source": "visual:step:review",
"target": "visual:step:apply",
"kind": "dependency"
},
{
"id": "visual:edge:step:apply->step:sanitize",
"ast_edge_id": "edge:step:apply->step:sanitize",
"source": "visual:step:apply",
"target": "visual:step:sanitize",
"kind": "dependency"
},
{
"id": "visual:edge:step:sanitize->step:publish",
"ast_edge_id": "edge:step:sanitize->step:publish",
"source": "visual:step:sanitize",
"target": "visual:step:publish",
"kind": "dependency"
},
{
"id": "visual:edge:step:publish->end",
"ast_edge_id": "edge:step:publish->end",
"source": "visual:step:publish",
"target": "visual:end",
"kind": "sequence"
}
]
},
"relevance_examples": [
{
"label": "fal-style async queue",
"compareTo": "Submit a long-running job, keep a request id, poll status/results, or receive a webhook.",
"signal": "Relevant when redaction, OCR, sanitization, or review can take longer than a blocking API request should stay open.",
"okraPattern": "Create or import a workflow, start a run with PDF inputs, wait on status_url or webhook events, then fetch the approved output.",
"fit": "Good fit for backend queues, agent workers, batch portals, and document automation that already treat AI work as jobs."
},
{
"label": "Replicate-style prediction",
"compareTo": "Create a prediction with input, get an id plus status URL, optionally include a webhook, then inspect the web view.",
"signal": "Relevant when product teams need a stable run record that can be shown to a reviewer or support person, not just a final file.",
"okraPattern": "A workflow run has a workflow_id, run_id, status_url, approval gate, and visualization endpoint for the live run graph.",
"fit": "Good fit if you want prediction-like lifecycle semantics for PDF operations with human review before publish."
},
{
"label": "n8n community workflow",
"compareTo": "Public template page for discovery, isolated visual embed for sharing, JSON definition for import or automation.",
"signal": "Relevant when the workflow itself is the artifact: sales pages, docs, internal enablement, and customer-specific variants.",
"okraPattern": "workflows.okrapdf.com hosts crawlable metadata and JSON; embed.okrapdf.com renders only the isolated workflow visual.",
"fit": "Good fit for SEO pages, integration docs, and template galleries where private runs must stay separated from public content."
}
],
"api_examples": [
{
"title": "Create a dynamic workflow definition",
"description": "Use the resource-style workflow API to store a configurable workflow source. This mirrors a model or function registration step.",
"method": "POST",
"path": "/v1/workflows",
"code": "const source = [\n \"phase('Detect');\",\n \"const plan = await agent('Detect FOIA redactions in the supplied PDF.', { label: 'redactions' });\",\n \"phase('Review');\",\n \"const decision = await human.approval({ approval_key: 'foia-redaction', prompt: 'Approve redactions before publish', event_type: 'redaction-approval', timeout: '24 hours', on_timeout: 'reject' });\",\n \"return { plan, decision };\"\n].join(\"\\n\");\n\nconst workflow = await fetch(\"https://api.okrapdf.com/v1/workflows\", {\n method: \"POST\",\n headers: {\n \"Authorization\": \"Bearer $OKRAPDF_API_KEY\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n name: \"FOIA redaction review\",\n definition: { code: source }\n })\n}).then((res) => res.json());",
"responseShape": {
"object": "workflow",
"id": "wf_...",
"workflow_id": "wf_...",
"version_id": "wv_...",
"execution_mode": "agent_workflow_script",
"runnable": true,
"run": null
}
},
{
"title": "Run it like an async job",
"description": "This is the run shape for executable workflows. For this FOIA step-definition template today, the API returns 409 until the redaction/publish runner lands.",
"method": "POST",
"path": "/v1/runs",
"code": "const run = await fetch(\"https://api.okrapdf.com/v1/runs\", {\n method: \"POST\",\n headers: {\n \"Authorization\": \"Bearer $OKRAPDF_API_KEY\",\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n workflowId: workflow.id,\n inputs: {\n pdf_url: \"https://example.gov/request.pdf\",\n webhook_url: \"https://example.com/webhooks/okra\"\n }\n })\n}).then((res) => res.json());",
"responseShape": {
"object": "run",
"id": "dynrun_...",
"run_id": "dynrun_...",
"workflow_id": "wf_...",
"status": "queued",
"status_url": "/v1/runs/dynrun_..."
}
},
{
"title": "Show status and the live run graph",
"description": "Fetch the status endpoint for lifecycle state, and fetch the visualization endpoint when you want a UI to show the current node and review gate.",
"method": "GET",
"path": "/v1/runs/{run_id}/visualization",
"code": "const status = await fetch(run.status_url, {\n headers: { \"Authorization\": \"Bearer $OKRAPDF_API_KEY\" }\n}).then((res) => res.json());\n\nconst visual = await fetch(`https://api.okrapdf.com/v1/runs/${run.run_id}/visualization`, {\n headers: { \"Authorization\": \"Bearer $OKRAPDF_API_KEY\" }\n}).then((res) => res.json());",
"responseShape": {
"object": "workflow_run_visualization_projection",
"version": "okra.workflow.run.visualization.v1",
"run_id": "dynrun_...",
"nodes": [
"intake",
"detect",
"review",
"publish"
],
"current_step": "review"
}
}
],
"review_checklist": [
"Every redaction has a page, bbox, entity class, and reviewer decision.",
"Rejected or unresolved detections block publish instead of silently passing through.",
"Metadata and hidden text are removed after redaction, not before review.",
"The public URL points to the redacted derivative, never the source PDF."
],
"outputs": [
"Redacted PDF derivative",
"Signed or public review link",
"Redaction decision log",
"Audit manifest with source and derivative ids"
]
}