Tutoriales

Contabilizar las facturas en tu sistema contable

Lees las facturas validadas con una pasada por ventanas, luego sus líneas, pagos y notas de crédito, las contabilizas en tu libro mayor y llevas tu propio registro de lo que contabilizaste. La API publica totales en todas partes y el desglose de impuestos solo en el detalle de una factura, así que planifica primero las llamadas y las lagunas.

Este tutorial se apoya en la pasada por ventanas de Sincronizar datos y muestra solo lo específico de las facturas. El dinero que lees es siempre una cadena decimal con dos decimales (la llamada de factura externa del paso 8 acepta hasta seis decimales en la entrada); consulta Importes y monedas.

  • Cada factura y nota de crédito lleva sus totales: subTotal, netPrice, taxesPrice y grossPrice.
  • El desglose por tipo de impuesto está en un solo sitio: taxBreakdown, solo en la lectura de detalle de una factura, y es null cuando no se ha calculado.
  • Las líneas de factura no tienen tipo de impuesto, y la API no publica la serie de una factura.
  • Una nota de crédito solo tiene totales. La especificación dice: "The signed tax document, the tax breakdown, the lines and the reason for the correction are not published."
  • El identificador fiscal del cliente es el actual de la ficha del contacto, no el que figuraba en la factura cuando se emitió.
  • No hay PDF de una factura. Validar una factura es irreversible, y ni la respuesta de la validación ni ningún campo de la factura lleva un estado de la autoridad fiscal. No des por hecho a partir de la API si una factura validada se envió a una autoridad fiscal; pregunta a tu contacto de Filmo si lo necesitas.
  • El status de una nota de crédito es una cadena libre, no una lista cerrada: tolera cualquier valor.

Trata Filmo como la fuente de importes y documentos, y conserva en tu propio registro, en el momento en que los lees, los datos legalmente relevantes que necesita tu contable. La tabla de campos de abajo indica, campo por campo, de dónde sale cada valor o que no está disponible. Hasta que Filmo publique más, contabiliza a partir de estos totales y del desglose del detalle; no deduzcas los tipos de impuesto a partir de los precios de las líneas.

  • Una clave de API con account:read, invoices:read (facturas, líneas y notas de crédito), treasury:read (pagos) y contacts:read (el identificador fiscal del cliente). Añade invoices:write solo si reflejas en Filmo facturas emitidas por el ERP. Crea la clave en los ajustes de API y MCP de la app (Ajustes → API y MCP); solo pueden hacerlo los administradores.
  • Node 22 o posterior, o Python 3 con requests, y la clave en la variable de entorno FILMO_API_KEY.
  • La pasada por ventanas de Sincronizar datos. No sigas el cursor para averiguar qué ha cambiado.

Guarda el cliente una vez; todos los fragmentos posteriores lo importan. Aguarda un rate_limited durante tantos segundos como indique Retry-After y devuelve la hora del servidor a partir de la cabecera Date.

# Export FILMO_API_KEY first: a key with the scopes listed above.
FILMO_URL="${FILMO_BASE_URL:-https://app.filmo.io}"

GET /api/v1/account te da currency y timezone. Una factura lleva su propio currency, que puede ser distinto; contabiliza en la moneda de la factura.

# Export FILMO_API_KEY first: a key with the scopes listed above.
FILMO_URL="${FILMO_BASE_URL:-https://app.filmo.io}"

curl -sS "$FILMO_URL/api/v1/account" \
  -H "Authorization: Bearer $FILMO_API_KEY"

GET /api/v1/invoices tiene updatedFrom (desde, inclusive) y updatedBefore (hasta, exclusive), así que una ventana semiabierta de updatedAt funciona exactamente como en la guía: una página de hasta 500, divide la ventana si pagination.hasMore es true, deduplica por id. La lista no tiene filtro por estado del documento, así que léelas todas y sepáralas por status: draft aún no tiene número (no contabilices nada), validated está numerada y lista, voided se trata en el paso 7. Cuando se valida un borrador, su registro cambia, así que vuelve en una ventana posterior. Validar, anular y registrar un pago mueven el updatedAt de la factura. La marca un segundo anterior que describe la guía pertenece al pedido que contiene la factura, no a la factura, pero Filmo sigue sin dar una cota garantizada para el retraso antes de que un cambio sea legible, así que mantén el margen de seguridad de la guía (dos minutos como mínimo) y deduplica por id.

