IRONSOFTWAREHOME
VIDEOS

Migración de Veryfi a IronOCR

Kannaopat Udonpant
Kannapat Udonpant
Updated: 1 de agosto de 2026

Esta guía guía a los desarrolladores de .NET a través del proceso de sustitución de la API de procesamiento de documentos en la nube de Muy fi por IronOCR, una biblioteca IronOCR local. Abarca el intercambio de paquetes, la limpieza de espacios de nombres y cuatro ejemplos completos de migración de código centrados en los patrones más comunes en torno a Veryfi: inicialización del cliente, extracción de campos basada en regiones, categorización de gastos con datos estructurados y sustitución de webhooks. No es necesario haber leído previamente el artículo comparativo.

¿Por qué migrar desde Veryfi?

Los documentos financieros fluyen a través del proceso de Muy fi en una sola dirección: desde su infraestructura hacia la de ellos. Ese hecho arquitectónico impulsa la mayoría de las migraciones. Estos son los puntos débiles específicos que empujan a los equipos a dar el salto.

Cada llamada de documento transmite datos financieros confidenciales a un servidor de terceros. Los recibos contienen los cuatro últimos dígitos de la tarjeta y las relaciones con los proveedores. Las facturas incluyen números de cuenta bancaria, números de ruta y números de identificación fiscal de los proveedores. Los extractos bancarios contienen el historial completo de transacciones. Con Veryfi, cada llamada ProcessDocumentAsync carga esos bytes a api.veryfi.com, los procesa en la infraestructura de Veryfi, y devuelve JSON. Tu control sobre esos datos termina en el momento en que se envía la solicitud HTTP.

Se requieren cuatro credenciales y deben mantenerse sincronizadas en todos los entornos. VeryfiClient requiere clientId, clientSecret, username, y apiKey—cuatro secretos separados para almacenar en la configuración, rotar según horario, inyectar en las tuberías de CI/CD, y auditar para exposición. Una sola fuga de credenciales rompe la autenticación de todos los documentos procesados en toda la aplicación.IronOCR requiere una cadena de clave de licencia.

El precio por documento se acumula sin límite máximo. Los recibos cuestan aproximadamente entre 0,05 y 0,15 dólares cada uno, las facturas entre 0,10 y 0,25 dólares, y los extractos bancarios entre 0,15 y 0,30 dólares. A razón de 50 000 documentos al mes, eso supone entre 5000 y 15 000 dólares al mes en facturación por consumo, sin reducción en el segundo ni en el tercer año. La licencia IronOCR Professional, con un precio de 2999 $, cubre un número ilimitado de documentos de forma perpetua; el umbral de rentabilidad frente a un gasto mensual de 5000 $ en Muy fi se alcanza en menos de tres semanas.

La API es solo asincrónica porque el trabajo subyacente es remoto. ProcessDocumentAsync no es asincrónica porque el procesamiento es computacionalmente prolongado; Es asíncrono porque el documento debe enviarse a un servidor, ponerse en cola detrás de otras solicitudes, completar la inferencia y devolver una respuesta a través de la red. La latencia no es determinista. La limitación de velocidad HTTP 429 requiere una lógica de reintento. Los errores de pago HTTP 402 detienen por completo el procesamiento por lotes. Los errores HTTP 500 en la infraestructura de Muy fi paralizan tu flujo de trabajo.

El alcance de los documentos de Muy fi termina en el límite del documento de gastos. Los modelos entrenados devuelven campos estructurados de forma fiable para recibos, facturas, cheques, extractos bancarios, formularios W-2 y tarjetas de visita. Fuera de esa lista —documentos empresariales generales, contratos, historiales médicos, documentos de envío, formularios internos personalizados— los resultados se deterioran o requieren un entrenamiento de modelos personalizados de pago. Las organizaciones que adoptan Muy fi para la automatización de gastos suelen descubrir, en un plazo de 6 a 12 meses, que otros equipos necesitan OCR para documentos que Muy fi no fue diseñado para gestionar.

El esquema propietario JSON de Muy fi acopla toda la lógica de extracción a un único proveedor. Cada línea de código que lee response.Vendor?.Name, response.BankAccount?.RoutingNumber, o response.LineItems es código que solo funciona con Veryfi. Cambiar de proveedor —o pasar a un OCR local— implica reescribir toda la lógica de extracción desde cero.

El problema fundamental

// Veryfi: financial data leaves your infrastructure on every call
var client = new VeryfiClient(clientId, clientSecret, username, apiKey); // 4 secrets
var bytes = File.ReadAllBytes("invoice-with-routing-number.pdf");
var response = await client.ProcessDocumentAsync(bytes); // bank details transmitted
var routingNumber = response.BankAccount?.RoutingNumber; // arrived via Muy fi cloud
C#
// IronOCR: routing numbers never leave your server
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // 1 key
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("invoice-with-routing-number.pdf"); // processed locally
var result = ocr.Read(input);
var routingNumber = Regex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})").Groups[1].Value;
C#

