Versionado y cambios

GUÍA

Winal versiona en dos planos que no debes confundir: la ruta (/v1), que cambia solo ante rediseños incompatibles a gran escala, y la versión de API por fecha (api_version), que fija la forma exacta de los payloads. La regla de oro: tu integración no se rompe por un cambio que tú no pediste.

La ruta /v1

Todos los endpoints de integración cuelgan de /v1. Ese número mayor solo cambiaría ante un rediseño incompatible del API completo — algo raro y muy anunciado. Mientras exista /v1, seguirá aceptando el contrato que documentamos aquí.

api_version por fecha

La forma concreta de los recursos se identifica con una versión con fecha, del estilo 2026-07-01. La verás en cada entrega de webhook, en el campo api_version del envelope:

envelope de webhook
{
  "event_id": "8f2a1c3e-...",
  "event_type": "payment_intent.succeeded",
  "api_version": "2026-07-01",
  "livemode": false,
  "data": { "...": "..." }
}

Esa marca te dice contra qué contrato serializamos el payload. Fíjala en tu integración (guárdala o valídala) para saber, sin ambigüedad, qué forma esperar.

Cómo introducimos cambios

Distinguimos cambios aditivos (seguros, entran sin aviso) de cambios rompientes (nunca en silencio). Escribe tu cliente para tolerar los primeros.

Aditivo (no rompe)Rompiente (nunca en silencio)
Un campo nuevo en una respuestaRenombrar o quitar un campo existente
Un valor nuevo en un enumCambiar el tipo de un campo
Un endpoint o recurso nuevoVolver requerido un parámetro antes opcional
Un event_type nuevoCambiar el significado de un campo o de un estado
Un header de respuesta nuevoRetirar un endpoint
🧱 Escribe un cliente tolerante
  • Ignora campos que no conozcas en vez de fallar al deserializar.
  • Trata los enums como abiertos: maneja un status o event_type desconocido con una rama por defecto, no con un crash.
  • Recuerda que los campos null se omiten en las respuestas de /v1 (no llegan como null, simplemente no están) — no asumas que una llave siempre existe.

Los cambios rompientes, cuando sean inevitables, se introducen bajo una api_version nueva y con aviso previo; tu integración existente sigue recibiendo la forma con la que la escribiste hasta que decidas migrar.

Deprecación

Cuando algo va a retirarse, lo marcamos como deprecado en la Referencia y en las notas de cambio, con una alternativa recomendada y una ventana de transición. Un endpoint deprecado sigue funcionando durante esa ventana; no desaparece de un día para otro.

2026-09-24 — Depósitos: el formulario de TAECEL, el aviso y el saldo al momento

Lo que un punto de venta necesita para que una farmacia fondee su saldo y sepa cuándo ya puede vender. Todo es aditivo salvo una corrección, abajo. El comprobante lo recibe y lo valida TAECEL en su propio formulario; Winal no ve ni guarda el archivo.

2026-09-20 — Varios agregadores de recargas: respaldo, ruteo y cuadre por agregador

Un solo programa en tres piezas, todas aditivas, en POST /v1/recharges, GET /v1/recharges, GET /v1/recharges/{id} y GET /v1/recharges/statement(.csv): nada se renombra, nada cambia de significado, ningún estado nuevo, ningún campo que ya leías cambia de posición. Si tu integración ya funciona, sigue funcionando sin tocar nada. Lo que sigue es lo que puedes empezar a usar.

Lo que NO cambia. Nada en la API nombra al agregador salvo el connector_key que ya venía en cada recarga y el filtro nuevo; el traspaso de saldo sigue exigiendo dos cuentas en el agregador (el destino es un clienteID del proveedor, no otra bolsa dentro de la misma cuenta); pouch_id sigue siendo solo del JSON del estado de cuenta; y las reglas de dinero —un timeout no es un fracaso, una entrega no se reversa— son las mismas.

2026-09-18 — Tu Idempotency-Key ahora es de tu ambiente

