Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.facture.ar/llms.txt

Use this file to discover all available pages before exploring further.

Facturación masiva en lotes

La facturación en lotes te permite emitir múltiples facturas electrónicas en una sola operación asincrónica. Es ideal para e-commerce, facturación mensual recurrente, sistemas ERP y cualquier caso donde necesitás procesar muchas facturas juntas.

Lotes desde el dashboard (CSV)

Si cargás comprobantes con archivo CSV desde la web (sin armar integración propia), el flujo, las columnas y el archivo de ejemplo están detallados en Facturación por lotes desde la app. Incluye la columna opcional cbte_fch, correlatividad de fechas dentro del lote y contra ARCA.

Fecha del comprobante (cbteFch) en la API

En cada ítem que envíes al batch (mismo cuerpo que una factura suelta en /api/invoices), podés incluir el campo opcional cbteFch en formato YYYYMMDD. Si no lo enviás, Facturear usa la fecha actual al ejecutar el trabajo contra ARCA. Reglas que aplican igual que en ARCA:
  • Por CUIT + punto de venta + tipo de comprobante, la fecha del nuevo comprobante no puede ser menor que la del último comprobante autorizado en ese circuito.
  • Orden dentro del lote: para el mismo circuito, las fechas efectivas deben ser no decrecientes en el orden en que se procesan los ítems.
Para facturación retroactiva (por ejemplo cerrar un mes anterior), solo es coherente si no emitiste después con fechas más nuevas en ese mismo punto de venta y tipo.

¿Cuándo usar lotes?

Caso de usoSin lotesCon lotes
Emitir 500 facturas fin de mes500 requests individuales1 batch con 500 items
E-commerce con picos de ventasPosibles timeoutsProcesamiento asincrónico
Facturación recurrente SaaSScript secuencial lentoProcesamiento paralelo
Migración de facturas históricasInviableIdeal
Los lotes procesan las facturas de forma asincrónica. Enviás el lote, Facturear lo procesa con ARCA y podés consultar el estado cuando quieras. No necesitás esperar a que termine para continuar con otras operaciones.

Flujo de trabajo con lotes

1
Crear el lote: POST /invoices/batches — inicializa un lote vacío
2
Agregar facturas: PATCH /invoices/batches/ — agregá facturas al lote
3
Procesar: el lote se procesa automáticamente (o podés forzar el procesamiento)
4
Consultar estado: GET /invoices/batches/ — verificá el progreso
5
Manejar errores: reintentá los ítems fallidos con POST /invoices/batches//items//retry

Crear un lote

POST /invoices/batches
const response = await fetch('https://api.facture.ar/invoices/batches', {
  method: 'POST',
  headers: {
    'x-api-key': 'tu_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    cuitId: 'id-de-tu-cuit',
    descripcion: 'Facturación mensual Mayo 2025'
  })
})

const batch = await response.json()
console.log('Batch ID:', batch.id)  // "batch_xyz789"
Respuesta:
{
  "id": "batch_xyz789",
  "estado": "creado",
  "cuitId": "id-de-tu-cuit",
  "descripcion": "Facturación mensual Mayo 2025",
  "createdAt": "2025-05-01T10:00:00Z",
  "totalItems": 0,
  "procesados": 0,
  "exitosos": 0,
  "fallidos": 0
}

Agregar facturas al lote

PATCH /invoices/batches/{batchId}
Podés agregar facturas de a una o en grupos:
const items = [
  {
    receptor: {
      razonSocial: 'Cliente Uno S.A.',
      cuit: '30-11111111-1',
      condicionIva: 'RI'
    },
    tipo: 1,  // Factura A
    puntoVenta: 1,
    cbteFch: '20260505', // opcional, YYYYMMDD; si omitís, fecha del día al procesar
    items: [
      {
        descripcion: 'Suscripción Pro - Mayo 2025',
        cantidad: 1,
        precioUnitario: 25000,
        alicuotaIva: 21
      }
    ]
  },
  {
    receptor: {
      razonSocial: 'Consumidor Final',
      condicionIva: 'CF'
    },
    tipo: 6,  // Factura B
    puntoVenta: 1,
    items: [
      {
        descripcion: 'Suscripción Basic - Mayo 2025',
        cantidad: 1,
        precioUnitario: 8000,
        alicuotaIva: 21
      }
    ]
  }
  // ... más facturas
]

await fetch(`https://api.facture.ar/invoices/batches/${batchId}`, {
  method: 'PATCH',
  headers: {
    'x-api-key': 'tu_api_key',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ items })
})
Podés agregar ítems en múltiples llamadas al mismo batch. Esto es útil si tenés que armar el lote de forma incremental o si querés agregar facturas desde diferentes partes de tu sistema.

Consultar el estado del lote

GET /invoices/batches/{batchId}
const batch = await fetch(`https://api.facture.ar/invoices/batches/${batchId}`, {
  headers: { 'x-api-key': 'tu_api_key' }
}).then(r => r.json())

console.log(`Total: ${batch.totalItems}`)
console.log(`Procesados: ${batch.procesados}`)
console.log(`Exitosos: ${batch.exitosos}`)
console.log(`Fallidos: ${batch.fallidos}`)
Respuesta:
{
  "id": "batch_xyz789",
  "estado": "procesando",
  "totalItems": 150,
  "procesados": 87,
  "exitosos": 85,
  "fallidos": 2,
  "items": [
    {
      "id": "item_001",
      "estado": "exitoso",
      "invoiceId": "inv_abc123",
      "cae": "71234567890123"
    },
    {
      "id": "item_002",
      "estado": "fallido",
      "error": {
        "codigo": "10013",
        "descripcion": "CUIT receptor no válido"
      }
    }
    // ...
  ]
}