##IronOCR frente a Veryfi: comparación de características

La tabla siguiente compara las capacidades de ambos productos para facilitar la evaluación técnica.

CaracterísticaMuy fiIronOCR
Lugar de procesamientoServidores en la nube Muy fiSu infraestructura
Modelo de despliegueSolo API en la nubeLocal, Docker, Azure, AWS, Linux
Soporte sin conexiónNo
Se requiere conexión a InternetSí (todos los documentos)No
Los datos salen de la infraestructuraSí (en cada llamada)Nunca
Compatible con la HIPAA sin BAANo
Compatibilidad con entornos aisladosNo es posibleTotalmente compatible
Modelo de preciosPor documento (entre 0,05 y 0,30 dólares)Licencia perpetua ($999–$2,399)
Credenciales requeridas4 (clientId, clientSecret, username, apiKey)1 clave de licencia
API síncronaNo (solo asíncrono)
limitación de velocidadSí (HTTP 429)None
Alcance del documentoRecibos, facturas, cheques, extractos bancarios, formularios W-2, tarjetas de visitaCualquier tipo de documento
Tipos de documentos personalizadosSe requiere formación en modelos de pagoCualquier diseño mediante extracción de expresiones regulares/patrones
Entrada de PDFSí (carga de bytes)Sí (nativo, local)
Salida en PDF con capacidad de búsquedaNoSí (result.SaveAsSearchablePdf())
OCR basado en regionesNoSí (CropRectangle)
Lectura de BarCodesNoSí (mismo proceso de OCR)
Acceso estructurado a los resultadosCampos JSON preanalizadosPáginas, párrafos, líneas, palabras con coordenadas
Puntuación de confianzaPor campo (propietario)Por palabra y en general (result.Confidence)
Soporte para más de 125 idiomasLimitadoSí (paquetes de idiomas de NuGet)
Procesamiento paralelo seguro para subprocesosSe aplican límites de concurrencia HTTPCompleto (un IronTesseract por hilo)
Pruebas unitarias sin simulacionesRequiere simulación de HTTPPruebas locales directas

Inicio rápido: Migración de Muy fi a IronOCR

Paso 1: Sustituir el paquete NuGet

Eliminar el SDK de Veryfi:

dotnet remove package Veryfi
SHELL

Instala IronOCR desde NuGet :

dotnet add package IronOcr

Paso 2: Actualizar los espacios de nombres

Sustituya los espacios de nombres de Muy fi por el espacio de nombres de IronOCR:

// Before (Veryfi)
using Veryfi;
using Veryfi.Models;

// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
C#

Paso 3: Inicializar licencia

Añade esta línea una vez al iniciar la aplicación, antes de cualquier llamada a OCR:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

Ejemplos de migración de código

Sustitución del cliente de procesamiento de documentos

Los servicios de Muy fi están construidos alrededor de la inyección de constructor de VeryfiClient. El constructor de cuatro credenciales es un punto natural para la inyección de dependencias, pero crea cuatro secretos que deben gestionarse y rotarse. Al sustituir esto por IronOCR, se consolidan las credenciales en una única clave de licencia y se traslada la instanciación del motor de procesamiento a la propia clase de servicio.

Enfoque de Veryfi:

using Veryfi;
using Microsoft.Extensions.Configuration;

public class ExpenseDocumentService
{
    private readonly VeryfiClient _client;

    // Four credentials injected — four secrets to manage, store, rotate
    public ExpenseDocumentService(IConfiguration config)
    {
        _client = new VeryfiClient(
            config["Veryfi:ClientId"],       // secret 1
            config["Veryfi:ClientSecret"],   // secret 2
            config["Veryfi:Username"],       // secret 3
            config["Veryfi:ApiKey"]          // secret 4
        );
    }

    public async Task<string> GetVendorNameAsync(string documentPath)
    {
        var bytes = File.ReadAllBytes(documentPath);
        // Document uploaded to Muy fi on this call
        var response = await _client.ProcessDocumentAsync(bytes);
        return response.Vendor?.Name;
    }

    public async Task<decimal?> GetTotalAsync(string documentPath)
    {
        var bytes = File.ReadAllBytes(documentPath);
        var response = await _client.ProcessDocumentAsync(bytes);
        return response.Total;
    }
}
C#

Enfoque IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

public class ExpenseDocumentService
{
    private readonly IronTesseract _ocr;

    // One license key — set once at startup, not per-instance
    public ExpenseDocumentService()
    {
        _ocr = new IronTesseract();
    }

    public string GetVendorName(string documentPath)
    {
        // All processing local — document bytes never leave this server
        var result = _ocr.Read(documentPath);

        // Vendor is typically the first non-whitespace line on a receipt
        return result.Pages[0].Paragraphs
            .OrderBy(p => p.Y)
            .Select(p => p.Text.Trim())
            .FirstOrDefault(t => t.Length > 3);
    }

