VerifikaDocs
Guías

Gastos con IA

Manda la foto o el PDF de una factura y recibe el gasto listo para registrar — proveedor, NIT, número de factura, IVA y categoría — con el aviso de si ya estaba registrado.

Es el «Registrar gasto con IA» del panel, por API: tu sistema manda la factura (foto o PDF) y Verifika la lee y devuelve un borrador del gasto —proveedor, NIT, número de factura, fecha, total, subtotal, IVA, categoría sugerida y medio de pago— junto con los gastos parecidos que ya estén en el libro. Tú decides si lo creas.

Sirve para un bot que recibe facturas de proveedores por WhatsApp, para un correo que reenvía facturas electrónicas o para digitalizar la caja de recibos de la semana.

Antes de empezar

  • El plan incluye los egresos y la lectura de facturas con IA (features.expenses_module y features.ai_expense_scan en GET /v1/plan).
  • La llave tiene expenses.scan (leer facturas) y, para crear el gasto, expenses.write. Crear la llave.
  • Con una llave real. No tiene modo prueba (403 TEST_MODE_UNAVAILABLE con vk_test_), pero leer una factura no crea nada hasta que lo pidas.

1. Lee la factura

Igual que el extracto de la conciliación, el archivo va de una de tres formas: multipart con el campo file, fileBase64 + fileName, o fileUrl (https y pública). Foto (JPG, PNG, WebP, HEIC) o PDF, hasta 15 MB.

curl -X POST https://api.verifika.tech/v1/expense-scans \
  -H "Authorization: Bearer $VERIFIKA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@factura-fe-20931.pdf"
201 · el borrador
{
  "object": "expenseScan",
  "id": "cmuhb7c8d0061x8w1f2g3h4jk",
  "outcome": "EXTRACTED",
  "message": null,
  "documentKind": "INVOICE",
  "confidence": "HIGH",
  "draft": {
    "amount": 357000,
    "subtotal": 300000,
    "tax": 57000,
    "paidTo": "Harina La Espiga S.A.S.",
    "vendorTaxId": "900123456-7",
    "invoiceNumber": "FE-20931",
    "occurredAt": "2026-10-10T05:00:00.000Z",
    "categoryId": "cmt7xbfrm0003q3w121ldx6wz",
    "categoryName": "Proveedores y mercancía",
    "paymentMethod": "TRANSFER",
    "accountLabel": null,
    "notes": "20 bultos de harina"
  },
  "duplicates": [],
  "file": { "attachmentId": "cmuhb7c9e0062x8w1m4n5b6vc", "fileName": "factura-fe-20931.pdf", "contentType": "application/pdf", "size": 84210 },
  "expenseId": null,
  "expense": null,
  "expiresAt": "2026-10-18T21:20:00.000Z",
  "createdAt": "2026-10-12T21:20:00.000Z"
}
CampoQué es
outcomeEXTRACTED (se leyó), NOT_A_RECEIPT (no es una factura ni un recibo) o UNREADABLE (no se lee). En los dos últimos, message es la frase para la persona.
draftEl gasto que se leyó. Lo que no se pudo leer viene en null.
duplicatesGastos parecidos que ya están en el libro: strength (STRONG o PROBABLE) y reasons (SAME_FILE, SAME_INVOICE_NUMBER, SAME_AMOUNT, SAME_DAY, NEAR_DAY, SIMILAR_PAYEE). [] = nada parecido.
expiresAtHasta cuándo puedes crear el gasto con esta lectura: 6 días. Después, 410 EXPENSE_SCAN_EXPIRED.

2. Crea el gasto

Si el borrador está bien —y duplicates está vacío o es otro gasto—, créalo. En expense van tus correcciones o lo que la lectura no sacó (los mismos campos de POST /v1/expenses):

curl -X POST https://api.verifika.tech/v1/expense-scans/cmuhb7c8d0061x8w1f2g3h4jk/expense \
  -H "Authorization: Bearer $VERIFIKA_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "expense": { "paidTo": "Harina La Espiga", "notes": "Pedido semanal" } }'

Responde 201 con el gasto, que nace con source: "API" y la factura adjunta. Una lectura crea un gasto: si repites la petición, te devuelve el mismo con 200.

¿Quieres leer y crear en un solo paso? Manda create: true en la lectura (y expense con las correcciones, como texto JSON si vas por multipart). Si la lectura no sacó un dato obligatorio, responde 422 EXPENSE_SCAN_INCOMPLETE con details.missing: mándalo en expense. Así también se registra a mano un NOT_A_RECEIPT o un UNREADABLE, con su soporte adjunto.

Cuando parece repetido

Si al crear hay un gasto parecido, no crea nada y responde 409 EXPENSE_DUPLICATE con los parecidos en details.duplicates. Si de verdad es otro gasto —el proveedor te factura lo mismo cada semana—, vuelve a pedirlo con "allowDuplicate": true: es el «Registrar de todos modos» del panel.

409 · parece repetido
{
  "error": {
    "code": "EXPENSE_DUPLICATE",
    "message": "Parece que este gasto ya está registrado. Si de verdad es otro, vuelve a pedirlo con `allowDuplicate: true`.",
    "details": {
      "scanId": "cmuhb7c8d0061x8w1f2g3h4jk",
      "duplicates": [
        { "strength": "STRONG", "reasons": ["SAME_INVOICE_NUMBER", "SAME_AMOUNT"], "expense": { "object": "expense", "id": "cmtnox8lz00016kw11frj0rww", "…": "…" } }
      ]
    }
  }
}

La factura, dónde queda

Se guarda en nuestro almacenamiento privado después de leerla (si la IA falla, no queda un archivo suelto por cada reintento). Al crear el gasto, se mueve a la carpeta de ese gasto; si nunca lo creas, se borra sola a los 7 días.

Límites y errores

Cada lectura es una consulta a la IA, así que tiene su propio freno, por negocio: 20 lecturas por minuto y 300 al día (429 RATE_LIMITED). Para registrar gastos sin leerlos, usa POST /v1/expenses, que no tiene ese límite.

HTTPcodeQué pasó
409EXPENSE_DUPLICATEParece repetido: allowDuplicate: true si es otro.
409ATTACHMENT_ALREADY_LINKEDDos pedidos de crear a la vez: reintenta y recibes el gasto con 200.
409EXPENSE_SCAN_ALREADY_USEDEl gasto que se creó con esta lectura se borró, y con él su factura. Vuelve a leerla.
410EXPENSE_SCAN_EXPIREDLa lectura venció (6 días).
413FILE_TOO_LARGEMás de 15 MB.
415FILE_TYPE_NOT_ALLOWEDNo es foto ni PDF (se mira el archivo, no la extensión).
422EXPENSE_SCAN_INCOMPLETEFalta un dato para crear el gasto (details.missing).
503AI_UNAVAILABLELa lectura con IA no está disponible: registra el gasto con POST /v1/expenses.

La referencia de cada endpoint está en Egresos → Gastos con IA. Por MCP, son las herramientas scan_expense_receipt, get_expense_scan y create_expense_from_scan.

En esta página