FILMO_URL="${FILMO_BASE_URL:-https://app.filmo.io}"

# One window [updatedFrom, updatedBefore), one page. If pagination.hasMore is true, split the window.
curl -sS -G "$FILMO_URL/api/v1/invoices" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "updatedFrom=2026-10-08T00:00:00.000Z" \
  --data-urlencode "updatedBefore=2026-10-09T00:00:00.000Z" \
  --data-urlencode "sort=updatedAt" \
  --data-urlencode "limit=500"
FILMO_URL="${FILMO_BASE_URL:-https://app.filmo.io}"

# One window [updatedFrom, updatedBefore), one page. If pagination.hasMore is true, split the window.
curl -sS -G "$FILMO_URL/api/v1/invoices" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "updatedFrom=2026-10-08T00:00:00.000Z" \
  --data-urlencode "updatedBefore=2026-10-09T00:00:00.000Z" \
  --data-urlencode "sort=updatedAt" \
  --data-urlencode "limit=500"

La lista ya devuelve lo que necesitas para una cabecera de asiento contable: número, fechas de emisión y de vencimiento, moneda, el contacto como id y nombre, los totales, el importe cobrado y el estado de pago. La marca de agua pasa a B solo después de leer todas las ventanas de la pasada. Las notas de crédito se leen de sus propios endpoints, en el paso 6. La lista de facturas aún puede devolver una fila con isRectification activado, por ejemplo una factura importada de otro sistema: trátala como un documento propio (su importe puede ser negativo) y cótejala con las notas de crédito por número, para no contabilizarla dos veces.

Paso 3. Leer el desglose de impuestos desde el detalle

Enlace a esta sección: Paso 3. Leer el desglose de impuestos desde el detalle

GET /api/v1/invoices/{invoiceId} devuelve la misma factura más taxBreakdown: una fila por tipo de impuesto, con taxType, label, rate (un porcentaje), baseAmount y amount. El detalle también tiene la dirección de facturación, el tipo de cambio y el reparto de los descuentos. Cuesta una llamada por factura, así que léelo una vez cuando veas la factura validada por primera vez, y de nuevo solo cuando la factura reaparezca en una ventana con un updatedAt distinto. Envía el ETag que guardaste en If-None-Match para obtener un 304 cuando nada ha cambiado; un 304 cuenta igualmente como petición.

# The detail is the only place with the tax breakdown.
curl -sS "$FILMO_URL/api/v1/invoices/$INVOICE_ID" \
  -H "Authorization: Bearer $FILMO_API_KEY"

Cuando el desglose es null o no coincide

taxBreakdown es null cuando no se ha calculado. Si es null, o si sus sumas difieren de taxesPrice y netPrice, contabiliza la factura por totales y márcala para revisión; no construyas tú el desglose a partir de las líneas, que no llevan tipo de impuesto.

GET /api/v1/invoices/{invoiceId}/lines devuelve lo que se facturó en orden de documento, con itemName congelado en el momento de la emisión (puede diferir del catálogo de hoy), quantity, unitPrice, linePrice y el periodo facturado. Las líneas de tipo section y type_group son agrupaciones de presentación sin recurso y sin precio. Las líneas no incluyen un tipo de impuesto, como dice la especificación: "los totales de la factura ya incluyen los impuestos calculados". Una factura validada no cambia, así que lee sus líneas una sola vez.

# What was invoiced, line by line, with the names frozen when the invoice was issued.
curl -sS -G "$FILMO_URL/api/v1/invoices/$INVOICE_ID/lines" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "limit=500"