    public decimal? GetTotal(string documentPath)
    {
        var result = _ocr.Read(documentPath);
        var match = Regex.Match(result.Text,
            @"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase);
        return match.Success
            ? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
            : (decimal?)null;
    }
}
C#

El cambio de constructor elimina cuatro entradas de configuración de cada entorno: appsettings.json, secretos de Docker, referencias de Azure Key Vault y variables de tuberías de CI/CD. La instancia de IronTesseract es reutilizable a través de múltiples llamadas en el mismo hilo. Consulte la guía de configuración de IronTesseract para conocer los patrones de registro de singletons en contenedores de inyección de dependencias de .NET Core.

Extracción de campos de recibos con OCR basado en regiones

Veryfi extrae los campos de los recibos ejecutando sus modelos de aprendizaje automático entrenados sobre la imagen completa del documento y devolviendo una respuesta JSON preestructurada. El equivalente de IronOCR es OCR basado en regiones usando CropRectangle, que apunta a zonas específicas de la imagen del recibo—zona de encabezado para el proveedor, zona de pie de página para totales—en lugar de realizar un pase de página completa buscando patrones en la salida. Esto es más rápido para diseños conocidos y más preciso cuando el área de interés está bien definida.

Enfoque de Veryfi:

using Veryfi;

public class ReceiptFieldExtractor
{
    private readonly VeryfiClient _client;

    public ReceiptFieldExtractor(VeryfiClient client)
    {
        _client = client;
    }

    public async Task<(string Vendor, decimal? Total, decimal? Tax)>
        ExtractReceiptFieldsAsync(string imagePath)
    {
        var bytes = File.ReadAllBytes(imagePath);

        // Full document uploaded — Veryfi's ML returns structured fields
        var response = await _client.ProcessDocumentAsync(bytes);

        return (
            Vendor: response.Vendor?.Name,
            Total:  response.Total,
            Tax:    response.Tax
        );
    }
}
C#

Enfoque IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

public class ReceiptFieldExtractor
{
    private readonly IronTesseract _ocr = new IronTesseract();

