> ## Documentation Index
> Fetch the complete documentation index at: https://docs.reducto.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Configuration Overview

> Configure every step of Reducto document processing

export const V2ToV3Converter = () => {
  const isDict = value => value !== null && typeof value === 'object' && !Array.isArray(value);
  const isBool = value => typeof value === 'boolean';
  const pyTruthy = value => {
    if (value === null || value === undefined || value === false || value === 0 || value === '') return false;
    if (Array.isArray(value) || isDict(value)) return Object.keys(value).length > 0;
    return true;
  };
  const pyString = value => typeof value === 'boolean' ? value ? 'True' : 'False' : String(value);
  const pyGet = (object, key, fallback) => isDict(object) && Object.prototype.hasOwnProperty.call(object, key) ? object[key] : fallback;
  const highlight = value => {
    const escaped = value.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return escaped.replace(/"([^"\\]*(\\.[^"\\]*)*)"|\b(\d+\.?\d*)\b|\b(true|false|null)\b/g, (match, _stringBody, _escapedCharacter, number, literal) => {
      if (number !== undefined) return `<span class="v2v3-num">${number}</span>`;
      if (literal !== undefined) return `<span class="v2v3-literal">${literal}</span>`;
      return `<span class="v2v3-string">${match}</span>`;
    });
  };
  const deepMerge = (base, override) => {
    const result = {
      ...base
    };
    Object.entries(override || ({})).forEach(([key, value]) => {
      const existing = result[key];
      if (Object.prototype.hasOwnProperty.call(result, key) && isDict(existing) && isDict(value)) {
        result[key] = deepMerge(existing, value);
      } else if (value !== null) {
        result[key] = value;
      }
    });
    return result;
  };
  const detectRequestType = payload => {
    if (Object.prototype.hasOwnProperty.call(payload, 'schema') || Object.prototype.hasOwnProperty.call(payload, 'extract_schema')) return 'extract';
    if (Object.prototype.hasOwnProperty.call(payload, 'split_description')) return 'split';
    return 'parse';
  };
  const getDefaultV2ParsePayload = () => ({
    document_url: '',
    options: {
      ocr_mode: 'standard',
      extraction_mode: 'ocr',
      chunking: {
        chunk_mode: 'variable'
      },
      table_summary: {
        enabled: false
      },
      figure_summary: {
        enabled: false,
        override: false
      },
      filter_blocks: [],
      force_url_result: false
    },
    advanced_options: {
      ocr_system: 'highres',
      table_output_format: 'html',
      merge_tables: false,
      include_formula_information: false,
      include_color_information: false,
      continue_hierarchy: true,
      keep_line_breaks: false,
      page_range: {},
      large_table_chunking: {
        enabled: true,
        size: 50
      },
      spreadsheet_table_clustering: 'default',
      add_page_markers: false,
      remove_text_formatting: false,
      return_ocr_data: false,
      filter_line_numbers: false,
      read_comments: false,
      persist_results: false,
      exclude_hidden_sheets: false,
      exclude_hidden_rows_cols: false,
      enable_change_tracking: false,
      enable_highlight_detection: false
    },
    experimental_options: {
      enrich: {
        enabled: false,
        mode: 'standard'
      },
      layout_enrichment: false,
      native_docx_parsing: false,
      native_office_conversion: false,
      enable_checkboxes: false,
      enable_equations: false,
      rotate_pages: true,
      rotate_figures: false,
      enable_scripts: false,
      return_figure_images: false,
      return_table_images: false,
      return_page_images: false,
      layout_model: 'default',
      embed_text_metadata_pdf: false,
      detect_signatures: false,
      danger_filter_wide_boxes: false
    }
  });
  const getDefaultV2ExtractPayload = () => ({
    ...getDefaultV2ParsePayload(),
    schema: {},
    extract_schema: {},
    system_prompt: 'Be precise and thorough.',
    generate_citations: false,
    array_extract: {
      enabled: false,
      mode: 'legacy',
      pages_per_segment: 10
    },
    use_chunking: false,
    include_images: false,
    spreadsheet_agent: false,
    experimental_table_citations: true,
    agent_extract: {
      enabled: false
    },
    latency_sensitive: false,
    citations_options: {
      numerical_confidence: false
    }
  });
  const getDefaultV2SplitPayload = () => ({
    ...getDefaultV2ParsePayload(),
    split_description: [],
    split_rules: 'Split the document into the applicable sections. Sections may only overlap at their first and last page if at all.',
    split_options: {
      table_cutoff: 'truncate'
    }
  });
  const getDefaultV2Payload = (requestType = 'parse') => requestType === 'extract' ? getDefaultV2ExtractPayload() : requestType === 'split' ? getDefaultV2SplitPayload() : getDefaultV2ParsePayload();
  const findExtraFields = (input, defaults, path = '') => {
    const warnings = [];
    if (!isDict(input) || !isDict(defaults)) return warnings;
    Object.entries(input).forEach(([key, value]) => {
      const currentPath = path ? `${path}.${key}` : key;
      if (!Object.prototype.hasOwnProperty.call(defaults, key)) {
        warnings.push(`\`${currentPath}\` cannot be set in V3`);
      } else if (isDict(value) && isDict(defaults[key])) {
        warnings.push(...findExtraFields(value, defaults[key], currentPath));
      }
    });
    return warnings;
  };
  const convertParseOptions = payload => {
    const options = pyGet(payload, 'options', {});
    const advanced = pyGet(payload, 'advanced_options', {});
    const experimental = pyGet(payload, 'experimental_options', {});
    const result = {
      enhance: {
        agentic: [],
        summarize_figures: true
      },
      retrieval: {
        chunking: {
          chunk_mode: 'disabled'
        },
        filter_blocks: [],
        embedding_optimized: false
      },
      formatting: {
        add_page_markers: false,
        table_output_format: 'dynamic',
        merge_tables: false,
        include: []
      },
      spreadsheet: {
        split_large_tables: {
          enabled: true,
          size: 50
        },
        include: [],
        clustering: 'accurate',
        exclude: []
      },
      settings: {
        ocr_system: 'standard',
        force_url_result: false,
        return_ocr_data: false,
        return_images: [],
        embed_pdf_metadata: false,
        persist_results: false
      }
    };
    result.retrieval.chunking = pyGet(options, 'chunking', {
      chunk_mode: 'disabled'
    });
    if (pyGet(options, 'ocr_mode', undefined) === 'agentic') {
      result.enhance.agentic.push({
        scope: 'text'
      }, {
        scope: 'table'
      });
    }
    result.retrieval.filter_blocks = pyGet(options, 'filter_blocks', []);
    const tableSummary = pyGet(options, 'table_summary', undefined);
    if (isDict(tableSummary)) result.retrieval.embedding_optimized = pyGet(tableSummary, 'enabled', false); else if (isBool(tableSummary)) result.retrieval.embedding_optimized = tableSummary;
    const figureSummary = pyGet(options, 'figure_summary', undefined);
    if (isDict(figureSummary)) {
      result.enhance.summarize_figures = pyGet(figureSummary, 'enabled', true);
      if (pyTruthy(pyGet(figureSummary, 'enhanced', undefined)) || pyTruthy(pyGet(figureSummary, 'override', undefined))) {
        const figureAgentic = {
          scope: 'figure'
        };
        if (pyTruthy(pyGet(figureSummary, 'prompt', undefined))) figureAgentic.prompt = figureSummary.prompt;
        result.enhance.agentic.push(figureAgentic);
      }
    } else if (isBool(figureSummary)) result.enhance.summarize_figures = figureSummary;
    result.settings.force_url_result = pyGet(options, 'force_url_result', false);
    result.settings.extraction_mode = pyGet(options, 'extraction_mode', 'ocr');
    result.settings.ocr_system = ({
      highres: 'legacy',
      multilingual: 'standard',
      legacy: 'legacy',
      reducto: 'legacy',
      combined: 'standard'
    })[pyGet(advanced, 'ocr_system', undefined)] || 'standard';
    const tableFormat = pyGet(advanced, 'table_output_format', undefined);
    result.formatting.table_output_format = tableFormat === 'jsonbbox' ? 'json' : tableFormat;
    result.formatting.merge_tables = pyGet(advanced, 'merge_tables', false);
    if (pyTruthy(pyGet(advanced, 'keep_line_breaks', false))) result.settings.alpha = {
      keep_line_breaks: true
    };
    result.settings.return_ocr_data = pyGet(advanced, 'return_ocr_data', false);
    result.formatting.add_page_markers = pyGet(advanced, 'add_page_markers', false);
    if (pyTruthy(pyGet(advanced, 'page_range', undefined))) result.settings.page_range = pyGet(advanced, 'page_range', undefined);
    if (pyTruthy(pyGet(advanced, 'document_password', undefined))) result.settings.document_password = pyGet(advanced, 'document_password', undefined);
    if (pyTruthy(pyGet(advanced, 'include_color_information', false))) result.spreadsheet.include.push('cell_colors');
    if (pyTruthy(pyGet(advanced, 'include_formula_information', false))) result.spreadsheet.include.push('formula');
    const largeTable = pyGet(advanced, 'large_table_chunking', undefined);
    if (isDict(largeTable)) {
      result.spreadsheet.split_large_tables.enabled = pyGet(largeTable, 'enabled', true);
      result.spreadsheet.split_large_tables.size = pyGet(largeTable, 'size', 50);
    } else if (isBool(largeTable)) result.spreadsheet.split_large_tables.enabled = largeTable;
    result.spreadsheet.clustering = ({
      default: 'fast',
      disabled: 'disabled',
      intelligent: 'accurate'
    })[pyGet(advanced, 'spreadsheet_table_clustering', undefined)] || 'fast';
    result.settings.persist_results = pyGet(advanced, 'persist_results', false);
    if (pyTruthy(pyGet(advanced, 'exclude_hidden_sheets', false))) result.spreadsheet.exclude.push('hidden_sheets');
    if (pyTruthy(pyGet(advanced, 'exclude_hidden_rows_cols', false))) result.spreadsheet.exclude.push('hidden_rows', 'hidden_cols');
    if (pyTruthy(pyGet(advanced, 'read_comments', false))) result.formatting.include.push('comments');
    if (pyTruthy(pyGet(advanced, 'enable_change_tracking', false))) result.formatting.include.push('change_tracking');
    if (pyTruthy(pyGet(advanced, 'enable_highlight_detection', false))) result.formatting.include.push('highlight');
    result.settings.embed_pdf_metadata = pyGet(experimental, 'embed_text_metadata_pdf', false);
    const enrich = pyGet(experimental, 'enrich', undefined);
    if (isDict(enrich) && pyTruthy(pyGet(enrich, 'enabled', false)) && pyGet(enrich, 'mode', undefined) === 'table') {
      const agentic = {
        scope: 'table'
      };
      if (pyTruthy(pyGet(enrich, 'prompt', undefined))) agentic.prompt = enrich.prompt;
      result.enhance.agentic.push(agentic);
    }
    if (pyTruthy(pyGet(experimental, 'return_figure_images', false))) result.settings.return_images.push('figure');
    if (pyTruthy(pyGet(experimental, 'return_table_images', false))) result.settings.return_images.push('table');
    if (pyTruthy(pyGet(experimental, 'return_page_images', false))) result.settings.return_images.push('page');
    if (pyTruthy(pyGet(experimental, 'detect_signatures', false))) result.formatting.include.push('signatures');
    if (pyTruthy(pyGet(experimental, 'user_specified_timeout_seconds', undefined))) result.settings.timeout = pyGet(experimental, 'user_specified_timeout_seconds', undefined);
    if (pyTruthy(pyGet(experimental, 'enable_checkboxes', false))) result.settings.alpha = {
      ...result.settings.alpha || ({}),
      enable_checkboxes: true
    };
    if (pyTruthy(pyGet(experimental, 'native_docx_parsing', false))) result.settings.alpha = {
      ...result.settings.alpha || ({}),
      native_docx_parsing: true
    };
    const dpi = pyGet(experimental, 'dpi', undefined);
    if (dpi !== null && dpi !== undefined) result.settings.alpha = {
      ...result.settings.alpha || ({}),
      dpi
    };
    const customDpiModel = pyGet(experimental, 'custom_dpi_model', undefined);
    if (customDpiModel !== null && customDpiModel !== undefined) result.settings.alpha = {
      ...result.settings.alpha || ({}),
      custom_dpi_model: customDpiModel
    };
    const customArgs = pyGet(experimental, 'custom_dpi_additional_args', undefined);
    if (pyTruthy(customArgs)) result.settings.alpha = {
      ...result.settings.alpha || ({}),
      custom_dpi_additional_args: customArgs
    };
    return result;
  };
  const fillV2Defaults = payload => deepMerge(getDefaultV2Payload(detectRequestType(payload)), payload);
  const convertV2ToV3 = input => {
    const warnings = [];
    const requestType = detectRequestType(input);
    const defaults = getDefaultV2Payload(requestType);
    warnings.push(...findExtraFields(input, defaults));
    const payload = deepMerge(defaults, input);
    const advanced = payload.advanced_options;
    const experimental = payload.experimental_options;
    const continueHierarchy = pyGet(advanced, 'continue_hierarchy', true);
    if (!pyTruthy(continueHierarchy)) warnings.push(`\`advanced_options.continue_hierarchy\`=${pyString(continueHierarchy)} cannot be set in V3. V3 will default to True.`);
    const removeFormatting = pyGet(advanced, 'remove_text_formatting', false);
    if (pyTruthy(removeFormatting)) warnings.push(`\`advanced_options.remove_text_formatting\`=${pyString(removeFormatting)} cannot be set in V3. V3 will default to False.`);
    const layoutModel = pyGet(experimental, 'layout_model', 'default');
    if (layoutModel === 'default') warnings.push(`\`experimental_options.layout_model\`='${layoutModel}' cannot be set in V3. V3 will default to 'beta'.`);
    const chunkTableBlocks = pyGet(experimental, 'chunk_table_blocks', false);
    if (pyTruthy(chunkTableBlocks)) warnings.push(`\`experimental_options.chunk_table_blocks\`=${pyString(chunkTableBlocks)} cannot be set in V3. V3 will default to False.`);
    const parsing = convertParseOptions(payload);
    if (requestType === 'extract') {
      const schema = pyTruthy(payload.schema) ? payload.schema : pyGet(payload, 'extract_schema', {});
      const citationsOptions = pyGet(payload, 'citations_options', {});
      const v3 = {
        input: pyGet(payload, 'document_url', ''),
        parsing,
        instructions: {
          schema,
          system_prompt: pyGet(payload, 'system_prompt', 'Be precise and thorough.')
        },
        settings: {
          include_images: pyGet(payload, 'include_images', false),
          optimize_for_latency: pyGet(payload, 'latency_sensitive', false),
          array_extract: isDict(payload.array_extract) ? pyGet(payload.array_extract, 'enabled', false) : false,
          citations: {
            enabled: pyGet(payload, 'generate_citations', false),
            numerical_confidence: isDict(citationsOptions) ? pyGet(citationsOptions, 'numerical_confidence', true) : true,
            parent_block: isDict(citationsOptions) ? pyGet(citationsOptions, 'parent_block', 'full') : 'full'
          }
        }
      };
      if (pyTruthy(payload.use_chunking)) warnings.push('`use_chunking` cannot be set in V3. Use `parsing.retrieval.chunking.chunk_mode` instead.');
      if (pyTruthy(payload.spreadsheet_agent)) warnings.push('`spreadsheet_agent` cannot be set in V3. Spreadsheet agent is automatically enabled when needed.');
      if (!pyTruthy(payload.experimental_table_citations)) warnings.push('`experimental_table_citations` cannot be disabled in V3. Table citations are always enabled.');
      if (pyTruthy(payload.alpha_deep_extract)) warnings.push('`alpha_deep_extract` cannot be set in V3 without alpha options.');
      if (pyTruthy(payload.alpha_table_citations)) warnings.push('`alpha_table_citations` cannot be set in V3 without alpha options.');
      if (!pyTruthy(pyGet(payload, 'alpha_big_extraction_model', true))) warnings.push('`alpha_big_extraction_model` cannot be disabled in V3 without alpha options.');
      if (isDict(payload.agent_extract) && pyTruthy(payload.agent_extract.enabled)) v3.instructions.agent_in_the_loop = {
        enabled: true,
        fields_to_verify: []
      };
      return [v3, warnings];
    }
    if (requestType === 'split') {
      const options = pyGet(payload, 'split_options', {});
      return [{
        input: pyGet(payload, 'document_url', ''),
        parsing,
        split_description: pyGet(payload, 'split_description', []),
        split_rules: pyGet(payload, 'split_rules', 'Split the document into the applicable sections. Sections may only overlap at their first and last page if at all.'),
        settings: {
          table_cutoff: isDict(options) ? pyGet(options, 'table_cutoff', 'truncate') : 'truncate',
          allow_page_overlap: isDict(options) ? pyGet(options, 'allow_page_overlap', true) : true
        }
      }, warnings];
    }
    return [{
      input: pyGet(payload, 'document_url', ''),
      ...parsing
    }, warnings];
  };
  const [input, setInput] = React.useState(JSON.stringify(getDefaultV2ParsePayload(), null, 2));
  const [state, setState] = React.useState(() => {
    const parsed = getDefaultV2ParsePayload();
    const [output, warnings] = convertV2ToV3(parsed);
    return {
      output,
      warnings,
      filled: fillV2Defaults(parsed),
      error: ''
    };
  });
  const [copyStatus, setCopyStatus] = React.useState('idle');
  const copyResetTimer = React.useRef(null);
  React.useEffect(() => () => {
    if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
  }, []);
  React.useEffect(() => {
    const timer = setTimeout(() => {
      try {
        const parsed = JSON.parse(input);
        if (!isDict(parsed)) throw new Error('Expected a JSON object.');
        const [output, warnings] = convertV2ToV3(parsed);
        setState({
          output,
          warnings,
          filled: fillV2Defaults(parsed),
          error: ''
        });
      } catch (error) {
        setState({
          output: null,
          warnings: [],
          filled: null,
          error: error.message
        });
      }
    }, 250);
    return () => clearTimeout(timer);
  }, [input]);
  const outputText = state.output ? JSON.stringify(state.output, null, 2) : '';
  const showCopyStatus = status => {
    if (copyResetTimer.current) clearTimeout(copyResetTimer.current);
    setCopyStatus(status);
    copyResetTimer.current = setTimeout(() => setCopyStatus('idle'), 1500);
  };
  const copyOutput = () => {
    if (!outputText) return;
    if (typeof navigator === 'undefined' || !navigator.clipboard?.writeText) {
      showCopyStatus('error');
      return;
    }
    navigator.clipboard.writeText(outputText).then(() => showCopyStatus('success'), () => showCopyStatus('error'));
  };
  return <div className="v2v3-converter not-prose my-6 rounded-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden shadow-sm">
      <style>{`
        .v2v3-converter .v2v3-string { color: #0369a1; }
        .v2v3-converter .v2v3-num { color: #1d4ed8; }
        .v2v3-converter .v2v3-literal { color: #dc2626; }
        :is(.dark *) .v2v3-converter .v2v3-string { color: #a5d6ff; }
        :is(.dark *) .v2v3-converter .v2v3-num { color: #79c0ff; }
        :is(.dark *) .v2v3-converter .v2v3-literal { color: #ff7b72; }
      `}</style>
      <div className="grid md:grid-cols-2">
        <div className="bg-zinc-50 dark:bg-[#0d1117] border-b md:border-b-0 md:border-r border-zinc-200 dark:border-zinc-800">
          <div className="px-4 py-2 bg-zinc-100 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-800 flex items-center gap-2">
            <div className="flex gap-1.5">
              <div className="w-3 h-3 rounded-full bg-[#ff5f56]" />
              <div className="w-3 h-3 rounded-full bg-[#ffbd2e]" />
              <div className="w-3 h-3 rounded-full bg-[#27c93f]" />
            </div>
            <span className="text-xs text-zinc-500 ml-2 font-medium">V2 payload</span>
          </div>
          <textarea aria-label="V2 payload input" value={input} onChange={event => setInput(event.target.value)} className="w-full min-h-[460px] resize-y border-0 bg-zinc-50 dark:bg-[#0d1117] p-4 text-[13px] leading-relaxed text-zinc-700 dark:text-zinc-300 outline-none" style={{
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
  }} spellCheck={false} />
          {state.error && <div role="alert" className="mx-4 mb-4 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-700 dark:border-red-800 dark:bg-red-950/40 dark:text-red-300">
              Invalid JSON: {state.error}
            </div>}
          <details className="border-t border-zinc-200 dark:border-zinc-800">
            <summary className="cursor-pointer px-4 py-3 text-xs font-medium text-zinc-600 dark:text-zinc-400 hover:text-zinc-900 dark:hover:text-zinc-200">
              V2 payload with defaults applied
            </summary>
            <pre className="m-0 max-h-[360px] overflow-auto whitespace-pre-wrap px-4 pb-4 text-[12px] leading-relaxed text-zinc-700 dark:text-zinc-300" style={{
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
  }}>
              {state.filled ? JSON.stringify(state.filled, null, 2) : ''}
            </pre>
          </details>
        </div>
        <div className="bg-zinc-50 dark:bg-[#0d1117]">
          <div className="px-4 py-2 bg-zinc-100 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-800 flex items-center justify-between">
            <div className="flex items-center gap-2">
              <div className="flex gap-1.5">
                <div className="w-3 h-3 rounded-full bg-[#ff5f56]" />
                <div className="w-3 h-3 rounded-full bg-[#ffbd2e]" />
                <div className="w-3 h-3 rounded-full bg-[#27c93f]" />
              </div>
              <span className="text-xs text-zinc-500 ml-2 font-medium">V3 payload</span>
            </div>
            <button type="button" onClick={copyOutput} disabled={!outputText} className={`rounded-md border px-2.5 py-1 text-xs transition disabled:cursor-not-allowed disabled:opacity-50 ${copyStatus === 'error' ? 'border-red-300 text-red-700 hover:bg-red-50 dark:border-red-700 dark:text-red-300 dark:hover:bg-red-950/40' : 'border-zinc-300 text-zinc-700 hover:bg-zinc-200 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800 dark:hover:text-white'}`}>
              {copyStatus === 'success' ? 'Copied' : copyStatus === 'error' ? 'Copy failed' : 'Copy'}
            </button>
          </div>
          {state.warnings.length > 0 && <div role="status" className="m-3 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800 dark:border-amber-800 dark:bg-amber-950/40 dark:text-amber-200">
              <strong>Warnings</strong>
              <ul className="my-1.5 list-disc space-y-1 pl-4">{state.warnings.map(warning => <li key={warning}>{warning}</li>)}</ul>
            </div>}
          <pre className="m-0 min-h-[460px] overflow-auto whitespace-pre-wrap p-4 text-[13px] leading-relaxed text-zinc-700 dark:text-zinc-300" style={{
    fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace'
  }} dangerouslySetInnerHTML={{
    __html: highlight(outputText)
  }} />
        </div>
      </div>
    </div>;
};

Every Reducto endpoint exposes configuration options that control how documents are processed. This section covers all available configurations, from parse-level OCR and layout settings through extraction schemas and workflow orchestration.

## Configuration by Endpoint

<Tabs>
  <Tab title="Parse">
    Parse converts documents into structured content. Options are grouped by purpose:

    | Group         | Purpose                           | Pages                                                                                                                     |
    | ------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
    | `enhance`     | AI-powered accuracy               | [Agentic Modes](/configs/parse/agentic-modes), [Chart Extraction](/configs/parse/chart-extraction)                        |
    | `retrieval`   | RAG optimization                  | [Chunking Methods](/configs/parse/chunking-methods)                                                                       |
    | `formatting`  | Detecting styling & output format | [Table Formats](/configs/parse/table-output-formats), [Additional Document Data](/configs/parse/additional-document-data) |
    | `spreadsheet` | Excel/CSV handling                | [Spreadsheet Processing](/configs/parse/spreadsheet)                                                                      |
    | `settings`    | Processing controls               | [Processing Settings](/configs/parse/ocr-settings), [Page Ranges](/configs/parse/page-ranges)                             |

    ```python theme={null}
    result = client.parse.run(
        input=upload,
        enhance={...},
        retrieval={...},
        formatting={...},
        spreadsheet={...},
        settings={...}
    )
    ```
  </Tab>

  <Tab title="Extract">
    Extract pulls structured data from documents using a JSON schema.

    | Group          | Purpose                     | Pages                                                                                          |
    | -------------- | --------------------------- | ---------------------------------------------------------------------------------------------- |
    | `instructions` | Schema and system prompt    | (base config)                                                                                  |
    | `settings`     | Citations, array extraction | [Array Extraction](/configs/extract/array-extraction), [Citations](/configs/extract/citations) |
    | `parsing`      | Document processing         | All Parse options                                                                              |

    ```python theme={null}
    result = client.extract.run(
        input=upload,
        instructions={"schema": {...}, "system_prompt": "..."},
        settings={"deep_extract": True, "citations": {"enabled": True}},
        parsing={...}
    )
    ```
  </Tab>

  <Tab title="Split">
    Split divides documents into logical sections.

    | Group               | Purpose                | Pages                                               |
    | ------------------- | ---------------------- | --------------------------------------------------- |
    | `split_description` | Section definitions    | [Split Configuration](/configs/split/configuration) |
    | `split_rules`       | Splitting logic prompt | [Split Configuration](/configs/split/configuration) |
    | `settings`          | Table handling         | [Split Configuration](/configs/split/configuration) |
    | `parsing`           | Document processing    | All Parse options                                   |

    ```python theme={null}
    result = client.split.run(
        input=upload,
        split_description=[{"name": "...", "description": "..."}],
        split_rules="...",
        settings={"table_cutoff": "truncate"}
    )
    ```
  </Tab>

  <Tab title="Classify">
    Classify determines document type based on natural language criteria.

    | Group                   | Purpose               | Pages                                                     |
    | ----------------------- | --------------------- | --------------------------------------------------------- |
    | `classification_schema` | Category definitions  | [Classify Configuration](/configs/classify/configuration) |
    | `page_range`            | Pages used as context | [Classify Configuration](/configs/classify/configuration) |

    ```python theme={null}
    response = client.classify.run(
        input=upload,
        classification_schema=[
            {"category": "invoice", "criteria": ["billing info", "itemized charges"]},
            {"category": "contract", "criteria": ["legal terms", "signatures"]},
        ]
    )
    ```
  </Tab>

  <Tab title="Edit">
    Edit fills forms and modifies documents.

    | Option              | Purpose                       | Pages                                    |
    | ------------------- | ----------------------------- | ---------------------------------------- |
    | `edit_instructions` | Natural language instructions | (base config)                            |
    | `form_schema`       | Pre-defined field locations   | [Form Schema](/configs/edit/form-schema) |
    | `edit_options`      | Highlight color, overflow     | (base config)                            |

    ```python theme={null}
    result = client.edit.run(
        document_url=upload,
        edit_instructions="Fill name: John Doe, date: 2024-01-15",
        form_schema=[...],
        edit_options={"color": "#FF0000"}
    )
    ```
  </Tab>
</Tabs>

## Common Patterns

<AccordionGroup>
  <Accordion title="RAG-optimized parsing" icon="magnifying-glass">
    Variable chunking with embedding optimization for vector search:

    ```python theme={null}
    result = client.parse.run(
        input=upload,
        retrieval={
            "chunking": {"chunk_mode": "variable", "chunk_size": 1000},
            "embedding_optimized": True
        },
        formatting={"table_output_format": "dynamic"}
    )
    ```
  </Accordion>

  <Accordion title="High-accuracy processing" icon="bullseye">
    Enable agentic mode for both text and tables:

    ```python theme={null}
    result = client.parse.run(
        input=upload,
        enhance={
            "agentic": [{"scope": "text"}, {"scope": "table"}]
        }
    )
    ```
  </Accordion>

  <Accordion title="Complete extraction with citations" icon="quote-left">
    Deep Extract with source locations for long or complex documents (higher cost/latency):

    ```python theme={null}
    result = client.extract.run(
        input=upload,
        instructions={"schema": schema},
        settings={
            "deep_extract": True,
            "citations": {"enabled": True}
        }
    )
    ```
  </Accordion>
</AccordionGroup>

## Migrating from v2

If you're using the legacy configuration format, use this converter to transform your v2 config to v3:

<V2ToV3Converter />

See the [Migration Guide](/v/legacy/migration-guide) for complete mapping tables and examples.
