TitlPdfProcessor.Models 2.10.0

dotnet add package TitlPdfProcessor.Models --version 2.10.0
                    
NuGet\Install-Package TitlPdfProcessor.Models -Version 2.10.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="TitlPdfProcessor.Models" Version="2.10.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="TitlPdfProcessor.Models" Version="2.10.0" />
                    
Directory.Packages.props
<PackageReference Include="TitlPdfProcessor.Models" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add TitlPdfProcessor.Models --version 2.10.0
                    
#r "nuget: TitlPdfProcessor.Models, 2.10.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package TitlPdfProcessor.Models@2.10.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=TitlPdfProcessor.Models&version=2.10.0
                    
Install as a Cake Addin
#tool nuget:?package=TitlPdfProcessor.Models&version=2.10.0
                    
Install as a Cake Tool

TITL PDF Processor - .NET SDK Models

C# class definitions for deserializing TITL PDF Processor API responses.

Version: 2.9
Last Updated: April 8, 2026

Installation

Copy TitlPdfProcessor.Models.cs into your project, or reference it directly.

Contract Testing

This SDK includes automated contract tests to ensure it stays in sync with the API.

# Run contract tests (requires .NET 8 SDK)
cd tests
./run-tests.sh

# Or manually
dotnet test

When making API changes, see SYNC_CHECKLIST.md for the update process.

Dependencies:

  • .NET 6.0+ (or .NET Standard 2.0+)
  • System.Text.Json (built-in) or Newtonsoft.Json

Quick Start

using System.Net.Http;
using System.Text.Json;
using TitlPdfProcessor.Models;

public class PdfProcessorClient
{
    private readonly HttpClient _client;
    private readonly JsonSerializerOptions _jsonOptions;

    public PdfProcessorClient(string apiKey)
    {
        _client = new HttpClient();
        _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
        _client.BaseAddress = new Uri("https://pdf-processor-azyjo4e2za-uc.a.run.app");

        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            PropertyNameCaseInsensitive = true
        };
    }

    public async Task<JobResponse> GetJobAsync(string jobId)
    {
        var response = await _client.GetAsync($"/api/v1/jobs/{jobId}");
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<JobResponse>(json, _jsonOptions);
    }
}

Key Type Guarantees

The API now guarantees consistent types for all fields:

Field Type Notes
PropertyIdentifiers.Address string Multiple addresses joined with \|
PropertyIdentifiers.ParcelNumbers List<string> May be empty, never null
NormalizedFields NormalizedFields? Standardized party/date/address fields (null for TSS)
NormalizedFields.AddressComponents AddressComponents? Parsed US components when Address is set (TITL-779)
StructuredFields[*] string Most values are strings or null
StructuredFields["easements"] EasementItem[] Array of easements (EASEMENT docs only)
StructuredFields["covenants"] CovenantItem[] Array of covenants (RESTRICTIVE_COVENANT docs only)
StructuredFields["additional_parcels"] ParcelItem[] Array of parcels (DEED docs with multiple properties)
StructuredFields["schedule_a_coverage"] ScheduleAItem[] Schedule A coverage items (COMMITMENT_FOR_POLICY only)
StructuredFields["schedule_b_exceptions"] ScheduleBExceptionItem[] Schedule B exceptions (COMMITMENT_FOR_POLICY only)

Page-Reference Linking (January 2026)

For TITLE_SEARCH_SUMMARY documents, each detected section now includes a SourcePage property linking the extracted data to its original location in the PDF:

// Access sections with their source page numbers
if (dataSet.DataType == "TITLE_SEARCH_SUMMARY" && dataSet.DetectedSections != null)
{
    foreach (var section in dataSet.DetectedSections)
    {
        // section.SourcePage can be "1" (single page) or "2-3" (range)
        Console.WriteLine($"[Page {section.SourcePage}] {section.SectionName}");

        // section.Data contains the extracted values for this section
        if (section.Data != null)
        {
            foreach (var kvp in section.Data)
            {
                Console.WriteLine($"  {kvp.Key}: {kvp.Value}");
            }
        }
    }
}

This enables:

  • Linking extracted fields back to their source page in the PDF viewer
  • Auditing which page each piece of data came from
  • Better user experience when reviewing extractions