    public (string Vendor, decimal? Total, decimal? Tax)
        ExtractReceiptFields(string imagePath)
    {
        // Region 1: Header zone — vendor name typically in top 15% of receipt
        var headerRegion = new CropRectangle(0, 0, 800, 150);
        using var headerInput = new OcrInput();
        headerInput.LoadImage(imagePath, headerRegion);
        headerInput.Deskew();
        var headerResult = _ocr.Read(headerInput);

        // Region 2: Footer zone — totals typically in bottom 20% of receipt
        var footerRegion = new CropRectangle(0, 650, 800, 200);
        using var footerInput = new OcrInput();
        footerInput.LoadImage(imagePath, footerRegion);
        footerInput.DeNoise();
        var footerResult = _ocr.Read(footerInput);

        var vendor = headerResult.Pages[0].Paragraphs
            .OrderBy(p => p.Y)
            .Select(p => p.Text.Trim())
            .FirstOrDefault(t => t.Length > 3);

        var footerText = footerResult.Text;

        var totalMatch = Regex.Match(footerText,
            @"(?:Total|Grand Total):?\s*\$?\s*([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase);

        var taxMatch = Regex.Match(footerText,
            @"(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase);

        return (
            Vendor: vendor,
            Total: totalMatch.Success
                ? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
                : (decimal?)null,
            Tax: taxMatch.Success
                ? decimal.Parse(taxMatch.Groups[1].Value.Replace(",", ""))
                : (decimal?)null
        );
    }
}
C#

CropRectangle toma (x, y, width, height) en píxeles. Procesar solo las zonas del encabezado y el pie de página es más rápido que leer la página completa y evita coincidencias falsas con los importes de las partidas individuales del cuerpo del recibo. La guía OCR basada en regiones abarca estrategias de medición de coordenadas para documentos de tamaño variable, y el ejemplo de recorte de región muestra el patrón completo.

Categorización de gastos con datos de párrafos estructurados

Veryfi devuelve response.LineItems como un array preestructurado de objetos con Description, Quantity, UnitPrice, y Total ya analizados.IronOCR proporciona el equivalente a través de result.Pages[0].Paragraphs y result.Lines, que exponen cada bloque de texto con sus coordenadas X/Y. La lógica de categorización de gastos —decidir si una partida es una comida, un viaje, un material o un gasto de software— funciona con el mismo texto en ambos casos. La diferencia es que, con IronOCR, la lógica de categorización es tuya: puedes controlarla, ajustarla y ampliarla sin necesidad de un ciclo de reentrenamiento de ML de pago.

Enfoque de Veryfi:

using Veryfi;

public class ExpenseCategorizer
{
    private readonly VeryfiClient _client;

    public ExpenseCategorizer(VeryfiClient client)
    {
        _client = client;
    }

    public async Task<Dictionary<string, decimal>> CategorizeExpensesAsync(string receiptPath)
    {
        var bytes = File.ReadAllBytes(receiptPath);
        var response = await _client.ProcessDocumentAsync(bytes);

        var categories = new Dictionary<string, decimal>();

        // Line items arrive pre-parsed from Veryfi's ML pipeline
        foreach (var item in response.LineItems ?? Enumerable.Empty<dynamic>())
        {
            var category = response.Category ?? "Uncategorized";
            var amount   = (decimal)(item.Total ?? 0m);

            if (!categories.ContainsKey(category))
                categories[category] = 0m;

            categories[category] += amount;
        }

        return categories;
    }
}
C#

Enfoque IronOCR:

using IronOcr;
using System.Text.RegularExpressions;

public class ExpenseCategorizer
{
    private readonly IronTesseract _ocr = new IronTesseract();

    // Keyword-based categorization — tune these for your expense policy
    private static readonly Dictionary<string, string[]> CategoryKeywords = new()
    {
        ["Meals & Entertainment"] = new[] { "restaurant", "cafe", "coffee", "lunch", "dinner", "food", "bar" },
        ["Travel"]                = new[] { "airline", "hotel", "uber", "lyft", "taxi", "parking", "gas", "fuel" },
        ["Office Supplies"]       = new[] { "staples", "office depot", "paper", "ink", "toner", "supplies" },
        ["Software & Subscriptions"] = new[] { "adobe", "microsoft", "github", "aws", "azure", "slack" }
    };

    public Dictionary<string, decimal> CategorizeExpenses(string receiptPath)
    {
        var result = _ocr.Read(receiptPath);

        // Use paragraph coordinates to isolate line items
        // Line items typically appear in the middle vertical band of the receipt
        var lineItemParagraphs = result.Pages[0].Paragraphs
            .Where(p => p.Y > 150 && p.Y < 650) // skip header/footer regions
            .OrderBy(p => p.Y)
            .ToList();

        var categories = new Dictionary<string, decimal>();
        var pricePattern = new Regex(@"\$?([\d,]+\.\d{2})$");
        var vendorText   = result.Text.ToLower();

        // Determine top-level category from vendor name
        var topCategory = "Uncategorized";
        foreach (var (cat, keywords) in CategoryKeywords)
        {
            if (keywords.Any(kw => vendorText.Contains(kw)))
            {
                topCategory = cat;
                break;
            }
        }

        // Extract individual line item amounts
        foreach (var para in lineItemParagraphs)
        {
            var priceMatch = pricePattern.Match(para.Text.Trim());
            if (!priceMatch.Success)
                continue;

            if (!decimal.TryParse(priceMatch.Groups[1].Value.Replace(",", ""), out var amount))
                continue;

            // Classify individual items where keywords appear in the description
            var itemCategory = topCategory;
            var descriptionText = para.Text.ToLower();
            foreach (var (cat, keywords) in CategoryKeywords)
            {
                if (keywords.Any(kw => descriptionText.Contains(kw)))
                {
                    itemCategory = cat;
                    break;
                }
            }

            if (!categories.ContainsKey(itemCategory))
                categories[itemCategory] = 0m;

            categories[itemCategory] += amount;
        }

        return categories;
    }
}
C#

La colección de Paragraphs proporciona la coordenada Y de cada bloque de texto, lo que facilita aislar la zona vertical donde aparecen los ítems en un diseño de recibo estándar. La guía de acceso a datos estructurados explica la jerarquía completa de Pages, Paragraphs, Lines, Words, y Characters con sus propiedades de coordenadas. Para los recibos con mala calidad de escaneo —papel arrugado, impresión térmica con poco contraste—, la guía de corrección de la calidad de la imagen incluye filtros de preprocesamiento que mejoran la precisión antes de que se ejecute la lógica de categorización.

Eliminación de webhooks y sustitución de lotes sincrónicos

En caso de grandes volúmenes de documentos, Muy fi recomienda las notificaciones basadas en webhooks en lugar del sondeo. El patrón requiere un punto final HTTPS de acceso público, un secreto de webhook para la verificación de la firma, una cola para almacenar los resultados hasta que se active el webhook y una lógica de reintento para las entregas fallidas. Se trata de una infraestructura importante para lo que, en última instancia, es una solución alternativa al hecho de que el OCR en la nube es lento en comparación con el procesamiento local.IronOCR procesa de forma sincrónica. No hay ninguna brecha asíncrona que salvar con un webhook.

Enfoque de Veryfi:

using Veryfi;
using Microsoft.AspNetCore.Mvc;

// Muy fi webhook receiver — required for high-volume reliable processing
[ApiController]
[Route("webhooks")]
public class VeryfiWebhookController : ControllerBase
{
    private readonly IDocumentResultQueue _queue;

    public VeryfiWebhookController(IDocumentResultQueue queue)
    {
        _queue = queue;
    }

    [HttpPost("veryfi")]
    public IActionResult ReceiveWebhook([FromBody] VeryfiWebhookPayload payload,
                                        [FromHeader(Name = "X-Veryfi-Token")] string token)
    {
        // Validate webhook signature — prevents spoofed payloads
        if (!IsValidSignature(token, payload))
            return Unauthorized();

        // Enqueue result for async downstream consumption
        _queue.Enqueue(new DocumentResult
        {
            DocumentId = payload.Id,
            Vendor     = payload.Data?.Vendor?.Name,
            Total      = payload.Data?.Total
        });

        return Ok();
    }

    private bool IsValidSignature(string token, VeryfiWebhookPayload payload) =>
        // HMAC validation against webhook secret — infrastructure requirement
        token == ComputeHmac(payload, Environment.GetEnvironmentVariable("VERYFI_WEBHOOK_SECRET"));
}

// Document batch submission — fire and forget, results arrive via webhook
public class VeryfiDocumentBatchSubmitter
{
    private readonly VeryfiClient _client;

    public async Task SubmitBatchAsync(string[] documentPaths)
    {
        foreach (var path in documentPaths)
        {
            var bytes = File.ReadAllBytes(path);
            // Submit — result arrives asynchronously via webhook, not here
            await _client.ProcessDocumentAsync(bytes);
        }
    }
}
C#

Enfoque IronOCR:

using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;

// No webhook controller needed — results are synchronous and local
public class DocumentBatchProcessor
{
    // IronTesseract is thread-safe when one instance is created per thread
    public List<DocumentResult> ProcessBatch(string[] documentPaths)
    {
        var results = new ConcurrentBag<DocumentResult>();

        Parallel.ForEach(documentPaths, documentPath =>
        {
            // One IronTesseract per thread — thread-safe pattern
            var ocr    = new IronTesseract();
            var result = ocr.Read(documentPath);

            results.Add(new DocumentResult
            {
                FilePath   = documentPath,
                Vendor     = ExtractVendor(result),
                Total      = ExtractTotal(result.Text),
                Confidence = result.Confidence,
                // Result is available immediately — no queue, no webhook
                ProcessedAt = DateTime.UtcNow
            });
        });

        return results.OrderBy(r => r.FilePath).ToList();
    }

    private string ExtractVendor(OcrResult result)
    {
        // Vendor: first substantive paragraph ordered by vertical position
        return result.Pages[0].Paragraphs
            .OrderBy(p => p.Y)
            .Select(p => p.Text.Trim())
            .FirstOrDefault(t => !string.IsNullOrWhiteSpace(t) && t.Length > 3);
    }

    private decimal? ExtractTotal(string text)
    {
        var match = Regex.Match(text,
            @"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
            RegexOptions.IgnoreCase);
        return match.Success
            ? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
            : (decimal?)null;
    }
}

public class DocumentResult
{
    public string FilePath   { get; set; }
    public string Vendor     { get; set; }
    public decimal? Total    { get; set; }
    public double Confidence { get; set; }
    public DateTime ProcessedAt { get; set; }
}
C#

Al eliminar la capa de webhooks, se suprime el punto final HTTPS, el requisito de rotación de secretos de webhooks, la cola de resultados, la lógica de validación HMAC y la configuración de reintentos. Toda la infraestructura de procesamiento posterior existe únicamente porque los resultados de Muy fi llegan de forma asíncrona desde un servidor remoto. Con IronOCR, Parallel.ForEach reemplaza todo eso. El ejemplo de multihilos demuestra el patrón IronTesseract por hilo en detalle, y la guía OCR asincrónica cubre la integración Task.Run para la capacidad de respuesta de la UI. La guía de optimización de la velocidad abarca la configuración de instancias para obtener el máximo rendimiento en cargas de trabajo por lotes.

Referencia de mapeo de la API de Muy fi a IronOCR

Muy fiEquivalente a IronOCR
new VeryfiClient(clientId, clientSecret, username, apiKey)new IronTesseract() + IronOcr.License.LicenseKey = "key"
_client.ProcessDocumentAsync(bytes)ocr.Read(filePath) o ocr.Read(ocrInput)
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" })input.LoadPdf(ruta); ocr.Leer(entrada)
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" })input.LoadPdf(ruta); ocr.Leer(entrada)
response.Vendor?.NamePrimer párrafo ordenado por p.Y desde result.Pages[0].Paragraphs
response.TotalRegex.Match(result.Text, @"Total:?\s*\$?([\d,]+\.\d{2})")
response.TaxRegex.Match(result.Text, @"Tax:?\s*\$?([\d,]+\.\d{2})")
response.DateRegex.Match(result.Text, @"\d{1,2}/\d{1,2}/\d{4}")
response.LineItemsresult.Pages[0].Paragraphs filtrado por rango de coordenadas Y
response.InvoiceNumberRegex.Match(result.Text, @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)")
response.BankAccount?.AccountNumberRegex.Match(result.Text, @"Account\s*#?\s*:?\s*(\d{4,})")
response.BankAccount?.RoutingNumberRegex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})")
response.ConfidenceScoreresult.Confidence (en general) o word.Confidence (por palabra)
response.Payment?.Last4Regex.Match(result.Text, @"\*{4}\s*(\d{4})")
VeryfiApiException (401/402/429/500)Excepciones de .NET Standard: sin códigos de error HTTP para el procesamiento local
Codificación Base64 antes de la cargaNo es necesario — ocr.Read(filePath) acepta rutas de archivo directamente
response.CategoryEmparejamiento de palabras clave personalizadas contra result.Text
Deserialización de la carga útil de WebhookNo es necesario — ocr.Read() devuelve el resultado de manera sincrónica
ProcessDocumentAsync con reintento/retrocesoNo es obligatorio: sin límites de frecuencia en el procesamiento local

Problemas comunes de migración y soluciones

Problema 1: Campos preanalizados que faltan

Veryfi: response.Vendor?.Name, response.Total, y response.LineItems llegan como campos estructurados de un modelo de ML previamente entrenado. No se requiere ninguna lógica de extracción en el lado del cliente.

Solución: Escribe patrones Regex para cada campo que utilice tu aplicación. El tiempo de migración suele ser de entre 8 y 24 horas, dependiendo del número de diseños de documento distintos que se procesen. Para los patrones comunes de recibos y facturas, el tutorial de OCR de facturas y el tutorial de escaneo de recibos proporcionan implementaciones completas de los patrones de extracción.

// Map each Muy fi field to a Regex extraction
private static readonly Dictionary<string, string> FieldPatterns = new()
{
    ["InvoiceNumber"] = @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
    ["PurchaseOrder"]  = @"(?:PO|P\.O\.|Purchase Order)\s*#?\s*:?\s*(\w+)",
    ["DueDate"]        = @"Due\s*(?:Date)?:?\s*(\d{1,2}/\d{1,2}/\d{4})",
    ["PaymentTerms"]   = @"(?:Terms|Net)\s*:?\s*(\w+\s*\d+)"
};

public string ExtractField(string text, string fieldName)
{
    if (!FieldPatterns.TryGetValue(fieldName, out var pattern))
        return null;
    var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
    return match.Success ? match.Groups[1].Value.Trim() : null;
}
C#

Problema 2: Firmas de métodos asíncronos en todo el código base

Veryfi: ProcessDocumentAsync es asincrónico a nivel del SDK de Veryfi. Los equipos típicamente propagan await a través de cada método de llamada hacia arriba en la pila de llamadas, lo que significa que las clases de servicio, los controladores y los trabajos en segundo plano todos llevan firmas async Task<t>.

Solución: El Read() de IronOCR es sincrónico. Las firmas de métodos existentes async se pueden preservar envolviendo con Task.Run durante el período de transición. Esto evita cambios masivos de firmas en todo el código, al tiempo que elimina la dependencia de la nube.

// Preserve async signature during transition — no codebase-wide refactor needed
public async Task<string> GetVendorNameAsync(string documentPath)
{
    return await Task.Run(() =>
    {
        var result = _ocr.Read(documentPath);
        return result.Pages[0].Paragraphs
            .OrderBy(p => p.Y)
            .Select(p => p.Text.Trim())
            .FirstOrDefault(t => t.Length > 3);
    });
}
C#

Problema 3: Configuración de credenciales dispersa por los entornos

Veryfi: Cuatro credenciales (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey) aparecen en appsettings.json, bloques de variables de entorno en archivos de Docker Compose, secretos de GitHub Actions, referencias de Azure Key Vault y configuraciones de tuberías de CI/CD.

Solución: Buscar y eliminar las cuatro entradas de credenciales de todos los entornos. Agregue una sola variable de entorno IRONOCR_LICENSE_KEY. Cárgala al iniciar el sistema.

# Find all Muy fi credential references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
    --include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
SHELL
// Load from environment at startup
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
    ?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
C#

Problema 4: Problemas de calidad de escaneo no visibles anteriormente

Veryfi: El procesamiento en la nube incluye la mejora de imágenes del lado del servidor antes de que se ejecute la inferencia de ML. Los escaneos de recibos de baja calidad —papel arrugado, impresión térmica descolorida, fotos de móvil torcidas— se corrigieron de forma automática antes de la extracción de campos.

Solución: Aplicar explícitamente el proceso de preprocesamiento de IronOCR. Deskew(), DeNoise(), y Contrast() cubren la mayoría de los problemas de calidad de escaneo de recibos en el mundo real.

using var input = new OcrInput();
input.LoadImage("receipt-phone-photo.jpg");
input.Deskew();        // correct rotation from angled phone capture
input.DeNoise();       // remove compression artifacts
input.Contrast();      // improve faded thermal print
input.Sharpen();       // recover edge detail

var result = _ocr.Read(input);
C#

La guía de corrección de la calidad de la imagen y el tutorial sobre filtros de imagen abordan qué filtros aplicar para patrones específicos de degradación de la digitalización.

Tema 5: Rendimiento del procesamiento por lotes de gran volumen

Veryfi: Los límites de velocidad restringen la velocidad de envío de documentos. Las respuestas HTTP 429 requieren una lógica de retroceso exponencial. El rendimiento está limitado por el límite de velocidad por plan de Veryfi, no por tu hardware.

**Solución:**IronOCR solo está limitado por los núcleos de la CPU. Use Parallel.ForEach con una instancia IronTesseract por hilo. En un servidor de 8 núcleos, el rendimiento escala de forma aproximadamente lineal con el número de núcleos.

// One IronTesseract per thread — do not share instances across threads
Parallel.ForEach(
    documentPaths,
    new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
    path =>
    {
        var ocr    = new IronTesseract();
        var result = ocr.Read(path);
        SaveResult(path, result.Text, result.Confidence);
    });
C#

Problema 6: Esquema JSON propietario vinculado a Veryfi

Veryfi: Todo el código de extracción lee del esquema de respuesta de Veryfi: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. Este código solo funciona con el SDK de Veryfi. Cualquier cambio en el nombre de un campo en una actualización de la API de Muy fi provoca errores en el código de la aplicación.

Solución: La extracción de IronOCR utiliza System.Text.RegularExpressions.Regex estándar de .NET contra texto plano. Los patrones son portátiles, se pueden probar sin necesidad de simular ningún SDK y están bajo tu control. Las pruebas unitarias se ejecutan sin conexión a la red.

// Extraction logic that is fully portable and unit-testable
[Fact]
public void ExtractsRoutingNumberFromInvoiceText()
{
    const string sampleText = "Routing Number: 021000021\nAccount: 1234567890";
    var match = Regex.Match(sampleText, @"Routing\s*(?:Number)?:?\s*(\d{9})",
                            RegexOptions.IgnoreCase);
    Assert.True(match.Success);
    Assert.Equal("021000021", match.Groups[1].Value);
}
C#

Lista de verificación de migración de Veryfi

Pre-Migración

Revisa el código para hacer un inventario de todos los usos de Muy fi antes de tocar ningún código:

# Find all Muy fi using statements
grep -rn "using Veryfi" --include="*.cs" .

# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .

# Find all Muy fi response field accesses
grep -rn "response\.Vendor\|response\.Total\|response\.LineItems\|response\.BankAccount" --include="*.cs" .

# Find all credential configuration references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
    --include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .

# Find all webhook-related code
grep -rn "VeryfiWebhook\|X-Veryfi-Token\|webhook" --include="*.cs" .
SHELL

Registre el conteo total de los sitios de llamada ProcessDocumentAsync, la lista de campos de respuesta accesados por sitio de llamada, y la lista de entornos que contienen credenciales Veryfi.

Migración de código