Manejar errores y reintentos

Los ítems fallidos se pueden reintentar individualmente después de corregir el problema:
POST /invoices/batches/{batchId}/items/{itemId}/retry
// Corregí el CUIT incorrecto y reintentá
await fetch(
  `https://api.facture.ar/invoices/batches/${batchId}/items/${itemId}/retry`,
  {
    method: 'POST',
    headers: {
      'x-api-key': 'tu_api_key',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      // Datos corregidos del ítem
      receptor: {
        cuit: '30-22222222-2',  // CUIT corregido
        razonSocial: 'Cliente Corregido S.A.',
        condicionIva: 'RI'
      }
    })
  }
)

Listar todos los lotes

GET /invoices/batches
const batches = await fetch('https://api.facture.ar/invoices/batches?page=1&limit=20', {
  headers: { 'x-api-key': 'tu_api_key' }
}).then(r => r.json())
Parámetros de filtrado disponibles:
  • estado: creado, procesando, completado, con_errores
  • desde / hasta: filtro por fecha de creación
  • page / limit: paginación

Ejemplo completo: facturación mensual de un SaaS

Este script procesa todos los clientes activos de un SaaS y emite una factura mensual para cada uno:
async function facturacionMensual(clientes, mes) {
  const apiKey = process.env.FACTUREAR_API_KEY
  const cuitId = process.env.FACTUREAR_CUIT_ID
  const BASE_URL = 'https://api.facture.ar'
  
  // 1. Crear el lote
  const { id: batchId } = await fetch(`${BASE_URL}/invoices/batches`, {
    method: 'POST',
    headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json' },
    body: JSON.stringify({ cuitId, descripcion: `Facturación ${mes}` })
  }).then(r => r.json())

  console.log(`Lote creado: ${batchId}`)

  // 2. Agregar facturas en chunks de 50
  const CHUNK_SIZE = 50
  for (let i = 0; i < clientes.length; i += CHUNK_SIZE) {
    const chunk = clientes.slice(i, i + CHUNK_SIZE)
    
    const items = chunk.map(cliente => ({
      receptor: {
        razonSocial: cliente.razonSocial,
        cuit: cliente.cuit,
        condicionIva: cliente.condicionIva
      },
      tipo: cliente.condicionIva === 'RI' ? 1 : 6,  // A o B
      puntoVenta: 1,
      items: [{
        descripcion: `Suscripción ${cliente.plan} - ${mes}`,
        cantidad: 1,
        precioUnitario: cliente.montoPlan,
        alicuotaIva: 21
      }]
    }))

    await fetch(`${BASE_URL}/invoices/batches/${batchId}`, {
      method: 'PATCH',
      headers: { 'x-api-key': apiKey, 'Content-Type': 'application/json' },
      body: JSON.stringify({ items })
    })

    console.log(`Procesado chunk ${i / CHUNK_SIZE + 1}`)
  }

  // 3. Polling hasta que el lote termine
  let completado = false
  while (!completado) {
    await new Promise(r => setTimeout(r, 5000))  // Esperar 5 segundos
    
    const batch = await fetch(`${BASE_URL}/invoices/batches/${batchId}`, {
      headers: { 'x-api-key': apiKey }
    }).then(r => r.json())

    console.log(`Progreso: ${batch.procesados}/${batch.totalItems}`)
    completado = batch.estado === 'completado' || batch.estado === 'con_errores'
    
    if (completado) {
      console.log(`Exitosos: ${batch.exitosos}, Fallidos: ${batch.fallidos}`)
      return batch
    }
  }
}

Límites y consideraciones

ParámetroLímite
Ítems por loteSin límite (recomendado: máx. 10.000)
Ítems por PATCH500 por llamada
Lotes concurrentesDepende del plan
Tiempo de retención del lote30 días
Aunque los lotes son asincrónicos, ARCA puede tener límites de tasa. Si procesás volúmenes muy altos, implementá backoff exponencial en los reintentos de errores de ARCA.

Preguntas frecuentes

No se puede cancelar un lote que ya está siendo procesado. Los ítems que ya obtuvieron CAE están emitidos y son válidos. Si necesitás anularlos, debés emitir Notas de Crédito.
No. Cada ítem del lote se procesa de forma independiente. Si un ítem falla por un error de ARCA (CUIT inválido, etc.), el resto sigue procesándose normalmente.
Podés hacer polling al endpoint GET /invoices/batches/ o configurar un webhook para que Facturear te notifique cuando el lote cambia de estado. Ver la documentación de webhooks.
Sí, mientras el lote esté en estado “procesando” o “creado” podés seguir agregando ítems. Los nuevos ítems se encolan y se procesan.
Sí: en API usá cbteFch (YYYYMMDD) por ítem; en CSV del dashboard usá la columna cbte_fch (YYYYMMDD o YYYY-MM-DD). Si no lo definís, se usa la fecha actual al procesar. ARCA no permite fechas anteriores al último comprobante de ese punto de venta y tipo; dentro del lote, las fechas no pueden ir hacia atrás para el mismo circuito.

Recursos relacionados


Seguí estos pasos directamente en Facturear

Ir al dashboard de Facturear y gestionar tu facturación en lotes.