GET /api/v1/invoices/{invoiceId}/payments toma el scope treasury:read, no el de facturas, y devuelve los pagos asignados a la factura. No tiene filtro updated*, así que léela en orden descendente de sort -updatedAt y detente en el primer pago más antiguo que lo que tienes; un pago que cambia en mitad de una lectura pasa al principio y te da un duplicado, que deduplicas por id, nunca un hueco. Un pago tiene amount, date, reference, treasuryAccountId, un type de normal o deposit, y linkedDocuments, que indica cuánto fue a cada documento.

No necesitas leer los pagos de cada factura cada vez. La lista te da totalPaid y paymentStatus de cada factura, así que lee los pagos de una factura solo cuando difieran de lo que guardaste. Un pago puede llegar semanas después de la factura. Registrarlo mueve el updatedAt de la factura, pero Filmo no da ningún límite garantizado de cuánto puede retrasarse esa marca, así que una vez al día, enumera las facturas que aún pueden pagarse con paymentStatuses unpaid,partially_paid,overdue y compara. Esa lista puede incluir borradores: fíltralos por status por tu parte. Si la suma de los importes que tienes de una factura no coincide con su totalPaid, vuelve a leer sus pagos desde el principio.

# Newest change first. Stop reading when updatedAt is older than what you already hold.
curl -sS -G "$FILMO_URL/api/v1/invoices/$INVOICE_ID/payments" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "sort=-updatedAt" \
  --data-urlencode "limit=500"

# Once a day: the invoices that can still receive a payment.
curl -sS -G "$FILMO_URL/api/v1/invoices" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "paymentStatuses=unpaid,partially_paid,overdue" \
  --data-urlencode "limit=500"

Lee las notas de crédito desde sus propios endpoints. GET /api/v1/credit-notes acepta la misma ventana updatedFrom y updatedBefore, así que el mismo ayudante las lee. GET /api/v1/credit-notes/{creditNoteId} devuelve la misma ficha que la lista, así que no hay una llamada de detalle que presupuestar. Una nota de crédito tiene creditNoteNumber, issueDate, status, invoiceId (la factura que rectifica, o null) y los totales; no hay desglose, ni líneas, ni motivo. Su status es una cadena libre: guárdala tal como llega y no ramifiques sobre una lista cerrada de valores. Comprueba el signo de los importes de una nota de crédito en tu propia cuenta antes de decidir el signo de tu asiento.

# Credit notes have their own endpoints. The same windowed read, on updatedAt.
curl -sS -G "$FILMO_URL/api/v1/credit-notes" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  --data-urlencode "updatedFrom=2026-10-08T00:00:00.000Z" \
  --data-urlencode "updatedBefore=2026-10-09T00:00:00.000Z" \
  --data-urlencode "sort=updatedAt" \
  --data-urlencode "limit=500"

POST /api/v1/invoices/{invoiceId}/void solo funciona con una factura validada. La factura conserva su número, porque anular no libera la numeración, y pasa a voided; no emite una nota de crédito. Por tanto, una factura anulada es un cambio, no un borrado. La pasada por ventana la devuelve con su nuevo estado; el barrido semanal de la guía, que compara el estado y updatedAt, es la red de seguridad por si se escapa alguna.

VesQué hacer
Una factura voided que ya contabilizasteContabiliza la anulación en tu libro como te indique tu contable. Conserva el asiento original y su número; no lo borres.
Una factura voided que nunca viste validadaRegístrala como anulada y no contabilices nada, o contabilízala y revierte el asiento si tu contable necesita el número en los libros.
Dinero a devolverAnular no reembolsa nada. Si hay que devolver dinero, es otro documento: una nota de crédito (paso 6).
Una factura que desaparece de tus lecturasConfirma con GET /api/v1/invoices/{invoiceId} antes de cambiar tu lado; solo un 404 significa que ya no existe, como en el barrido de conciliación de la guía.

Paso 8. Reflejar en Filmo una factura emitida por el ERP (opcional)