  1. Elimine el paquete NuGet Veryfi de todos los proyectos en la solución.
  2. Instale el paquete NuGet IronOcr en todos los proyectos que anteriormente referenciaban Veryfi.
  3. Agregue IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; al inicio de la aplicación (antes de cualquier llamada de OCR).
  4. Reemplace todas las declaraciones using Veryfi; y using Veryfi.Models; con using IronOcr;.
  5. Reemplace la inyección de constructor VeryfiClient con la inicialización de campo IronTesseract.
  6. Elimine las cuatro entradas de credenciales Muy fi de cada archivo de configuración de appsettings.json, appsettings.*.json, y secretos.
  7. Convierta llamadas ProcessDocumentAsync(bytes) a ocr.Read(filePath) o ocr.Read(ocrInput).
  8. Reemplace los accesos response.Vendor?.Name con extracción de texto ordenada por párrafo desde result.Pages[0].Paragraphs.
  9. Reemplace response.Total, response.Tax, response.InvoiceNumber, y otros accesos a campos estructurados con patrones Regex contra result.Text.
  10. Reemplace la iteración response.LineItems con iteración result.Pages[0].Paragraphs filtrada por coordenada Y.
  11. Eliminar las clases del controlador de webhooks y eliminar los registros de puntos finales de webhooks.
  12. Eliminar las variables de entorno secretas de webhook de todos los entornos.
  13. Agregue OcrInput con preprocesamiento (Deskew(), DeNoise(), Contrast()) para entradas de imagen escaneada.
  14. Reemplace los bucles secuenciales de un solo hilo con Parallel.ForEach usando una IronTesseract por hilo.
  15. Agregue IRONOCR_LICENSE_KEY a todas las configuraciones de variables de entorno y almacenes de secretos de CI/CD.

Posmigración