Supported Document Types

The API extracts structured data from 19+ document types:

Core Legal Documents:

  • DEED - Warranty Deed, Quit Claim Deed, Deed of Trust, Open End Deed of Trust
  • MORTGAGE - Mortgages, Loan Documents
  • LIEN - Tax Liens, Judgment Liens, Mechanic's Liens
  • EASEMENT - Utility, Access, Drainage, Conservation Easements
  • RESTRICTIVE_COVENANT - CC&Rs, HOA Covenants

Supporting Documents:

  • CONSENT - Assent to Execution of Deeds, Waiver of Marital Rights
  • APPOINTMENT - Appointment of Substitute/Successor Trustee
  • ASSIGNMENT - Assignment of Rights/Interests
  • AFFIDAVIT - Heirship, Identity, Name Change Affidavits
  • AGREEMENT - Maintenance, Road, Easement Agreements

Property Documents:

  • PLAT - Plat Maps, Subdivision Plans
  • SURVEY - Property Surveys
  • TAX_STATEMENT - Tax Bills, Tax Receipts

Title & Policy Documents:

  • TITLE_SEARCH_SUMMARY - Title Search Reports
  • COMMITMENT_FOR_POLICY - Title Commitments, ALTA Policies

Release & Satisfaction Documents:

  • RELEASE - Satisfaction of Mortgage, Full Reconveyance, Release of Lien
  • PARTIAL_RELEASE - Partial Release, Partial Reconveyance, Partial Satisfaction

Court & Estate Documents:

  • JUDGMENT - Court Judgments, Final Judgments
  • LAST_WILL_AND_TESTAMENT - Wills, Testaments

Other:

  • CONTRACT - Real Estate Contracts
  • ORDINANCE - Municipal Ordinances
  • BILL_OF_SALE - Personal Property Transfers
  • UCC - UCC Filings

Working with Property Identifiers

// Access is always safe - no need to check for arrays
var job = await client.GetJobAsync(jobId);

foreach (var dataSet in job.Results.StructuredDataSets)
{
    if (dataSet.PropertyIdentifiers != null)
    {
        // Address is GUARANTEED to be a string
        string address = dataSet.PropertyIdentifiers.Address;

        // If you need individual addresses (when multiple exist)
        string[] addresses = dataSet.PropertyIdentifiers.GetAddressArray();

        // ParcelNumbers is GUARANTEED to be an array
        foreach (var parcel in dataSet.PropertyIdentifiers.ParcelNumbers)
        {
            Console.WriteLine($"Parcel: {parcel}");
        }
    }
}

Working with Structured Fields

foreach (var dataSet in job.Results.StructuredDataSets)
{
    switch (dataSet.DataType)
    {
        case "DEED":
            // Use type-safe field name constants
            var grantor = dataSet.GetField(StructuredFieldNames.GrantorName);
            var grantee = dataSet.GetField(StructuredFieldNames.GranteeName);
            var amount = dataSet.GetField(StructuredFieldNames.ConsiderationAmount);

            Console.WriteLine($"Deed: {grantor} -> {grantee} for {amount}");
            break;

        case "MORTGAGE":
            var borrower = dataSet.GetField(StructuredFieldNames.BorrowerName);
            var lender = dataSet.GetField(StructuredFieldNames.LenderName);
            var principal = dataSet.GetField(StructuredFieldNames.PrincipalAmount);

            Console.WriteLine($"Mortgage: {borrower} from {lender} for {principal}");
            break;

        case "TITLE_SEARCH_SUMMARY":
            // Title search summaries have different structure
            foreach (var section in dataSet.DetectedSections ?? new())
            {
                Console.WriteLine($"Section: {section.SectionName}");
            }
            break;
    }
}

Working with Easements and Covenants

Easement and Restrictive Covenant documents can contain multiple items. Use the helper extension methods to extract them:

