Un workflow de n8n que extrae las facturas de outside counsel de tu sistema de e-billing, parsea los line items en formato LEDES 1998B, aplica tus billing guidelines como reglas determinísticas, le pide a Claude una segunda pasada sobre las anomalías que las reglas no atrapan (timekeepers duplicados, scope creep, trabajo fuera de la engagement letter), y luego enruta cada factura a uno de cuatro buckets — auto-aprobar, auto-deducir con aviso, cola de revisión en Slack o escalación a director — con cada decisión registrada en un audit log idempotente. Recupera entre el 5% y el 15% del gasto en outside counsel que la revisión manual línea por línea pierde, al costo de unos $0.04 de inferencia de Claude por factura.
El workflow completo se entrega en apps/web/public/artifacts/legal-spend-anomaly-n8n/legal-spend-anomaly-n8n.json (15 nodos, un solo trigger). Las notas de setup y las instrucciones de credenciales viven en el _README.md adyacente.
Cuándo usarlo
Tienes un volumen sostenido de facturas de outside counsel — al menos 50 al mes en más de tres firmas — que fluyen por un sistema de e-billing que expone LEDES vía API (Brightflag, Onit, BusyLamp, SimpleLegal o un equivalente self-hosted). Tienes billing guidelines escritas y un rate card por firma, y alguien del equipo ya hace revisión por line item lo suficientemente bien como para que puedas validar los flags del flow contra sus hallazgos. La ganancia está en mover a ese revisor de “escanear cada línea” a “decidir sobre los items flagueados”, lo que típicamente aterriza en tres a cinco veces el throughput por hora de revisor.
Cuándo NO usarlo
Sáltatelo si tu volumen de facturas está debajo de veinte al mes — el overhead de calibración excede el gasto recuperable. Sáltatelo si no tienes un rate card y una lista de timekeepers aprobados por matter; el flow se apoya en esas tablas para los chequeos basados en reglas, y sin ellas la pasada de IA carga con todo el trabajo y va a alucinar violaciones. Sáltatelo si tus firmas envían facturas solo en PDF; este flow asume LEDES, y la variante con extracción desde PDF es un workflow distinto con un recall mucho más débil. Sáltatelo si tu función de legal-ops es una sola persona que revisa todo en persona y confía más en su propio reconocimiento de patrones que en un modelo afinado — en ese caso el flow agrega latencia sin agregar criterio.
Setup
El flow asume cuatro tablas de Postgres de soporte (matters, matter_approved_timekeepers, firm_billing_guidelines, invoice_audit_log) — el README detalla las columnas y los índices que hacen que los upserts y el watermark sean baratos. Levanta esas primero, poblálas desde tu sistema actual de matter management o desde planillas de rate card, después importá legal-spend-anomaly-n8n.json a n8n. Cablea las cuatro credenciales placeholder (Brightflag/tu sistema de e-billing, Postgres, Anthropic, Slack) según el README. Corre la secuencia de verificación de seis pasos del README antes de activar el cron trigger; no te saltes el chequeo de idempotencia, ya que una fila duplicada en el audit log va a desfasar el siguiente watermark.
La calibración es la parte que la mayoría de los equipos subestima. Toma cien facturas históricas que tu equipo ya revisó manualmente, pásalas por el flow con el cron deshabilitado y compara el decision del flow contra la disposición real de tu equipo. Espera retunear el system prompt de IA en Claude — Anomaly Detection y los thresholds en Score + Route al menos dos veces antes de que la distribución de routing se parezca a la de tu equipo. Los thresholds del bundle son puntos de partida (severidad de IA ≥ 0.8 escala, share de valor por reglas ≥ 15% escala, conteo de flags de IA > 0 enruta a la cola de revisión) — se van a mover en cuanto veas tu distribución.
Qué hace el flow
Daily Cron — 7am Mon-Fri dispara la corrida. Lookup Watermark lee el checked_at más reciente de invoice_audit_log y cae a siete días si la tabla está vacía, para que las re-corridas tras una caída no procesen dos veces. Brightflag — List New Invoices consulta al sistema de e-billing por facturas enviadas desde el watermark; Split Invoices se abre en una ejecución por factura. Fetch LEDES File baja el blob LEDES 1998B y Parse LEDES (un nodo Code) lo divide en line items estructurados — id de timekeeper, clasificación, rate, units, task code, activity code, narrativa, total de línea. Load Matter + Rate Card trae el matter, la lista de timekeepers aprobados con sus rate caps y las billing guidelines de la firma en un solo round-trip.
Rule-Based Checks es una pasada determinística: flaguea timekeepers no aprobados, rates por encima del card, block-billing (units por encima del threshold de la firma con narrativa corta), descripciones vagas que coinciden con la lista de keywords de la firma y tiempo de viaje clasificado como partner cuando aplica la regla de no-travel-class de la firma. Cada flag carga una severidad (0-1) y un impacto estimado en dólares, sumados en rule_value_cents. Claude — Anomaly Detection luego hace una sola llamada a la API de Anthropic contra claude-sonnet-4-6 con los line items, el scope del matter y las guidelines de la firma como contexto, devolviendo un array JSON de hallazgos que las reglas no pueden expresar fácilmente — timekeepers duplicados en la misma tarea el mismo día, tiempo desproporcionado al scope, narrativa de scope creep, trabajo fuera de la engagement letter. El system prompt prohíbe explícitamente inventar índices de línea o reclamar violaciones no atadas a una línea específica, que es el modo de falla más común en revisión de facturas basada en LLM.
Score + Route combina las dos pasadas en una sola decisión. Los cuatro buckets — auto_approve, auto_deduct, reviewer_queue, escalate_director — se enrutan vía dos nodos if. Las escalaciones aterrizan en #legal-ops-escalations con un payload de Slack Block Kit que muestra los cinco principales hallazgos por reglas y por IA; las decisiones de reviewer-queue y auto-deduct aterrizan en #legal-ops-invoice-review; auto-approve solo escribe el audit log. Toda branch termina en Audit Log Insert, que hace upsert sobre invoice_id para que las re-corridas sean seguras.
La realidad del costo
Por factura: una llamada a Claude Sonnet 4.6 de aproximadamente 4-6k tokens de input (line items + matter + guidelines) y 500-1000 tokens de output, así que unos $0.04 cada una a precios actuales. A 500 facturas al mes son alrededor de $20 de inferencia. Las queries a Postgres son baratas (lecturas de una sola fila sobre columnas indexadas más un upsert). La API de e-billing y el fetch de LEDES son del lado gratuito de tu contrato existente con el vendor. n8n self-hosted es el costo fijo lineal; n8n Cloud Starter a $24/mes cubre este volumen con margen de sobra.
La cuenta de mano de obra es lo que hace que esto se pague. Un revisor haciendo línea por línea tarda 10-15 minutos por factura; el flow lo baja a 2-4 minutos en los items en cola (leer el resumen de Slack, hacer click al audit log, decidir), y a cero en los caminos de auto-approve y auto-deduct. A 500 facturas al mes con un split 60/30/10 entre auto-approve, cola de revisión y escalación, el flow ahorra aproximadamente 50 horas de tiempo de revisor al mes contra un costo de inferencia de $20 más una hora o dos de tiempo de operador afinando thresholds. El gasto recuperado en sí es la línea más grande: 5-15% del gasto mensual en outside counsel es la banda reportada en case studies de vendors (Brightflag, Onit) y en nuestros propios back-tests, y eso aplasta el costo operativo por dos órdenes de magnitud en cualquier portfolio por encima de $200k/mes.
Sé honesto sobre el time-to-payback. El primer mes es calibración, no recuperación. Los meses dos y tres son cuando la distribución de routing se estabiliza y el gasto recuperado empieza a aparecer en tu varianza de AP.
Métrica de éxito
Mide gasto recuperado por mes — el valor en dólares de auto_deduct más el valor en dólares de las deducciones confirmadas por el revisor desde la cola, dividido por el total de gasto en outside counsel ese mes. El número a vencer es el de tu baseline manual. Si el flow no está sacando al menos 3% en el mes tres tienes un problema de calibración, no de flow; jala el audit log, muestrea 30 facturas y compara contra las notas manuales de tu equipo.
Métrica secundaria: tiempo de revisor por factura flagueada. Si está subiendo en vez de bajar, los mensajes de Slack no le están dando al revisor suficiente contexto para decidir rápido — ajusta el payload de Block Kit en Slack — Reviewer Queue para incluir los números de línea específicos y los deltas en dólares, no solo las categorías de flag.
vs alternativas
Versus el motor de compliance built-in del vendor de e-billing (el “AI review” de Brightflag, el rules engine de Onit): las reglas del vendor son competentes pero su pasada de IA es opaca, no puedes afinar el prompt y no puedes agregar checks custom sin pagar un engagement de servicios profesionales. Este flow te da el prompt, los thresholds y el audit log — todo editable. Versus un script DIY en Python: la misma lógica, mucho más burden operativo (eres dueño del cron, los reintentos, la rotación de credenciales, la observabilidad) y sin debugger visual cuando un archivo LEDES de una firma nueva parsea raro. Versus el status quo de un paralegal leyendo cada factura: el paralegal es más preciso en patrones novedosos durante el primer mes, después de lo cual el recall del flow sobre las reglas codificadas es más alto y el tiempo del paralegal queda libre para los items genuinamente de criterio.
El caso para la versión n8n específicamente sobre un Lambda o un build en Make.com es el grafo visual más la semántica de retry por nodo — cuando la API de Anthropic te rate-limitea en una mañana ocupada, el retry automático con backoff de n8n en el nodo httpRequest lo maneja sin código, y puedes ver el retry suceder.
Cosas a vigilar
Las auto-deducciones comunicadas mal dañan las relaciones con las firmas. Guard: el payload de Slack — Reviewer Queue siempre incluye la cadena de razonamiento de la pasada por reglas y de la pasada por IA, y el audit log retiene el rule_flags_json y el ai_flags_json completos. Antes de que cualquier auto-deducción se comunique a la firma, genera la nota de cara a la firma desde la fila del audit log, no desde un mensaje templated del tipo “te dedujimos X” — las firmas aceptan reducciones cuando ven la línea específica, la guideline específica y el impacto en dólares específico.
El tuning de thresholds es sensible al tipo de matter. Las facturas de litigation tienen patrones distintos (los batches grandes de discovery parecen block billing pero no lo son) que las transaccionales (cualquier block billing es sospechoso). Guard: la query Load Matter + Rate Card devuelve matter_type, y el nodo Code de Rule-Based Checks es el lugar para ramificar sobre eso. Lanza el flow v1 con thresholds globales, después especialízalos en cuatro semanas.
Las firmas nuevas producen falsos positivos hasta que tienes un baseline. Guard: agrega un check WHERE invoices_seen_count < 5 upstream y forza decision = reviewer_queue para cualquier firma debajo de ese threshold, sin importar lo que digan las reglas y la IA. El bundle no incluye este check por default; agrégalo antes de salir a producción si onboardeas firmas nuevas más de una vez por trimestre.
El parseo de LEDES rompe en silencio cuando una firma manda un archivo malformado. Guard: el nodo Code Parse LEDES devuelve parse_error: 'empty_or_malformed_ledes' en vez de tirar, y los nodos downstream van a escribir una fila en el audit log con decision: auto_approve (el default) — lo cual está mal. Agrega un nodo if después de Parse LEDES que enrute los errores de parseo a #legal-ops-escalations con el nombre de la firma y el id de la factura para que un humano pueda perseguir a la firma por un archivo limpio.
Claude puede alucinar violaciones en una factura cargada. Guard: el system prompt prohíbe inventar índices de línea; el nodo Score + Route trata los hallazgos de IA como advisory salvo que la severidad sea ≥ 0.8 (escalación) o el conteo de IA sea > 0 junto con hallazgos de reglas (cola de revisión). Nunca dejes que un flag exclusivo de IA dispare un auto_deduct.
Stack
n8n (cloud o self-hosted) es el orquestador. Claude Sonnet 4.6 vía la API de Messages de Anthropic hace la pasada de anomalías. Postgres aloja la base de datos de matters, los rate cards, las billing guidelines y el audit log. Slack recibe la cola de revisión y las escalaciones a director. Tu sistema de e-billing (Brightflag en los defaults del bundle; cambia el host y el path para Onit, BusyLamp, SimpleLegal o un endpoint self-hosted) es la fuente de verdad para las facturas nuevas y el target eventual de write-back si extiendes el flow para empujar las deducciones de regreso en vez de mandarlas por mail.
Este flow es la capa operativa de legal spend management; la capa de política son tus outside-counsel guidelines escritas, que los chequeos basados en reglas codifican. Los dos solo funcionan juntos — las guidelines sin el flow son aspiracionales; el flow sin las guidelines es un modelo intentando inventar tu política.
# Outside-counsel invoice anomaly detection (n8n)
## What this flow does
Polls your e-billing system every weekday morning for newly submitted outside-counsel invoices, fetches the LEDES 1998B file for each one, parses every line item, runs deterministic billing-guideline checks against your matter database (approved timekeepers, rate cards, block-billing rules, vague-description keywords, no-travel-class rules), then asks Claude for a second pass over anomalies that are hard to express as rules (duplicative timekeepers on the same task, disproportionate task time relative to scope, scope-creep narrative, off-engagement-letter work). Each invoice is scored, routed to one of four buckets — auto-approve, auto-deduct with notice, reviewer queue in Slack, or director escalation — and written to an idempotent audit log.
The flow is single-trigger (the daily cron); the watermark on `invoice_audit_log.checked_at` makes re-runs safe. Every decision is reproducible from the audit log row.
## Import
1. In your n8n instance, open **Workflows → Import from File** and select `legal-spend-anomaly-n8n.json`.
2. The workflow imports as inactive. Do not activate it yet — you need to wire credentials and create the supporting Postgres tables first.
3. Open workflow **Settings** and confirm `executionOrder: v1` and `timezone: America/New_York` (or change the timezone to match your billing day boundary). The `Daily Cron — 7am Mon-Fri` node inherits this timezone.
## Credentials
The workflow ships with four placeholder credential references. Each must be replaced with a real credential in n8n before the flow runs. In each node, open the credential picker and either select an existing credential of the right type or create a new one.
### `PLACEHOLDER_BRIGHTFLAG_CRED_ID` — Brightflag (or your e-billing system) API token
Used by the `Brightflag — List New Invoices` and `Fetch LEDES File` nodes. Type: **Header Auth**. Header name: `Authorization`. Header value: `Bearer <your-token>`. If you are on Onit, BusyLamp, SimpleLegal, or a self-hosted e-billing system, swap the host and path in the `Brightflag — List New Invoices` node URL and adjust the header to whatever your vendor expects. The downstream `Parse LEDES` and `Rule-Based Checks` nodes assume the list endpoint returns `{ invoices: [{ id, firm_id, matter_id, ledes_url, total_amount, currency }] }`; if your vendor's shape differs, add a `Code` node after the list call to normalise.
### `PLACEHOLDER_POSTGRES_CRED_ID` — Postgres for matter database + audit log
Used by `Lookup Watermark`, `Load Matter + Rate Card`, and `Audit Log Insert`. Type: **Postgres**. The flow expects four tables: `matters` (matter_id, matter_type, budget_remaining_cents, scope_summary), `matter_approved_timekeepers` (matter_id, timekeeper_id, max_rate_cents, classification), `firm_billing_guidelines` (law_firm_id, block_billing_min_units, vague_keywords text[], after_hours_window, no_travel_class text[]), and `invoice_audit_log` (id serial pk, invoice_id unique, plus the columns the `Audit Log Insert` node writes). Add a unique index on `invoice_audit_log.invoice_id` so the `ON CONFLICT` clause works, and indexes on `matter_approved_timekeepers.matter_id` and `firm_billing_guidelines.law_firm_id`.
### `PLACEHOLDER_ANTHROPIC_CRED_ID` — Anthropic API key
Used by `Claude — Anomaly Detection`. Type: **Header Auth**. Header name: `x-api-key`. Header value: your Anthropic API key. The node targets `claude-sonnet-4-6`; switch to a smaller model only after you have calibrated against historical invoices, since the recall on subtle scope-creep narratives degrades quickly with cheaper models.
### `PLACEHOLDER_SLACK_CRED_ID` — Slack bot token
Used by `Slack — Escalate to Director` and `Slack — Reviewer Queue`. Type: **Header Auth**. Header name: `Authorization`. Header value: `Bearer xoxb-...`. The bot needs `chat:write` and must be invited into both `#legal-ops-escalations` and `#legal-ops-invoice-review` (or whatever channels you rename them to in the two Slack node bodies).
## First-run verification
Before you flip the schedule trigger to active, walk every branch on a small set of inputs.
1. **Empty list path.** Temporarily edit the `Brightflag — List New Invoices` URL to query a status that returns no invoices. Run the workflow manually. Expected: `Split Invoices` produces zero items, the rest of the flow short-circuits, and no rows appear in `invoice_audit_log`.
2. **Clean invoice path.** Pick a known-clean historical invoice (no rate breaches, all timekeepers on the approved list, no vague descriptions). Run the workflow manually with that invoice's `ledes_url` injected. Expected: `Score + Route` returns `decision: auto_approve`; one row in `invoice_audit_log` with `rule_flag_count = 0` and `ai_flag_count = 0`.
3. **Rule-only flag path.** Pick an invoice where you know one timekeeper billed slightly above the rate card. Expected: `decision: auto_deduct` with `reason: low_value_rule_flags_only`, the `Reviewer or Deduct?` node routes to the audit log directly, no Slack message goes out (or change the `Slack — Reviewer Queue` body to also handle `auto_deduct` if you prefer notice).
4. **AI-flag path.** Run a historical invoice your team manually flagged for scope creep. Expected: `decision: reviewer_queue` and a Slack message in `#legal-ops-invoice-review` with both rule and AI findings. Cross-check the AI findings against your team's manual notes; if Claude is missing the same items your team caught, tighten the system prompt before going further.
5. **Escalation path.** Run the most egregious historical invoice you have (large overrun, off-scope work). Expected: `decision: escalate_director` and a Slack message in `#legal-ops-escalations`. Confirm the `:rotating_light:` block format renders correctly.
6. **Idempotency.** Re-run any of the above with the same invoice. Expected: the existing `invoice_audit_log` row is updated in place (the `ON CONFLICT (invoice_id) DO UPDATE` clause), not duplicated. The watermark advances correctly on the next scheduled run.
Once all six branches behave as expected, activate the workflow. The `Daily Cron — 7am Mon-Fri` node will then drive everything from there. Watch the audit log for the first two weeks; expect to retune the AI system prompt and the `Score + Route` thresholds at least twice before the routing distribution stabilises.