Cambiar el estado de una factura
Cambiar el estado de una factura
Cuando un cliente paga por un medio externo a Venflow (efectivo, transferencia o taquilla), la factura permanece abierta y Venflow continúa intentando cobrarla. Estos endpoints te permiten actualizar su estado desde tu sistema, sin usar el dashboard: registrar el pago, darla por incobrable, anularla o reabrir el cobro de una factura en revisión.
| Acción | Endpoint | Qué hace |
|---|---|---|
| Marcar como pagada | POST /v1/invoices/:id/mark_paid | Deja constancia del pago y cierra la factura. No cobra nada |
| Marcar como incobrable | POST /v1/invoices/:id/mark_uncollectible | Venflow deja de intentar cobrarla. No cancela la suscripción |
| Anular | POST /v1/invoices/:id/mark_void | Deja la factura sin efecto: no se cobra ni cuenta como deuda. No cancela la suscripción |
| Reabrir el cobro | POST /v1/invoices/:id/mark_open | Devuelve a la cola de cobro una factura en revisión con el banco |
Las cuatro devuelven la factura actualizada, con la misma forma que
GET /v1/invoices/:id.
Anular y reabrir el cobro requieren especial cuidado, ya que en algunos casos
pueden dar lugar a un cobro duplicado. Por eso ambas acciones exigen un motivo
(reason), y anular una factura en revisión requiere además una confirmación
explícita. Te recomendamos revisar sus secciones antes de usarlas.
Requisito: la función debe estar habilitada
Estas acciones se habilitan por organización. Mientras estén deshabilitadas para la
tuya, los cuatro endpoints responden 404 con el código not_found, igual que una
ruta que no existe. Si recibes ese 404 con una factura que sí existe, pide que
habiliten la función para tu organización. Como en el resto de la API, decide por
el code de la respuesta, nunca por el message.
Una factura open puede estar esperando respuesta del banco
Una factura queda en revisión cuando el banco no ha confirmado si un cobro se realizó.
En la API conserva el estado open y se identifica con el campo
under_review: true. Para el resto de las facturas, este campo es false.
Mientras una factura está en revisión, Venflow no realiza nuevos intentos de
cobro. El filtro GET /v1/invoices?status=open incluye estas facturas; usa el
campo under_review para distinguirlas.
Te recomendamos consultar under_review antes de aplicar cualquier acción: en una
factura en revisión, es posible que el débito ya se haya realizado, y cada acción
tiene consecuencias distintas.
Qué acción se puede aplicar en cada estado
| Estado actual | mark_paid | mark_uncollectible | mark_void | mark_open |
|---|---|---|---|---|
open | Sí → paid | Sí → uncollectible | Sí → void | No |
open con under_review: true | Sí → paid ⚠️ | Sí → uncollectible ⚠️ | Sí → void 🔴, solo con confirm_under_review: true | Sí → open 🔴 |
uncollectible | Sí → paid | No | No | No |
paid | No | No | No | No |
void | No | No | No | No |
draft | No | No | No | No |
Los íconos ⚠️ y 🔴 indican acciones con riesgo de cobro duplicado; el detalle está en la sección de cada una.
Si la acción no es válida para el estado actual de la factura, la llamada responde
400 con el código failed_precondition. Esto incluye marcar como incobrable una
factura que ya lo es, reabrir una factura open que no está en revisión y anular una
factura en revisión sin confirm_under_review: true. Repetir la llamada no cambia el
resultado; consulta la factura antes de decidir cómo continuar.
Una respuesta 409 con el código aborted significa que esa llamada no aplicó
la acción. Pasa por uno de dos motivos: el estado de la factura cambió justo
mientras la aplicabas (por ejemplo, porque en ese momento entró el cobro
automático), u otra llamada con la misma Idempotency-Key todavía está en curso.
Como el código es el mismo, haz lo mismo en los dos casos: consulta la factura
y, si la acción todavía hace falta, reintenta con la misma Idempotency-Key. Con
la misma clave, la acción nunca se aplica dos veces.
Si una llamada se cortó y no sabes si se aplicó, reintenta también con la misma
Idempotency-Key, no con una nueva: la acción no se aplica otra vez y recibes la
factura como está en ese momento.
Marcar una factura como pagada
curl -X POST "https://api.venflow.app/v1/invoices/<invoice_id>/mark_paid" \
-H "Api-Key: pvk_live_abc123..." \
-H "Organization: org_xyz789..." \
-H "Idempotency-Key: pago-factura-1043-intento-1" \
-H "Content-Type: application/json" \
-d '{
"reference": "000123456789",
"reason": "Pagó en efectivo en la taquilla"
}'| Campo | Tipo | Notas |
|---|---|---|
reference | string (1-500) | Requerido. La referencia del pago tal como aparece en el estado de cuenta. Queda guardada en la transacción y en el historial de la factura, y es la que tu equipo puede buscar después |
reason | string (máx. 500) | Opcional. Una nota que queda en el historial de la factura |
⚠️ Es posible marcar como pagada una factura en revisión, pero ten en cuenta que el cobro automático podría haberse debitado. Si el banco lo confirma después, el pago quedaría registrado dos veces. Te recomendamos confirmar con tu cliente el medio de pago antes de hacerlo.
Marcar una factura como incobrable
curl -X POST "https://api.venflow.app/v1/invoices/<invoice_id>/mark_uncollectible" \
-H "Api-Key: pvk_live_abc123..." \
-H "Organization: org_xyz789..." \
-H "Idempotency-Key: incobrable-factura-1043" \
-H "Content-Type: application/json" \
-d '{ "reason": "El cliente cerró su cuenta bancaria" }'| Campo | Tipo | Notas |
|---|---|---|
reason | string (máx. 500) | Opcional. Por qué se da la factura por perdida; queda en su historial |
⚠️ Si la factura está en revisión (under_review: true), marcarla como incobrable
no anula el cobro pendiente: el banco aún no ha informado si se procesó. Si la
suscripción usa cobros por API, además se procesan los cobros
que estaban en espera. Te recomendamos verificar el estado del cobro con el banco
antes de hacerlo.
Marcar una factura como incobrable no cancela la suscripción; para cancelarla,
usa el API de suscripciones. Este endpoint no acepta un campo de cancelación: si
envías cancel_subscription, el campo se ignora, la factura se marca como
incobrable y la suscripción sigue activa.
Anular una factura
curl -X POST "https://api.venflow.app/v1/invoices/<invoice_id>/mark_void" \
-H "Api-Key: pvk_live_abc123..." \
-H "Organization: org_xyz789..." \
-H "Idempotency-Key: anular-factura-1043" \
-H "Content-Type: application/json" \
-d '{ "reason": "La cuota se canceló en la taquilla" }'| Campo | Tipo | Notas |
|---|---|---|
reason | string (1-500) | Requerido. Por qué se anula la factura; queda en su historial |
confirm_under_review | boolean | Solo para una factura en revisión (under_review: true), y ahí es obligatorio en true. En cualquier otra factura no hace falta |
Al anular una factura, esta queda sin efecto: Venflow no intentará cobrarla y dejará de considerarla una deuda del cliente. La suscripción no se cancela.
Anular una factura en revisión no cancela el cobro pendiente. El banco aún no
ha confirmado si ese débito se realizó; si lo confirma después, el pago quedará
asociado a una factura anulada. Por eso, sobre una factura con under_review: true,
la llamada responde 400 (failed_precondition) y no aplica cambios, a menos que
envíes "confirm_under_review": true. Te recomendamos confirmarlo solo después de
verificar con tu cliente o con tu banco que el cobro no se realizó.
Reabrir el cobro de una factura en revisión
curl -X POST "https://api.venflow.app/v1/invoices/<invoice_id>/mark_open" \
-H "Api-Key: pvk_live_abc123..." \
-H "Organization: org_xyz789..." \
-H "Idempotency-Key: reabrir-factura-1043" \
-H "Content-Type: application/json" \
-d '{ "reason": "El banco confirmó que el débito no se hizo" }'| Campo | Tipo | Notas |
|---|---|---|
reason | string (1-500) | Requerido. Por qué reabres el cobro, por ejemplo cómo confirmaste que el cobro anterior no se hizo; queda en el historial de la factura |
Esta acción solo aplica a facturas en revisión (under_review: true). La factura
vuelve al estado open, deja de estar en revisión y Venflow la incluye en su
próximo ciclo de cobro.
Mientras el cobro anterior no esté confirmado, Venflow no realiza un segundo
débito sobre la misma factura: primero consulta nuevamente ese cobro con el banco.
Si el banco lo confirma, la factura se marca como pagada; si aún no hay respuesta,
vuelve a quedar en revisión; y si el banco lo rechaza, la factura permanece open y
Venflow podrá intentar cobrarla de nuevo.
Excepción: si la factura corresponde a un cobro por API sin reintentos automáticos
(retry_policy: "none"), Venflow no realiza nuevos intentos ni consulta el cobro
pendiente. La factura queda en estado open y su seguimiento queda a cargo de tu
equipo.
Reabre el cobro únicamente si confirmaste que el débito anterior no se realizó.
Para registrar un pago recibido por otro medio, usa mark_paid.
Qué webhook recibes
Al anular o reabrir el cobro de una factura se envía el evento
INVOICE_UPDATE_EVENT, tanto si la
acción se realiza por API como desde el dashboard:
| Acción | invoice.status en el webhook |
|---|---|
Anular (mark_void) | cancelled: así llaman los webhooks a una factura anulada (void en la API) |
Reabrir el cobro (mark_open) | open |
Reglas del texto
reference y reason se validan igual en los cuatro endpoints. Todas devuelven
400 (invalid_argument):
- Máximo 500 caracteres, contando los espacios entre palabras. Los espacios al inicio y al final se quitan antes de contar y de guardar el texto.
- No pueden contener una clave API. Si el texto incluye algo que parece una
(
pvk_,pvtk_y similares), se rechaza, y el mensaje de error no repite el texto que mandaste. - En
mark_voidymark_open,reasones obligatorio: vacío o solo con espacios también responde 400.
Los campos que no figuran en la tabla del endpoint se ignoran: no generan un
error ni tienen efecto. Revisa el nombre de cada campo, ya que uno mal escrito se
considera ausente. Por ejemplo, si envías razon en lugar de reason, la acción se
aplica sin motivo o, si el motivo es obligatorio, se rechaza con 400. Del mismo
modo, un confirm_under_review mal escrito hace que la anulación de una factura en
revisión sea rechazada.
Idempotency-Key: reintentar sin aplicar la acción dos veces
Las cuatro acciones exigen el header Idempotency-Key. Sin él, la respuesta es
un 400.
Si tu llamada se corta por la red o por un timeout, no sabes si la acción se aplicó. Reintenta con la misma clave: Venflow no vuelve a aplicar la acción y te devuelve la factura como está en ese momento.
| Situación | Resultado |
|---|---|
| Misma clave, misma factura, misma acción y mismos datos | La acción no se repite. Se devuelve la factura como está ahora |
Misma clave con otro reference, reason o confirm_under_review | 400, con un mensaje que nombra el campo distinto |
| Misma clave con otra factura u otra acción | 400 |
| Misma clave mientras la primera llamada sigue en curso | 409. Espera unos segundos, consulta la factura y, si la acción todavía hace falta, reintenta con la misma clave |
| La primera llamada falló (por ejemplo, un 400 por el estado) | La clave queda libre: puedes reintentar con ella |
| La primera llamada respondió 500 | Consulta la factura antes de reintentar: el error pudo ocurrir después de aplicar la acción |
Cómo elegir la clave:
- Una clave por cada operación real, no por cada intento. Si registras dos pagos distintos, usa dos claves distintas.
- La clave es única dentro de tu organización y puede tener hasta 255 caracteres. Un identificador de tu sistema (el id del pago en tu caja, por ejemplo) o un UUID funcionan bien.
- El mensaje de error nunca muestra los datos guardados con la clave: solo dice qué campo no coincide.
Permisos de la clave API
Cualquier clave API de tu organización puede usar los cuatro endpoints. No hace falta darle ningún permiso aparte.
Cobros por API
Suscripciones en modo "Cobro por API" — tú decides cuándo y cuánto se cobra
Obtener un cobro GET
Obtiene una solicitud de cobro con su estado actual. Cuando el cobro ya se ejecutó, la respuesta incluye la factura y el pago que generó; cuando falló o se canceló, incluye el motivo en `failure_reason`.