Document Insights

Lazarus Integration - Troubleshooting Guide

This document covers the Lazarus custom OCR integration within Document Insights. Lazarus handles two distinct document processing paths: identity document extraction (driver's licences, passports, SSNs) and custom form extraction (any document type mapped via a template). Both paths are covered here.


Integration Architecture Summary

Lazarus is a synchronous OCR service. Unlike MoneyThumb (webhook) or Ocrolus (batch polling), Lazarus returns extracted data in the same HTTP response as the upload. There is no callback URL and no separate retrieval step.

Path 1 — Identity Document Extraction

Stage

Component

Description

  1. Feature Check

PDFInsightRequestController

Validates Feature_Entitlement__c.PDF_Insights__c

  1. Submission

PDFInsightRequestController.callPDFInsightService

Groups files by source, creates PDF_Insight__c, enqueues QueueablePDFConvert

  1. Upload + Extract

QueueablePDFConvertWS_DocumentInsight.callIdentificationService

Routes to DL/Passport or SSN endpoint

  1. Record Creation

WS_DocumentInsight.callFormExtractionService / callFormSSNService

Parses response via DocumentExtractionParser, creates Identity_Verification__c

Path 2 — Custom Form Extraction

Stage

Component

Description

  1. Feature Check

CustomDocumentInsightController

Validates Feature_Entitlement__c.Custom_Forms__c

  1. Submission

CustomDocumentInsightController.submitCustomFormRequest

Enqueues QueueableCallCustomFormService

  1. Upload + Extract

QueueableCallCustomFormServiceWS_DocumentInsight.callCustomFormService

Multipart POST to Lazarus generic form endpoint

  1. Response Parsing

GenericFormInsightParser.parse()

Converts Lazarus key-value response into structured pairs

  1. Record Creation

ProcessCustomFormParser.parseCustomFormJSON

Maps key-value pairs to Salesforce fields and objects

Key Differences from Other Integrations

Characteristic

Lazarus

MoneyThumb

Ocrolus

Gemini

Auth method

orgId / authKey headers

Basic auth → Bearer token

OAuth2 client credentials

API key header

Response timing

Synchronous (same request)

Async webhook

Async batch poll

Synchronous

Request format

Multipart form data

Multipart form data

JSON / Multipart

JSON (inline base64)

Feature flag

PDF_Insights__c (identity) / Custom_Forms__c (forms)

PDF_Insights__c

PDF_Insights__c

Custom_Forms__c

Confidence Matrix

Yes

No

No

No


Prerequisites and Configuration Checklist

Custom Settings

Setting

Expected Value

Form_Identification_Endpoint__c

Lazarus identity document extraction URL

Generic_Form_Endpoint__c

Lazarus generic (custom) form extraction URL

orgId

Organisation ID issued by Lazarus

authKey

Authentication key issued by Lazarus

Feature_Entitlement__c.PDF_Insights__c

Must be true for identity document path

Feature_Entitlement__c.Custom_Forms__c

Must be true for custom form path

Remote Site Settings

Both the identity endpoint domain and the generic form endpoint domain must be registered under Setup → Remote Site Settings. These may be on different subdomains — register both.

Document_Insight_Template__c Records (Custom Forms Only)

Custom form extraction requires a matching template. Verify:

Field

Requirement

Active__c

Must be checked

Source__c

Must match the source string used in the submission (not 'Google Gemini')

Template_Name__c

Must exactly match the name selected in the UI

Data_Field_Mapping__c

Must contain valid JSON array of GenericFormConfiguration objects

Primary_Object__c

Must be a valid Salesforce object API name


Document Type Routing Reference

QueueablePDFConvert routes identity documents based on sDocumentType. Custom form documents bypass this class entirely and go through QueueableCallCustomFormService.

Document Type

Method Called

Child Record Created

DL (Driver's Licence)

WS_DocumentInsight.callFormExtractionService

Identity_Verification__c (full ID fields)

Passport

WS_DocumentInsight.callFormExtractionService

Identity_Verification__c (full ID fields)

SSN

WS_DocumentInsight.callFormSSNService

Identity_Verification__c (SSN + name only)

Custom Form

WS_DocumentInsight.callCustomFormService

Primary object record (via ProcessCustomFormParser) + PDF_Insight__c


Issue: Request Button Not Visible (Identity Path)

Root Cause 1 — Feature flag disabled The identity document path checks Feature_Entitlement__c.PDF_Insights__c. Navigate to Setup → Custom Settings → Feature Entitlement and ensure PDF_Insights__c is enabled.

Root Cause 2 — Record is a PDF_Insight__c PDFInsightRequestController.showRequestButton() always returns false when the current record is itself a PDF_Insight__c.

Root Cause 3 — ShowRequestSection metadata disabled Check the ShowRequestSection field on the relevant custom metadata record.

Issue: Submission Form Not Accessible (Custom Form Path)

The custom form submission UI checks Feature_Entitlement__c.Custom_Forms__c, not PDF_Insights__c. An org with identity document processing enabled may still have custom forms disabled. Enable Custom_Forms__c in Custom Settings → Feature Entitlement.


Issue: Authentication Failure

Symptom: PDF_Insight__c or Identity_Verification__c is not created. Debug logs show a 401 or 403 HTTP response from Lazarus.

Lazarus uses a header-based authentication scheme — no token exchange, no OAuth flow. Every request includes:

orgId: <value from Custom Setting>
authKey: <value from Custom Setting>

Diagnostic Steps:

  1. Verify both orgId and authKey are populated in Custom Settings. A blank value sends an empty header, which Lazarus rejects.

  2. Both values are case-sensitive. Confirm there are no leading or trailing spaces — these are invisible in the UI but break authentication.

  3. Test in Execute Anonymous:

WS_DocumentInsight ws = new WS_DocumentInsight();
// Trigger a minimal call and inspect the HTTP response

Check the debug log for the raw response body — Lazarus typically returns a descriptive error when credentials are invalid.

  1. If credentials were recently rotated by the Lazarus administrator, update both Custom Setting values. Unlike OAuth2, there is no fallback or retry on auth failure — the job will fail immediately.


Issue: Endpoint Misconfiguration (Connection Error)

Symptom: System.CalloutException in Apex logs rather than an HTTP status code. No network response received.

Root Cause 1 — Remote Site Settings missing The Lazarus endpoint domain is not registered. Add it at Setup → Remote Site Settings.

Root Cause 2 — Wrong endpoint URL Form_Identification_Endpoint__c and Generic_Form_Endpoint__c are separate endpoints. Using the identity endpoint for a custom form call (or vice versa) results in either a connection error or an unexpected response structure that fails parsing.

Verification: Check which endpoint is being called against which document type. callFormExtractionService and callFormSSNService use Form_Identification_Endpoint__c. callCustomFormService uses Generic_Form_Endpoint__c.

Root Cause 3 — Missing Version header on generic form endpoint customFormAPI() sends a Version: 2 header on the generic form endpoint. If the endpoint has been updated to a newer version but the header value has not been updated in code or Custom Settings, Lazarus may return a 400 or serve an older API version with a different response schema.


Issue: Wrong Document Type Routed (Identity Path)

Symptom: A driver's licence is processed but an Identity_Verification__c is created with only SSN/name fields (or vice versa).

QueueablePDFConvert routes based on sDocumentType:

  • sDocumentType = 'DL' or 'Passport'callFormExtractionService → full identity extraction

  • sDocumentType = 'SSN'callFormSSNService → SSN and name only

If sDocumentType is set incorrectly at submission, the wrong extraction method is called and only a subset of fields are populated.

Resolution: Verify the document type selection in the submission UI. The sDocumentType value must match exactly — check for case sensitivity and spacing. If the submission UI does not allow explicit type selection and auto-detects the type, verify the auto-detection logic.


Issue: Identity_Verification__c Created but Fields Are Blank

Symptom: An Identity_Verification__c record exists but most or all fields are empty after processing.

callFormExtractionService parses the Lazarus response via DocumentExtractionParser. The parser maps response keys to Salesforce field API names. Blank fields indicate either that Lazarus could not extract those values from the document, or that the parser mapping is missing entries for the returned keys.

Diagnostic Steps:

  1. Enable Apex debug logging for the Queueable user and reproduce the submission.

  2. In the debug log, find the raw HTTP response from Form_Identification_Endpoint__c. Check:

    • Did Lazarus return a 200 with data, or a success wrapper with empty fields?

    • Are the field keys in the response present in DocumentExtractionParser?

  3. Check the document quality — Lazarus OCR accuracy degrades significantly on:

    • Low-resolution images (below 300 DPI)

    • Glare, shadow, or partial obstructions on the ID

    • Expired IDs with faded printing

    • Non-standard ID formats from unsupported regions

  4. If the raw response contains data but fields are blank in Salesforce, the parser mapping is missing those keys. This requires a code change to DocumentExtractionParser to add the new field mappings.


Issue: Custom Form Extraction Fails to Find Template

Symptom: PDF_Insight__c is created with Status = Failed. Debug logs show a template lookup returning no results inside callCustomFormService.

WS_DocumentInsight.callCustomFormService queries Document_Insight_Template__c using values from GenericFormWrapper:

  • sTemplateName must match Template_Name__c exactly

  • sTemplatePrimaryObject must match Primary_Object__c exactly

  • Active__c must be true

Common causes:

Cause

Resolution

Template name has trailing space or different casing

Edit the template record and verify exact spelling

Template was deactivated

Set Active__c = true on the template record

Template source does not match routing

If the template's Source__c is set to 'Google Gemini', QueueableCallCustomFormService routes to callGoogleGeminiAPI instead — verify the source value on the template

Wrong primary object selected at submission

The object selected in the UI populates sTemplatePrimaryObject — ensure it matches the template's Primary_Object__c exactly


Issue: Custom Form Extraction Returns a Response but PDF_Insight__c Shows "Failed"

Symptom: The Lazarus callout succeeds (HTTP 200) but PDF_Insight__c is set to Status = Failed.

On failure inside callCustomFormService, a PDF_Insight__c is created with Status = Failed and Missing_Fields__c populated. The failure may occur at the parsing stage, not the callout stage.

Root Cause 1 — GenericFormInsightParser.parse() failed GenericFormInsightParser.parse() processes the Lazarus key-value response. If the response structure does not match the expected format (e.g., Lazarus changed its response schema), parsing throws an exception.

Resolution: Enable debug logging and check the raw Lazarus response. Confirm it matches the format GenericFormInsightParser expects — a key-value pair structure where each entry has a recognisable key and value field.

Root Cause 2 — ProcessCustomFormParser exception After parsing, ProcessCustomFormParser.parseCustomFormJSON() applies the template field mapping. Common exceptions:

  • sFieldAPIName in Data_Field_Mapping__c references a field that no longer exists on the target object

  • sObjectName in a configuration entry is not a valid or accessible object API name

  • Running user lacks Create/Edit permissions on the target object

Check Missing_Fields__c on the PDF_Insight__c record for clues about which fields failed.


Issue: Picklist Fields Not Populated (Custom Forms)

Symptom: Text and date fields are written correctly but picklist fields remain blank after custom form extraction.

Lazarus uses a specific syntax for picklist values in its response. Unlike Gemini (which returns direct values), Lazarus returns picklist selections in one of two formats:

  • :selected: — indicates the field was checked/selected

  • true — boolean-style selection

ProcessCustomFormParser handles both formats for Lazarus picklist fields. If a picklist value is not populating:

  1. Check the raw Lazarus response to see what value is being returned for that key.

  2. If Lazarus is returning a plain string (e.g., "Married") rather than :selected: or true, the parser will not coerce it correctly for a picklist field — this requires reviewing the parser logic or adjusting the template's sDataType to Text for that field.

  3. Verify the sPicklistValue in Data_Field_Mapping__c matches the API value of the picklist entry exactly (not the label).


Issue: QueueablePDFConvert Chains Not Completing

Symptom: Some files in a multi-file submission are processed but others are not. Processing stops partway through.

QueueablePDFConvert processes one file per Queueable execution and chains itself for remaining files. Each file results in a separate Queueable job. If chaining stops:

Root Cause 1 — Queueable job limit reached Salesforce limits the number of chained Queueable jobs. In a sandbox, this limit is lower than production. If many files are submitted simultaneously across multiple submissions, the org-wide Queueable limit may be hit, and later jobs are rejected.

Resolution: Check Setup → Apex Jobs for QueueablePDFConvert jobs with status Held or Failed. Failed jobs with System.AsyncException: Maximum stack depth has been reached confirm the limit issue. Reduce batch submission size or stagger submissions.

Root Cause 2 — Earlier job threw unhandled exception If a Queueable job fails without catching the exception, the chain stops at that point. The remaining files are never processed.

Resolution: In Apex Jobs, find the failed job and read the error message. Fix the underlying issue (invalid file, auth error, endpoint down) and resubmit only the remaining files.

Root Cause 3 — File removed from ContentDocument between submission and processing If a file is deleted after submission but before its Queueable job runs, WS_DocumentInsight cannot load the ContentVersion.VersionData. This causes a null reference exception that breaks the chain.


Issue: PDF_Insight__c Stuck in "Processing" (Lazarus / Identity Path)

Unlike MoneyThumb and Ocrolus, Lazarus should never leave a record in Processing indefinitely because the response is synchronous. If a record is stuck in Processing:

Root Cause 1 — QueueablePDFConvert never ran The job was enqueued but never executed — possible in orgs with high async job volume. Check Setup → Apex Jobs for the QueueablePDFConvert job. If status is Queued or Holding, the job is waiting for an execution slot.

Root Cause 2 — Job ran but threw a governor limit exception CPU time, heap size, or SOQL limits exceeded inside the Queueable. The job is marked Failed in Apex Jobs. The PDF_Insight__c status was set to Processing before the callout and was never updated to Completed or Failed because the exception interrupted execution before the status update DML.

Resolution: Check Apex Jobs for the failure. Fix the limit issue (usually caused by overly large files or excessive SOQL inside the job), then manually update PDF_Insight__c.Status__c to Failed and resubmit.

Root Cause 3 — Governor limit hit mid-chain For a multi-file submission, early files complete but a later file hits a limit. The completed files' PDF_Insight__c status is Completed while the parent record may still show Processing if it aggregates child statuses.


Issue: Confidence Matrix Not Generating or Incomplete

Symptom: The Confidence Matrix tab shows no data, or a spinner that does not resolve.

The Confidence Matrix is built from Success*.json ContentVersion files attached to completed Lazarus PDF_Insight__c records.

Step 1 — Confirm Source Records Exist

CustomDocumentInsightController.asyncGetConfidenceMatrix(recordId) queries for Lazarus PDF_Insight__c records with Status = Completed on the parent record. If no such records exist, the matrix cannot be built.

SELECT Id, Status__c, Source__c
FROM PDF_Insight__c
WHERE <ParentLookupField__c> = '<parentRecordId>'
  AND Source__c = 'Lazarus'
  AND Status__c = 'Completed'

Step 2 — Confirm Success JSON Files Exist

For each completed Lazarus record, check for a ContentVersion named Success*.json:

SELECT Id, Title, ContentDocumentId
FROM ContentVersion
WHERE Title LIKE 'Success%'
  AND FileExtension = 'json'
  AND FirstPublishLocationId = '<PDF_Insight__c Id>'

If no Success*.json files exist, the raw Lazarus response was not saved. Check whether ConfigurationService.rawResponseFile() is enabled — this controls whether raw responses are persisted.

Step 3 — Confirm @future Method Ran

asyncGetConfidenceMatrix is an @future method. It cannot be chained from another async context. If it was called from a Queueable or another @future method, Salesforce silently drops the call with no error.

Check whether createConfidenceMatrixTable was invoked from a synchronous context (LWC controller call) vs an async context. It should only be called from a user-initiated LWC action.

Step 4 — Confirm Platform Event Was Published

On completion, asyncGetConfidenceMatrix publishes a Custom_Documents_Event__e platform event to signal the UI to refresh. If the event was published but the UI did not update, check that the LWC subscriber for Custom_Documents_Event__e is correctly registered and the running user has access to the platform event.

Step 5 — Template Data Field Mapping

The confidence matrix compares Lazarus extraction values against threshold values defined in the template's Data_Field_Mapping__c. If the template mapping has been modified since the last successful extraction, the matrix columns may not align with the stored extraction data.


Issue: Raw Response File Not Created

Symptom: No ContentVersion file is attached to the PDF_Insight__c record after processing. This blocks confidence matrix generation and makes debugging extraction failures difficult.

ProcessCustomFormParser saves the raw response via ConfigurationService.rawResponseFile(). This method checks a configuration flag before creating the file.

Resolution: Check ConfigurationService settings and ensure raw response file saving is enabled. In production environments, this may be disabled to reduce storage consumption — consider enabling it temporarily during debugging, then disabling again.


Debugging Workflow (Quick Reference)

Identity_Verification__c not created
│
├─ Check: Apex Jobs for QueueablePDFConvert
│   ├─ Failed → Check error message
│   │   ├─ Auth error (401/403) → Verify orgId/authKey in Custom Settings
│   │   ├─ Connection error → Check Remote Site Settings
│   │   └─ Null response → Endpoint URL wrong or document unreadable
│   └─ Never appeared → Submission failed before enqueue
│       Check: PDF_Insight__c created? Auth on callPDFInsightService?

Identity_Verification__c created but fields blank
│
├─ Check: Document quality (resolution, clarity, supported format)
├─ Check: sDocumentType correct (DL/Passport vs SSN routes differently)
└─ Check: DocumentExtractionParser has mapping for all response keys

PDF_Insight__c Status = Failed (Custom Form path)
│
├─ Check: Missing_Fields__c — which keys had no mapping?
├─ Check: Template exists and Active = true?
├─ Check: Template_Name__c and Primary_Object__c match exactly?
└─ Check: Running user has Create/Edit on target object?

Confidence Matrix blank
│
├─ Check: Completed Lazarus PDF_Insight__c records exist on parent?
├─ Check: Success*.json ContentVersion attached to those records?
├─ Check: asyncGetConfidenceMatrix called from sync context?
└─ Check: Custom_Documents_Event__e published and LWC subscribed?


Relevant Apex Classes Reference

Class

Responsibility

PDFInsightRequestController

LWC controller for identity document submission and feature check

CustomDocumentInsightController

LWC controller for custom form submission, confidence matrix, template management

WS_DocumentInsight

All Lazarus HTTP callouts — identity extraction, SSN extraction, custom form extraction

QueueablePDFConvert

Async per-file routing for identity documents; chains per file

QueueableCallCustomFormService

Async per-document routing for custom forms; chains per item

DocumentExtractionParser

Parses Lazarus identity document response

GenericFormInsightParser

Parses Lazarus custom form key-value response

ProcessCustomFormParser

Generic field mapping engine — creates/updates SF records from parsed key-value pairs

ConfigurationService

Raw response file toggle, FLS enforcement, test mode settings

HttpHexFormBuilder

Builds multipart form-data request bodies for Lazarus upload calls


Relevant Objects and Metadata Reference

Object / Metadata

Role

PDF_Insight__c

Central audit record — one per submission; tracks status, missing fields, duplicate keys

Identity_Verification__c

Stores extracted identity document fields (name, DOB, address, ID number, expiry)

Document_Insight_Template__c

Template config for custom forms — prompt, field mapping JSON, related object config

Feature_Entitlement__c.PDF_Insights__c

Feature flag for identity document path

Feature_Entitlement__c.Custom_Forms__c

Feature flag for custom form path

GenericFormWrapper

Carries all context through queueable chain (template name, object, document ID, source)

Custom_Documents_Event__e

Platform event published on confidence matrix completion to trigger UI refresh