foreach (var dataSet in job.Results.StructuredDataSets)
{
    // Handle EASEMENT documents (may contain multiple easements)
    if (dataSet.IsEasement())
    {
        var propertyOwner = dataSet.GetField(StructuredFieldNames.PropertyOwner);
        Console.WriteLine($"Easement from: {propertyOwner}");

        // Get all easements in this document
        foreach (var easement in dataSet.GetEasements())
        {
            Console.WriteLine($"  Type: {easement.EasementType}");
            Console.WriteLine($"  Holder: {easement.EasementHolder}");
            Console.WriteLine($"  Purpose: {easement.EasementPurpose}");
            Console.WriteLine($"  Location: {easement.EasementLocation}");
            Console.WriteLine($"  Width: {easement.EasementWidth}");
        }
    }

    // Handle RESTRICTIVE_COVENANT documents (typically 10-50+ restrictions)
    if (dataSet.IsRestrictiveCovenant())
    {
        var subdivision = dataSet.GetField(StructuredFieldNames.SubdivisionName);
        Console.WriteLine($"Covenants for: {subdivision}");

        // Get all covenants/restrictions in this document
        foreach (var covenant in dataSet.GetCovenants())
        {
            Console.WriteLine($"  [{covenant.CovenantType}] {covenant.Description}");
            Console.WriteLine($"    Applies to: {covenant.AppliesTo}");
            Console.WriteLine($"    Enforcement: {covenant.Enforcement}");
        }
    }

    // Handle DEED documents (may have multiple parcels)
    if (dataSet.IsDeed())
    {
        var grantor = dataSet.GetField(StructuredFieldNames.GrantorName);
        var grantee = dataSet.GetField(StructuredFieldNames.GranteeName);
        var deedType = dataSet.GetField(StructuredFieldNames.DeedType);

        // For Deed of Trust, also extract trustee and lender
        if (deedType?.Contains("trust", StringComparison.OrdinalIgnoreCase) == true)
        {
            var trustee = dataSet.GetField(StructuredFieldNames.TrusteeName);
            var lender = dataSet.GetField(StructuredFieldNames.LenderName);
            Console.WriteLine($"Deed of Trust: Borrower={grantor}, Trustee={trustee}, Lender={lender}");
        }

        // Get all parcels if deed covers multiple properties
        foreach (var parcel in dataSet.GetParcels())
        {
            Console.WriteLine($"  Parcel: {parcel.ParcelId}");
            Console.WriteLine($"    Address: {parcel.PropertyAddress}");
            Console.WriteLine($"    Legal: {parcel.LegalDescription}");
        }
    }
}

Working with Title Commitments (Schedule A/B)

Title commitment documents (COMMITMENT_FOR_POLICY) now return Schedule A and Schedule B as structured arrays instead of free-text blobs (TITL-212, February 2026).

foreach (var dataSet in job.Results.StructuredDataSets)
{
    if (dataSet.IsCommitmentForPolicy())
    {
        var policyNumber = dataSet.GetField(StructuredFieldNames.PolicyNumber);
        var insured = dataSet.GetField(StructuredFieldNames.InsuredName);
        Console.WriteLine($"Commitment: {policyNumber} for {insured}");

        // Schedule A - coverage terms (effective date, amount, insured, etc.)
        foreach (var item in dataSet.GetScheduleACoverage())
        {
            Console.WriteLine($"  Schedule A: {item.Label} = {item.Value}");
        }

        // Schedule B - exceptions (easements, liens, restrictions, etc.)
        foreach (var exception in dataSet.GetScheduleBExceptions())
        {
            Console.WriteLine($"  Schedule B [{exception.Type}]: {exception.Description}");
        }
    }
}

Document Types Quick Reference

Type Description Array Fields
DEED Warranty deed, quit claim, deed of trust, etc. additional_parcels[]
MORTGAGE Mortgages and loan documents -
LIEN Tax liens, judgment liens, mechanic's liens -
EASEMENT Utility, access, drainage easements easements[]
RESTRICTIVE_COVENANT HOA declarations, CC&Rs covenants[]
CONSENT Assent to deed, waiver of marital rights -
APPOINTMENT Appointment of substitute/successor trustee -
TITLE_SEARCH_SUMMARY Title search reports -
TAX_STATEMENT Property tax statements, receipts -
PLAT Recorded plat maps -
SURVEY Survey documents -
CONTRACT Real estate contracts -
AGREEMENT Maintenance, road agreements -
ASSIGNMENT Assignment of rights/interests -
AFFIDAVIT Heirship, identity affidavits -
UCC UCC financing statements -
BILL_OF_SALE Personal property transfers -
ORDINANCE Municipal ordinances -
COMMITMENT_FOR_POLICY Title commitments, ALTA policies schedule_a_coverage[], schedule_b_exceptions[]
JUDGMENT Court judgments, final judgments -
LAST_WILL_AND_TESTAMENT Wills, testaments -
RELEASE Satisfaction of mortgage, reconveyance -
PARTIAL_RELEASE Partial release of mortgage/lien -
UNKNOWN Unclassified documents -