Enlace a esta sección: Paso 8. Reflejar en Filmo una factura emitida por el ERP (opcional)

Si tu ERP emite algunas facturas, PUT /api/v1/invoices/external/{originSystem}/{originExternalId} guarda en Filmo una copia de solo lectura de cada una para que el equipo de operaciones pueda verla. La copia nunca se envía a una autoridad fiscal y no se numera en una serie de Filmo. La especificación es explícita sobre lo que es esa copia: "Filmo no la emite: no se numera en una serie de Filmo, no se firma y nunca se envía a Verifactu. Se guarda validada, bloqueada y marcada como emitida externamente, y en Filmo no se puede editar, anular, cobrar, rectificar, facturar electrónicamente ni enviar por correo: todo cambio llega por esta misma llamada."

Esta es la única llamada en la que eliges la clave. El par originSystem (un slug en minúsculas tuyo, como acme_erp) y originExternalId (el id del documento en tu ERP) identifica el espejo: repetir la llamada lo actualiza, y repetir el mismo contenido no cambia nada. Responde 201 cuando crea el espejo y 200 cuando lo actualiza o lo encuentra idéntico. Envía una Idempotency-Key como en cualquier escritura. El cliente se resuelve por contactId, luego por identificador fiscal y luego por nombre exacto; un cliente desconocido o ambiguo se rechaza, porque los contactos nunca se crean de forma implícita. Los totales declarados se comprueban contra las líneas con una tolerancia de un céntimo por línea, y una discrepancia también se rechaza. Ambos casos responden 400 validation_error, con errors[0].path indicando el campo (contactId, contactTaxId, contactName, subTotal, taxTotal, total o lines[n].taxRate), y no se escribe nada. Los importes, cantidades y precios de esta llamada admiten hasta seis decimales, y la regla de dos decimales se aplica a lo que lees de vuelta. En el ejemplo, 2 × 150.00 + 1 × 80.00 = 380.00 de base, 79.80 de impuesto al 21% y 459.80 de total.

# originSystem is a lowercase slug you choose; originExternalId is the document id in your ERP.
curl -sS -X PUT "$FILMO_URL/api/v1/invoices/external/acme_erp/INV-2026-0001" \
  -H "Authorization: Bearer $FILMO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "invoiceNumber": "INV-2026-0001",
    "invoiceDate": "2026-10-08",
    "dueDate": "2026-11-07",
    "currency": "EUR",
    "contactTaxId": "B00000000",
    "lines": [
      { "description": "Camera package, 2 days", "quantity": "2", "unitPrice": "150.00", "taxRate": "21" },
      { "description": "Delivery", "quantity": "1", "unitPrice": "80.00", "taxRate": "21" }
    ],
    "subTotal": "380.00",
    "taxTotal": "79.80",
    "total": "459.80",
    "externalStatus": "issued"
  }'

Estos espejos pueden volver en tu propia lectura

Una factura que reflejas se guarda como validada, así que puede aparecer en GET /api/v1/invoices como cualquier otra. Conserva el id de Filmo que devuelve la llamada junto a tu id del ERP y omite esos ids cuando contabilices, o contabilizarás tu propia factura dos veces. Automatizaciones: esta llamada dispara los workflows de eventos de la cuenta (factura creada, actualizada o anulada) después de la respuesta, en la medida de lo posible, y no puedes suprimirlos por petición. Primero lista los workflows de eventos activos (consulta Pruebas) y filtra por origen el trigger de cualquier workflow que no deba reaccionar, para excluir api y mcp. Una factura anulada en tu ERP se envía con externalStatus voided y un motivo; Filmo se niega (409, con errors[0].code invalid_state) a convertir de nuevo en emitido un espejo anulado.

De dónde sale cada campo de tu sistema contable. "Not available" significa que la API no lo publica hoy; la columna de la derecha da la solución alternativa.