Un cambio de contrato en toda operación que mueve dinero o timbra un comprobante, más una capacidad nueva para quien administra cuentas. Cinco minutos de lectura; probablemente no tengas que cambiar nada.

El cambio de contrato: qué es distinto y qué sigue igual

Una Idempotency-Key se identificaba por (tu cuenta, la llave). Ahora se identifica por (tu cuenta, el AMBIENTE de tu credencial, la llave) — ver el detalle en Entornos y Base URL. Aplica a toda ruta que mueve dinero o emite un comprobante fiscal: cobros, refunds, payouts, traspasos de Connect, facturas, notas de crédito y complementos de pago (REP), recargas y pagos de servicio, y el nuevo traspaso de saldo entre bolsas.

Dentro de un mismo ambiente, nada cambia: la misma llave con el mismo cuerpo te sigue devolviendo la misma operación sin volver a ejecutarla, y con otro cuerpo sigue siendo un conflicto. Lo que cambia es el cruce ENTRE ambientes. Antes, tu sk_test_ y tu sk_live_ compartían el espacio de llaves de tu cuenta; si reutilizabas la misma Idempotency-Key en los dos —lo típico si la derivas de tu folio de ticket y probaste en sandbox con los mismos folios con los que vendes de verdad—, tu primera operación real en producción podía recibir de vuelta, silenciosamente, la respuesta que ya se había cacheado en pruebas: un acuse de éxito por una operación que solo ocurrió en el simulador. Ahora esa misma llave desde el otro ambiente es una petición nueva, que ejecuta y crea su propia operación.

Qué tienes que hacer: nada, si ya generas llaves distintas por ambiente (lo más común). Si derivas tu llave de un folio propio y ese folio se repite entre tu integración de pruebas y tu operación real, ya lo sabes: tu primera venta real con un folio que ya usaste en sandbox ahora se procesa de verdad, en vez de devolverte el resultado de la prueba.

Esto se arregló, y pudo haberte tocado

Nuevo: mueve saldo entre tus propias cuentas del agregador

Si administras cuentas de terceros (Cuentas administradas) y cada una tiene su PROPIA cuenta en el agregador de recargas, hoy fondear cada una exige un depósito bancario por separado. POST /v1/recharge-transfers mueve saldo YA depositado de una bolsa tuya a otra del mismo comercio: depositas una vez a tu cuenta central y repartes desde tu sistema. Detalle completo en Recargas de tiempo aire → Traspasar saldo entre tus bolsas.

Requisito real, no de trámite: necesitas al menos DOS cuentas de TAECEL dadas de alta bajo tu comercio. El destino de un traspaso es un clienteID real del agregador — no una segunda bolsa que Winal invente por ti —, así que si hoy solo tienes UNA cuenta activa, el endpoint ya está disponible pero no tiene con qué operar hasta que des de alta una segunda (recharge_transfer.source_not_found o recharge_transfer.destination_not_found). Preferimos que lo sepas aquí a que lo descubras con un error sin contexto.

Es irreversible una vez aplicado —el agregador no cancela ni reversa un traspaso exitoso, igual que una recarga entregada—. Si mandas de más, la única salida es que la cuenta destino te lo regrese con otro traspaso.

Nuevo, y ya lo puedes usar sin condiciones: el historial de tu bolsa

GET /v1/recharges/bag-movements lee el historial de movimientos de tu bolsa —incluidos los depósitos— tal como lo reporta el agregador, para conciliar un comprobante de depósito sin hacer la resta de saldos a mano. Ver Recargas de tiempo aire → Conciliar un depósito.

Changelog

Historial de capacidades del API, de lo más reciente a lo más antiguo. Las fechas son de disponibilidad en modo prueba.