Working with Address Analysis (v2.8+)

When a search package contains multiple documents, the API collects all property street addresses, filters out legal descriptions (lot/plat/subdivision references), and runs AI-powered comparison to determine if multiple distinct properties are present.

var job = await client.GetJobAsync(jobId);

if (job.Results?.AddressAnalysis != null)
{
    var analysis = job.Results.AddressAnalysis;

    // Quick check: does this package reference multiple properties?
    if (analysis.MultipleAddressesDetected)
    {
        Console.WriteLine("⚠️ Multiple properties detected!");
    }

    // List all unique street addresses
    foreach (var addr in analysis.UniqueAddresses)
    {
        Console.WriteLine($"Address: {addr.Address}");
        foreach (var src in addr.Sources)
            Console.WriteLine($"  Found in: {src.DocumentType} (pages {src.SourcePages})");
    }

    // Pairwise comparison details (when multiple addresses exist)
    if (analysis.Comparisons != null)
    {
        foreach (var cmp in analysis.Comparisons)
        {
            var status = cmp.IsSameProperty ? "same" : "DIFFERENT";
            Console.WriteLine($"  {cmp.Address1} vs {cmp.Address2} → {status}");
        }
    }
}

// Or use the convenience helpers:
if (job.Results.HasMultipleProperties())
{
    var addresses = job.Results.GetUniqueAddresses();
    Console.WriteLine($"Found {addresses.Count} distinct addresses");
}

Key behaviors:

  • Legal descriptions (lot references, plat books, subdivision text) are excluded from analysis
  • MultipleAddressesDetected is based on semantic comparison, not string equality
  • Different formatting of the same address (e.g., "26 Steeplechase Dr" vs "26 STEEPLECHASE DRIVE") resolves to isSameProperty: true
  • The field is absent when no street addresses are extracted

Working with Normalized Fields (v2.7+)

Every structured extraction (except TITLE_SEARCH_SUMMARY) now includes a NormalizedFields object that provides standardized access to common fields regardless of document type:

foreach (var dataSet in job.Results.StructuredDataSets)
{
    if (dataSet.NormalizedFields != null)
    {
        var nf = dataSet.NormalizedFields;
        Console.WriteLine($"{nf.ContentType}: {nf.FirstParty} → {nf.SecondParty}");
        Console.WriteLine($"  Date: {nf.DocumentDate}, Recorded: {nf.RecordedDate}");
        Console.WriteLine($"  Address: {nf.Address}");
        Console.WriteLine($"  Amount: {nf.ConsiderationAmount}");

        if (nf.TaxIds?.Count > 0)
            Console.WriteLine($"  Tax IDs: {string.Join(", ", nf.TaxIds)}");

        if (nf.ReferencedInstruments?.Count > 0)
            Console.WriteLine($"  References: {nf.ReferencedInstruments.Count} instruments");
    }
}
Normalized Field DEED MORTGAGE LIEN TAX_STATEMENT RELEASE
FirstParty Grantor Borrower Property Owner Property Owner Releasing Party
SecondParty Grantee Lender Lien Holder - Borrower
ThirdParty Trustee - - - -
DocumentDate Deed Date Mortgage Date Lien Date Tax Year Release Date
ConsiderationAmount Amount Principal Lien Amount - -

Polling for Completion