Campo contableCampo de FilmoLee conNotas o alternativa
Número de facturainvoiceNumberGET /api/v1/invoicesNull solo mientras la factura es un borrador. Una factura anulada conserva su número.
Fecha de emisióninvoiceDateGET /api/v1/invoicesUn instante. Toma la fecha en la zona horaria del negocio (timezone) para el libro contable.
Fecha de vencimientodueDateGET /api/v1/invoicesNull si no se establece.
Moneda y tipo de cambiocurrency; exchangeRateGET /api/v1/invoices; GET /api/v1/invoices/{invoiceId}La tasa solo aparece en el detalle y es null cuando no se aplica.
Clientecontact: un id y un nameGET /api/v1/invoicesEl id es tu clave del cliente; el nombre es tal como lo muestra Filmo.
Identificador fiscal del cliente en el momento de la emisiónNo disponible-La API solo devuelve el nif actual, leído con GET /api/v1/contacts/{contactId}. Lee el contacto la primera vez que veas la factura y guarda el identificador fiscal con el asiento que contabilices.
Dirección de facturaciónbillingAddressGET /api/v1/invoices/{invoiceId}Solo en el detalle; null si no se registró.
Subtotal, descuentos, base, impuesto, totalsubTotal, discountTotal, netPrice, taxesPrice, grossPriceGET /api/v1/invoicesCadenas decimales con dos decimales. El detalle divide el descuento en productDiscountTotal y globalDiscountTotal y añade insuranceTotal y depositTotal.
Base e impuesto por tipo de impuestotaxBreakdownGET /api/v1/invoices/{invoiceId}Una llamada de detalle por factura; null si no se ha calculado. No está en la lista.
LíneasitemName, quantity, unitPrice, linePrice, startDate, endDate, rentalDaysGET /api/v1/invoices/{invoiceId}/linesLos nombres se congelan al emitir. Una línea facturada a cero tiene free activado.
Tipo de impuesto de cada líneaNo disponible-Una línea no tiene campo de impuesto. Usa el taxBreakdown de la factura para el desglose por tipo de impuesto; no lo repartas entre las líneas.
Serie de facturaNo disponible-La API no publica la serie de una factura. Tómala de la app; no la extraigas del número a menos que tu contable confirme el formato del número.
Pagosamount, date, reference, treasuryAccountId; en la factura totalPaid, paymentStatus, paymentMethodGET /api/v1/invoices/{invoiceId}/payments; GET /api/v1/invoicesLos pagos necesitan treasury:read. Un pago puede repartirse entre documentos: lee linkedDocuments.
Notas de créditocreditNoteNumber, issueDate, invoiceId, contactId, netPrice, taxesPrice, grossPriceGET /api/v1/credit-notes; GET /api/v1/credit-notes/{creditNoteId}Solo totales. Léelos en los endpoints de notas de crédito.
Desglose de impuestos, líneas y motivo de la nota de créditoNo disponible-Contabiliza la nota de crédito por totales y completa el desglose y el motivo desde la app.
PDF de la facturaNo disponible-Ninguna operación lo devuelve. Genera tu propio documento a partir de los datos anteriores, o descárgalo desde la app.

La tabla siguiente se genera a partir de la especificación. Enumera, campo por campo, lo que publican los esquemas de factura y de nota de crédito, y los datos contables que la API no ofrece en esta versión.