FechaCapacidadTipo
2026-09-24Depósitos de saldo (migración 0156): GET /v1/recharge-report-links y POST /v1/recharge-report-links/refresh (el enlace del formulario de TAECEL donde la farmacia sube su comprobante, de cualquier bolsa propia; solo con llave sk_live_), POST /v1/recharge-balance/refresh (el saldo al momento, con freno de 10 minutos por bolsa; bloque refresh en GET /v1/recharges/balance) y el webhook recharge.deposit.detected — ver el aviso arriba.Aditivo
2026-09-24uses_own_credentials de GET /v1/recharges/balance es true para una bolsa de la que la cuenta es dueña (antes salía false para cualquier bolsa).Corrección
2026-09-23La cuenta propia de cada farmacia en el agregador (migración 0155): desde la ficha de cada cliente, Winal le da de alta su cuenta en TAECEL dentro de tu red de distribuidor —su referencia de depósito, su formulario para reportar el depósito y su saldo—. Endpoint nuevo de solo lectura GET /v1/recharge-subaccounts para que tu punto de venta muestre la referencia y el enlace de reporte de cada farmacia. Un traspaso ya puede llegar a la cuenta propia de la farmacia. Códigos nuevos recharge_subaccount.*. En la consola, mode: "provision" sobre una bolsa propia sigue rechazándose con recharge.provisioning_unavailable, ahora con la dirección correcta.Aditivo
2026-09-21Depósitos por referencia (migración 0152): una bolsa puede acreditar el cupo de cada cliente a partir de la referencia de depósito con la que el agregador etiquetó el abono, en vez de que una persona identifique cada comprobante. Nace en modo sombra —propone y tú confirmas— porque en qué campo del reporte viaja la referencia todavía no está medido. En el API, el estado de cuenta gana en deposits los campos attributed_count, attributed_claimed_minor y manual_count: cuánto de lo que recibiste entró solo. La configuración vive en la consola (Recargas → Depósitos de tus clientes), no en /v1.Aditivo
2026-09-20Cierre a revisión de una recarga: failure_code: "absent_from_report" (valor nuevo) con outcome: "undetermined", settled: false, safe_to_retry: false y el campo nuevo needs_review, más la relectura de los reportes de los días siguientes — ver el aviso arriba.Aditivo
2026-09-20Programa varios agregadores de recargas: respaldo entre agregadores (attempts[], attempt_count, failure_code; dos columnas al final del CSV), ruteo por salud, saldo y prioridad (attempts[].routing.evaluated[]; prioridad y vista previa en el tablero) y cuadre por agregador (by_connector[] y ?connector_key= en estado de cuenta, CSV y listado; recharge.connector_key_unknown) — ver el aviso arriba.Aditivo
2026-09-18La Idempotency-Key se identifica por (cuenta, ambiente, llave) en toda ruta que mueve dinero o timbra — ver el aviso completo arriba.Corrección
2026-09-18Reintentar y cancelar un comprobante cruza el ambiente contra el comprobante, no solo contra tu perfil; la global de pruebas ya no bloquea la global real del período.Corrección
2026-09-18POST /v1/recharge-transfers (traspaso de saldo entre tus bolsas) y GET /v1/recharges/bag-movements (historial de movimientos, incluidos depósitos).Aditivo
2026-07-08Infraestructura de plataforma: Winal Connect (split/marketplace), Payouts/dispersión, Onboarding KYC/KYB, pago de servicios, BNPL, tokenización de red y card-present.Aditivo
2026-07-08Antifraude explicable, card-on-file / cobro 1-click, cobranza inteligente, conciliación bancaria y multisucursal/multicaja.Aditivo
2026-07-07Facturación CFDI 4.0 (PUE y PPD/REP), ruteo por costo con informe de ahorro, pólizas CONTPAQi/Aspel, propinas + corte de caja y CLI winal.Aditivo
2026-07-07Métodos ampliados y más conectores; metadata del intent en PaymentIntentResponse y en data.metadata del webhook.Aditivo
2026-07-07Disputas/contracargos, Payment Links + checkout hosteado (/pay/{slug}), suscripciones y SDKs oficiales C#/TS/PHP/Python.Aditivo
2026-07-01api_version base: payment intents, confirmación pública con client_secret, webhooks firmados y envelope de error estándar.Base

Fase 0, modo prueba: el API está estable y probado de extremo a extremo; la única marca de api_version en circulación es 2026-07-01. Este changelog crecerá con cada versión con fecha que publiquemos.