# Workflows

> Build configurable document processing pipelines with capture, OCR, extraction, validation, and review steps

Source: https://docs.korala.ai/guides/workflows

---

Workflows are configurable processing pipelines. Define a sequence of steps such as capture, OCR, extraction, validation, checks, enrichment, risk, review, and output, then run them against uploaded documents or accumulated case data.

## Creating a Workflow

```typescript

const korala = new KoralaClient({
  apiKeyId: 'your-api-key-id',
  apiSecret: 'your-api-secret',
});

const workflow = await korala.workflows.create({
  name: 'ID Document Extraction',
  slug: 'id-document',
  steps: [
    { type: 'capture', config: { acceptedTypes: ['application/pdf', 'image/png', 'image/jpeg'], maxSizeMb: 10 } },
    { type: 'ocr', config: { provider: 'auto' } },
    { type: 'extract', config: { prompt: 'inline', schema: 'inline', inlineSystemPrompt: '...', inlineOutputSchema: { ... } } },
    { type: 'validate', config: { schema: 'inline', aiValidation: { prompt: '...', fields: ['document_number'], failOnInvalid: false } } },
    { type: 'output', config: { format: 'json', includeMetadata: true } },
  ],
});
```

## Step Types

| Step | Description |
|------|-------------|
| `capture` | Accept document upload (PDF, images) |
| `ocr` | Extract text from document via OCR |
| `extract` | Structured data extraction with an LLM |
| `validate` | Assertions over already-known data, extracted fields, or prior outputs |
| `enrich` | Transforms or data augmentation that do not create first-class findings |
| `check` | Provider-backed or specialized verification that emits findings, scores, and review signals |
| `risk` | Aggregate scoring across evidence, history, and prior steps |
| `review` | Human-in-the-loop pause point |
| `webhook` | Fire-and-forget HTTP POST |
| `output` | Format and return results |

Use `check` when the step calls an external or specialized verification source and you want to persist first-class findings such as PEP, sanctions, adverse media, or business registry results. Keep `validate` for deterministic assertions over data you already have.

## Running a Workflow

```typescript
// 1. Start a run and get upload URL
const run = await korala.workflows.startRun('id-document', {
  inputData: { customField: 'value' },
});

// 2. Upload the document
await fetch(run.uploadUrl, {
  method: 'PUT',
  body: documentFile,
  headers: { 'Content-Type': documentFile.type },
});

// 3. Confirm upload to start processing
await korala.workflows.confirmUpload(run.runId);

// 4. Poll for results
const result = await korala.workflows.getRun(run.runId);
// result.status: 'completed' | 'running' | 'failed'
// result.outputData: extracted data
```

## Workflow Webhooks

Subscribe to these events for real-time notifications:

| Event | Description |
|-------|-------------|
| `workflow_run_completed` | Workflow run finished |
| `workflow_run_failed` | Workflow run failed |

## Human Review

If a workflow includes a `review` step, it pauses for human review:

```typescript
// Approve and continue
await korala.workflows.submitReview(runId, {
  action: 'approve',
  editedData: { correctedField: 'new value' },
});

// Or reject
await korala.workflows.submitReview(runId, {
  action: 'reject',
  reason: 'Document is unreadable',
});
```