CampoTipoDisponible
InvoiceDto.idstringSí
InvoiceDto.invoiceNumberstring | nullSí
InvoiceDto.statusstringSí
InvoiceDto.isRectificationbooleanSí
InvoiceDto.invoiceDatestring | nullSí
InvoiceDto.dueDatestring | nullSí
InvoiceDto.currencystringSí
InvoiceDto.contactobject | nullSí
InvoiceDto.orderIdstring | nullSí
InvoiceDto.orderNumberstring | nullSí
InvoiceDto.projectIdstring | nullSí
InvoiceDto.subTotalstringSí
InvoiceDto.discountTotalstringSí
InvoiceDto.taxesPricestringSí
InvoiceDto.netPricestringSí
InvoiceDto.grossPricestringSí
InvoiceDto.totalPaidstring | nullSí
InvoiceDto.paymentStatusstringSí
InvoiceDto.paymentMethodstring | nullSí
InvoiceDto.tagsarraySí
InvoiceDto.createdAtstringSí
InvoiceDto.updatedAtstringSí
InvoiceDetailDto.idstringSí
InvoiceDetailDto.invoiceNumberstring | nullSí
InvoiceDetailDto.statusstringSí
InvoiceDetailDto.isRectificationbooleanSí
InvoiceDetailDto.invoiceDatestring | nullSí
InvoiceDetailDto.dueDatestring | nullSí
InvoiceDetailDto.currencystringSí
InvoiceDetailDto.contactobject | nullSí
InvoiceDetailDto.orderIdstring | nullSí
InvoiceDetailDto.orderNumberstring | nullSí
InvoiceDetailDto.projectIdstring | nullSí
InvoiceDetailDto.subTotalstringSí
InvoiceDetailDto.discountTotalstringSí
InvoiceDetailDto.taxesPricestringSí
InvoiceDetailDto.netPricestringSí
InvoiceDetailDto.grossPricestringSí
InvoiceDetailDto.totalPaidstring | nullSí
InvoiceDetailDto.paymentStatusstringSí
InvoiceDetailDto.paymentMethodstring | nullSí
InvoiceDetailDto.tagsarraySí
InvoiceDetailDto.createdAtstringSí
InvoiceDetailDto.updatedAtstringSí
InvoiceDetailDto.projectNamestring | nullSí
InvoiceDetailDto.taxBreakdownarray | nullSí
InvoiceDetailDto.productDiscountTotalstringSí
InvoiceDetailDto.globalDiscountTotalstringSí
InvoiceDetailDto.insuranceTotalstringSí
InvoiceDetailDto.depositTotalstringSí
InvoiceDetailDto.exchangeRatenumber | nullSí
InvoiceDetailDto.billingAddressobject | nullSí
InvoiceDetailDto.sourceQuoteIdsarray | nullSí
InvoiceDetailDto.sourceProformaIdsarray | nullSí
DocumentLineDto.idstringSí
DocumentLineDto.resourceTypestringSí
DocumentLineDto.transactionTypestringSí
DocumentLineDto.positionintegerSí
DocumentLineDto.itemIdstring | nullSí
DocumentLineDto.itemNamestring | nullSí
DocumentLineDto.variantIdstring | nullSí
DocumentLineDto.variantNamestring | nullSí
DocumentLineDto.quantitynumberSí
DocumentLineDto.orderIdstring | nullSí
DocumentLineDto.orderNumberstring | nullSí
DocumentLineDto.startDatestring | nullSí
DocumentLineDto.endDatestring | nullSí
DocumentLineDto.rentalDaysnumber | nullSí
DocumentLineDto.unitPricestring | nullSí
DocumentLineDto.linePricestring | nullSí
DocumentLineDto.freebooleanSí
DocumentLineDto.notesstring | nullSí
CreditNoteDto.idstringSí
CreditNoteDto.creditNoteNumberstring | nullSí
CreditNoteDto.statusstringSí
CreditNoteDto.issueDatestring | nullSí
CreditNoteDto.currencystringSí
CreditNoteDto.contactIdstring | nullSí
CreditNoteDto.invoiceIdstring | nullSí
CreditNoteDto.subTotalstringSí
CreditNoteDto.taxesPricestringSí
CreditNoteDto.netPricestringSí
CreditNoteDto.grossPricestringSí
CreditNoteDto.createdAtstringSí
CreditNoteDto.updatedAtstringSí
PDF de facturas y otros documentos—No disponible en v1
Componer borradores de factura y editar presupuestos—No disponible en v1
Desglose de impuestos, líneas y motivo de una nota de crédito—No disponible en v1
El identificador fiscal del cliente en el momento de emitir una factura—No disponible en v1
Tipo de impuesto por línea y serie de una factura—No disponible en v1