  • Comprueba que no aparezcan llamadas a la red Muy fi en los registros de tráfico HTTP tras la implementación de la migración.
  • Confirme que los nombres de los proveedores extraídos coinciden con los valores esperados en una muestra de entre 20 y 50 recibos.
  • Confirme que los totales extraídos coinciden con los valores esperados con una tolerancia de 0,01 $ para el mismo conjunto de muestras.
  • Verifica que la extracción del número de factura se realice correctamente para cada formato de factura del corpus de documentos.
  • Comprueba el rendimiento del procesamiento por lotes con respecto al rendimiento de referencia de Muy fi para confirmar la eliminación del límite de velocidad.
  • Ejecute la Suite completa de pruebas sin conexión a la red para confirmar la ausencia total de dependencia de la nube.
  • Confirme que las puntuaciones result.Confidence exceden el 80% para escaneos de documentos limpios; Un valor inferior al 80 % indica que se debe añadir un paso de preprocesamiento.
  • Comprueba que se han eliminado las cuatro credenciales de Muy fi de todos los entornos (desarrollo, staging, producción).
  • Confirma que los puntos finales de webhook devuelven un 404 o han sido eliminados de la tabla de enrutamiento.
  • Comprueba el comportamiento con escaneos de recibos de baja calidad (arrugados, descoloridos, torcidos) con el proceso de preprocesamiento activo.

Principales ventajas de migrar a IronOCR

Los documentos financieros procesados localmente son documentos que no pueden ser interceptados por terceros. Tras la migración, los números de cuenta bancaria extraídos de las facturas, los números de ruta analizados de los cheques y los historiales de transacciones leídos de los extractos bancarios se procesan en su propio hardware. Ningún incidente de seguridad de terceros, acceso a datos por parte de subcontratistas o violación de la infraestructura de Muy fi puede exponer documentos que nunca han salido de sus servidores.

Los costes por documento se reducen a cero el día en que se implementa la migración. Con 50 000 documentos al mes, desaparece la partida mensual de Muy fi de entre 5000 y 15 000 dólares. The Professional License of IronOCR, with a price of 2999 $, is amortized in the first week of the first month. A partir de volúmenes más elevados, el ahorro se acumula cada año sin necesidad de negociar descuentos por volumen ni renovar el contrato.

El rendimiento del procesamiento se adapta al hardware, no a los límites de velocidad de los proveedores. Las respuestas HTTP 429, los límites de rendimiento a nivel de plan y los recargos por exceso de uso estacional son características propias de la arquitectura de las API en la nube. Con IronOCR, al añadir núcleos de CPU, el rendimiento aumenta proporcionalmente. Un lote de 10 000 recibos se procesa según tu calendario, no según el programa de límites de velocidad de Veryfi.

Cualquier tipo de documento se procesa con la misma API. La organización ya no necesita una segunda herramienta de OCR cuando RR. HH. solicita el procesamiento de formularios de incorporación, el departamento jurídico necesita extraer el texto de los contratos o el departamento de operaciones necesita datos de documentos de envío. ocr.Read() maneja todos ellos. El tutorial sobre lectura de texto a partir de imágenes y las guías de documentos especializados abarcan toda la gama de formatos de documentos que IronOCR maneja.

La lógica de extracción se convierte en una parte fundamental del código base. Los patrones Regex se encuentran en el control de código fuente, se pueden revisar en pull requests, se pueden probar en pruebas unitarias sin necesidad de simular ningún SDK y se pueden ajustar en función de los comentarios de producción. Cuando el modelo preentrenado de Muy fi devuelve un nombre de proveedor incorrecto, no hay nada que ajustar. Cuando el patrón de extracción de IronOCR devuelve un nombre de proveedor incorrecto, la solución consiste en un cambio de una sola línea en la expresión regular, acompañado de una prueba unitaria. La página de licencias de IronOCR describe las opciones de planes, incluida la suscripción SaaS para equipos que prefieren la facturación anual en lugar de la compra perpetua.

**El espacio de implementación se reduce a un único paquete NuGet que se ejecuta en cualquier entorno.**IronOCR se instala como un único paquete sin dependencias externas, sin gestión de binarios nativos y sin configuración de la carpeta tessdata. La misma referencia de paquete se resuelve en Windows, Linux, macOS, Docker, Azure App Service y AWS Lambda sin código condicional de plataforma. Consulte la guía de implementación de Docker y la guía de implementación de Linux para entornos en contenedores en los que los requisitos de salida de red de Muy fi supongan un obstáculo para la implementación.

Por favor nota: Tesseract y Muy fi son marcas registradas de sus respectivos propietarios. Este sitio no está afiliado, respaldado ni patrocinado por Google o Veryfi. Todos los nombres de producto, logotipos y marcas son propiedad de sus respectivos dueños. Las comparaciones son solo para fines informativos y reflejan información públicamente disponible en el momento de la redacción.

Artículos Relacionados

Key in blue circle

Obtenga su clave de prueba gratuita de 30 días al instante.

Your trial license will be sent to your email address

Sin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.

bullet_checkedNo se requiere tarjeta de crédito ni creación de cuentaSin limitaciones. 100 % desbloqueado. Sin tarjeta de crédito.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Obtén tu Consulta Sin Compromiso
Completa el formulario a continuación o envía un correo a sales@ironsoftware.com
Tus detalles siempre serán mantenidos confidenciales.
Confiado por millones de ingenieros en todo el mundo
Logos de clientes de Iron Software
Obtenga su Clave de Prueba de 30 días gratis al instante.
No se requiere tarjeta de crédito ni creación de cuenta