public async Task<JobResponse> WaitForCompletionAsync(string jobId, int maxWaitSeconds = 300)
{
    var startTime = DateTime.UtcNow;
    var delay = TimeSpan.FromSeconds(2);

    while ((DateTime.UtcNow - startTime).TotalSeconds < maxWaitSeconds)
    {
        var job = await GetJobAsync(jobId);

        if (job.Status == "COMPLETED" || job.Status == "FAILED")
        {
            return job;
        }

        await Task.Delay(delay);

        // Exponential backoff up to 10 seconds
        if (delay < TimeSpan.FromSeconds(10))
            delay = TimeSpan.FromSeconds(delay.TotalSeconds * 1.5);
    }

    throw new TimeoutException($"Job {jobId} did not complete within {maxWaitSeconds} seconds");
}

Using with Newtonsoft.Json

If you prefer Newtonsoft.Json:

using Newtonsoft.Json;

var json = await response.Content.ReadAsStringAsync();
var job = JsonConvert.DeserializeObject<JobResponse>(json);

Complete Example

using System;
using System.IO;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using TitlPdfProcessor.Models;

class Program
{
    static async Task Main(string[] args)
    {
        var apiKey = "sk-your-api-key-here";
        var client = new PdfProcessorClient(apiKey);

        // Upload a PDF
        var jobId = await client.UploadPdfAsync("document.pdf");
        Console.WriteLine($"Job created: {jobId}");

        // Wait for completion
        var job = await client.WaitForCompletionAsync(jobId);

        if (job.Status == "COMPLETED")
        {
            Console.WriteLine($"Found {job.Results.StructuredDataSets.Count} documents");

            foreach (var dataSet in job.Results.StructuredDataSets)
            {
                Console.WriteLine($"\n--- {dataSet.DataType}: {dataSet.Title} ---");
                Console.WriteLine($"Pages: {dataSet.SourcePages}");
                Console.WriteLine($"Confidence: {dataSet.Confidence:P0}");

                // Safe access to property identifiers
                if (dataSet.PropertyIdentifiers != null)
                {
                    Console.WriteLine($"Address: {dataSet.PropertyIdentifiers.Address}");
                    Console.WriteLine($"Parcels: {string.Join(", ", dataSet.PropertyIdentifiers.ParcelNumbers)}");
                }

                // Safe access to structured fields
                if (dataSet.StructuredFields != null)
                {
                    foreach (var (field, value) in dataSet.StructuredFields)
                    {
                        if (!string.IsNullOrEmpty(value))
                            Console.WriteLine($"  {field}: {value}");
                    }
                }

                // For TITLE_SEARCH_SUMMARY: Access detected sections with page references
                if (dataSet.DataType == "TITLE_SEARCH_SUMMARY" && dataSet.DetectedSections != null)
                {
                    Console.WriteLine("\n  Detected Sections:");
                    foreach (var section in dataSet.DetectedSections)
                    {
                        Console.WriteLine($"    [{section.SourcePage}] {section.SectionName} ({section.SectionType})");
                        // section.Data contains the extracted key-value pairs for this section
                    }
                }
            }
        }
        else
        {
            Console.WriteLine($"Job failed: {job.Error}");
        }
    }
}

public class PdfProcessorClient
{
    private readonly HttpClient _client;
    private readonly JsonSerializerOptions _jsonOptions;
    private const string BaseUrl = "https://pdf-processor-azyjo4e2za-uc.a.run.app";

    public PdfProcessorClient(string apiKey)
    {
        _client = new HttpClient { BaseAddress = new Uri(BaseUrl) };
        _client.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");

        _jsonOptions = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
            PropertyNameCaseInsensitive = true
        };
    }

    public async Task<string> UploadPdfAsync(string filePath)
    {
        using var content = new MultipartFormDataContent();
        using var fileStream = File.OpenRead(filePath);
        using var fileContent = new StreamContent(fileStream);

        content.Add(fileContent, "file", Path.GetFileName(filePath));
        content.Add(new StringContent("true"), "enableDataExtraction");
        content.Add(new StringContent("true"), "enableClassification");

        var response = await _client.PostAsync("/api/v1/upload", content);
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        using var doc = JsonDocument.Parse(json);
        return doc.RootElement.GetProperty("jobId").GetString();
    }

    public async Task<JobResponse> GetJobAsync(string jobId)
    {
        var response = await _client.GetAsync($"/api/v1/jobs/{jobId}");
        response.EnsureSuccessStatusCode();

        var json = await response.Content.ReadAsStringAsync();
        return JsonSerializer.Deserialize<JobResponse>(json, _jsonOptions);
    }

    public async Task<JobResponse> WaitForCompletionAsync(string jobId, int maxWaitSeconds = 300)
    {
        var startTime = DateTime.UtcNow;
        var delay = TimeSpan.FromSeconds(2);

        while ((DateTime.UtcNow - startTime).TotalSeconds < maxWaitSeconds)
        {
            var job = await GetJobAsync(jobId);
            Console.WriteLine($"Status: {job.Status} ({job.Progress}%)");

            if (job.Status == "COMPLETED" || job.Status == "FAILED")
                return job;

            await Task.Delay(delay);
            if (delay < TimeSpan.FromSeconds(10))
                delay = TimeSpan.FromSeconds(delay.TotalSeconds * 1.5);
        }

        throw new TimeoutException($"Job did not complete within {maxWaitSeconds} seconds");
    }
}