La lista de lo que la API no ofrece en esta versión está en Capacidades y límites.

GuardarPor qué
id de la factura de Filmo junto al asiento que contabilizastePara volver a encontrarlo en una anulación, un pago o una nota de crédito. Los identificadores son opacos.
El updatedAt y el ETag de cada facturaPara omitir una lectura de detalle cuando no ha cambiado nada, y para el barrido semanal.
totalPaid y paymentStatus, y los pagos que tienesPara decidir qué facturas necesitan una lectura de pagos.
El identificador fiscal del cliente en el momento en que lees la facturaLa API solo devuelve el actual.
La marca de agua B de la última pasada completa, para facturas y para notas de créditoLa siguiente pasada empieza ahí. Solo avanza tras una pasada completa.
Los ids de Filmo de las facturas que has replicado con la llamada externaPara omitirlos cuando leas facturas.

Presupuesto de llamadas frente a 120 peticiones por minuto

Enlace a esta sección: Presupuesto de llamadas frente a 120 peticiones por minuto

Tu clave permite 120 peticiones por minuto en toda la API, y cada respuesta autenticada cuenta. La parte cara de este tutorial es el desglose de impuestos: existe solo en la lectura de detalle, que cuesta una llamada por factura. Para una lista leída en W ventanas de las cuales S desbordan una página, el coste es W + 2S llamadas. La carga inicial es:

Carga inicial
calls = 1 + (W_inv + 2*S_inv) + (W_cn + 2*S_cn) + N + N + P
  N = validated invoices (one detail call and one lines call each)
  P = invoices with a collection (one payments call each)
minutes = calls / 120

Ejemplo práctico. 12,000 facturas validadas en 24 meses, el 70% de ellas con un cobro (P = 8,400), y 600 notas de crédito. Facturas: 24 ventanas mensuales, de las cuales 12 tienen más de 500 y desbordan: 24 + 2 × 12 = 48 llamadas. Notas de crédito: 24 ventanas, ninguna desborda: 24 llamadas. Total: 1 + 48 + 24 + 12,000 + 12,000 + 8,400 = 32,473 llamadas. A 120 por minuto son 270.6 minutos (4.5 horas); a 96 por minuto, dejando libre una quinta parte de la cuota, 338.3 minutos (5.6 horas). Solo las lecturas de detalle son 12,000 de esas llamadas. Si puedes contabilizar por totales y no necesitas el desglose por tipo de impuesto, te las ahorras y la carga es de 20,473 llamadas, 170.6 minutos (2.8 horas).

Ritmo diario
calls per day = 3 * polls + D + L + Pd + R
  polls = passes per day (each: 1 server time + 1 invoice window + 1 credit-note window)
  D = invoices that appear in a window (one detail call each)
  L = newly validated invoices (one lines call each)
  Pd = invoices whose totalPaid or paymentStatus changed (one payments call each)
  R = open-invoice refresh, once a day: ceil(rows the filter returns / 500), drafts included

Ejemplo práctico. Una pasada cada hora (24 pasadas, así que 72 llamadas), 40 facturas nuevas al día y 10 antiguas que cambian, así que D = 50 y L = 40. Pagos que leer: 28 de las facturas nuevas que ya llevan un cobro (70% de 40) y 10 de las modificadas, así que Pd = 38. Con 300 facturas abiertas la actualización es 1 llamada. Total: 72 + 50 + 40 + 38 + 1 = 201 llamadas al día, menos de dos minutos de cuota (1.7). El barrido semanal cuesta las llamadas de lista de la carga más un GET por cada id que falte.

Ejecuta la carga inicial en una hora tranquila y deja que el cliente espere cuando reciba rate_limited.

RespuestaQué significa aquíQué hacer
401 api_key_owner_inactive o api_key_owner_not_adminLa persona que creó la clave se fue o dejó de ser administradora.Deja de publicar, avisa a alguien y vuelve a emitir la clave desde una cuenta de administrador.
403 insufficient_scopeFalta un permiso (scope); requiredScope lo nombra. Los pagos necesitan treasury:read y el identificador fiscal necesita contacts:read.Vuelve a emitir la clave con los permisos (scopes) de los requisitos previos.
404 not_foundEn una factura, una nota de crédito o sus pagos: no existe o está fuera de tu cuenta. Los pagos de una factura desconocida son un 404, no una lista vacía.Marca el registro como perdido y confírmalo en el siguiente barrido; no borres un asiento contabilizado.
400 validation_errorUn parámetro tiene un formato incorrecto, o el cuerpo de la llamada externa no es válido.Corrige la petición; errors[] lista cada campo.
409 conflict en la llamada externaLee errors[0].code. invalid_state: el número de factura lo usa otra factura, la clave pertenece a una factura que no es un reflejo, o se reenvió como emitido un reflejo anulado. in_progress: una petición con la misma clave sigue en ejecución. lock_timeout: otra escritura retuvo la factura durante más de cinco segundos.Para invalid_state, no reintentes: corrige los datos. Para in_progress y lock_timeout, espera y reintenta con el mismo Idempotency-Key.
422 idempotency_key_reusedReutilizaste una Idempotency-Key con un cuerpo distinto.Usa una clave nueva para un documento modificado; reutiliza una clave solo para reintentar la llamada idéntica.
400 validation_error en la llamada externa, por el cliente o los totalesEl cliente es desconocido o ambiguo, o los totales declarados no coinciden con las líneas. errors[] nombra el campo.Resuelve el cliente con contactId, corrige los totales y envía el documento corregido. Una petición rechazada no deja ningún registro, así que puedes reutilizar la Idempotency-Key o usar una nueva.
429 rate_limitedGastaste las 120 peticiones del minuto.Espera Retry-After segundos (también retryAfter en el cuerpo del problema) y continúa con la misma ventana.
500 internal_error, 502 o 504Un fallo transitorio. Las lecturas se pueden repetir sin riesgo; para la llamada externa, reintenta con el mismo Idempotency-Key.Reintenta con espera exponencial y no muevas la marca de agua.
503 service_unavailableNinguna operación de este tutorial lo documenta. Filmo controla el interruptor que hay detrás.No lo reintentes como un fallo transitorio. Detén esa llamada y contacta con el soporte de Filmo con el requestId.
  • Guías

    Sincronizar datos

    Filmo v1 no envía webhooks, así que mantienes otro sistema sincronizado consultando periódicamente: lee lo que cambió en ventanas de tiempo semiabiertas y ejecuta un barrido aparte para encontrar lo que se eliminó. No sigas el cursor de paginación para decidir qué cambió o qué desapareció.

  • Para saber más

    Importes y monedas

    Todo importe monetario es una cadena decimal con dos decimales, como "1234.50", nunca un número de coma flotante, con una excepción: los precios de priceConfig y defaultExpenses de un servicio y el customPrice de un accesorio son números JSON. Cada documento lleva su propia moneda, que puede diferir de la de la cuenta.

  • Para saber más

    Capacidades y límites de la v1

    La API cubre la mayor parte del trabajo diario con pedidos, contactos, artículos, facturas y la agenda, y deja una lista corta de cosas a la app. Compruébalo aquí antes de diseñar una integración en torno a una función.

  • Guías

    Idempotencia y reintentos seguros

    Envía una cabecera Idempotency-Key con cada escritura y reutiliza el mismo valor cuando reintentes esa operación: Filmo devuelve el resultado almacenado del primer intento en lugar de escribir dos veces.

  • Tutoriales

    Sincronizar tu inventario con otro sistema

    Lees el catálogo, las unidades físicas y las líneas de los pedidos que las comprometen, lo cargas todo una vez, y después consultas los cambios y concilias cada semana. Filmo no envía webhooks, así que consultar periódicamente es la forma de mantenerte al día.

¿Te ha resultado útil esta página?