Support

For questions or issues:

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

  • net6.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.10.0 103 4/30/2026
2.9.0 121 4/8/2026
2.8.0 114 4/2/2026
2.7.0 141 3/10/2026
2.6.0 113 2/16/2026
2.5.0 114 1/26/2026
2.3.0 176 1/19/2026

v2.10.0 (April 2026)
- Added normalizedFields.address_components (AddressComponents) — structured US address fields derived server-side from address (TITL-779)

v2.9.0 (April 2026)
- Normalized JUDGEMENT → JUDGMENT as the canonical document type (TITL-606)
- Added IsJudgment() helper method (checks DataType == "JUDGMENT")
- Deprecated IsJudgement() with [Obsolete] attribute — still works for both spellings
- Updated sample responses and contract tests for JUDGMENT

v2.8.0 (April 2026)
- Added AddressAnalysis to JobResults for cross-document address comparison (TITL-598)
- AddressAnalysis includes: UniqueAddresses, MultipleAddressesDetected, Comparisons
- Legal descriptions (lot/plat/subdivision references) are now filtered from address analysis
- Added AddressSource, AddressDocumentSource, AddressComparison classes
- Added HasMultipleProperties() and GetUniqueAddresses() helper methods on JobResults
- Non-breaking: existing v2.7.0 consumers will ignore the new optional field

v2.7.0 (March 2026)
- Added NormalizedFields to all structured extractions (first_party, second_party, document_date, etc.)
- Added RELEASE document type (satisfaction of mortgage, full reconveyance, release of lien)
- Added IsRelease() helper method
- Added ReleaseExtraction interface with fields matching release.md prompt
- Aligned extraction interfaces with AI prompts:
 - MORTGAGE: loan_amount → principal_amount
 - LIEN: debtor_name → property_owner
 - TAX_STATEMENT: fully restructured (owner_name → property_owner, parcel_number → parcel_id, etc.)
- Deprecated old field constants with [Obsolete] attributes (DebtorName, ParcelNumber, etc.)
- Added new StructuredFieldNames: PrincipalAmount, ParcelId, TotalAssessedValue, TotalTaxDue, etc.

v2.6.0 (February 2026)
- BREAKING: schedule_a_coverage and schedule_b_exceptions are now structured arrays (TITL-212)
- Added ScheduleAItem class (label, value) for Schedule A coverage terms
- Added ScheduleBExceptionItem class (description, type) for Schedule B exceptions
- Added GetScheduleACoverage() and GetScheduleBExceptions() helper methods
- Updated sample responses and contract tests

v2.5.0 (January 2026)
- Added PARTIAL_RELEASE, SECURITY_DEED, DEED_OF_TRUST, NOTICE_OF_COMPLETION document types
- Added ParcelItem class and GetParcels() helper for multi-parcel deeds
- Added JurisdictionInfo for state/county-aware processing

v2.3.0 (January 2026)
- Added COMMITMENT_FOR_POLICY document type (title commitments, ALTA policies)
- Added JUDGEMENT document type (court judgments)
- Added LAST_WILL_AND_TESTAMENT document type
- Fixed nullable TotalPages in PageNumberingContext
- Added contract tests for SDK validation

v2.2.0 (January 2026)
- Added CONSENT and APPOINTMENT document types
- Added sourcePage support for TITLE_SEARCH_SUMMARY sections
- Improved table extraction for large documents