Inyo

Webhooks

Los webhooks entregan notificaciones en tiempo real a su servidor cuando un pago cambia de estado. En lugar de consultar la API en busca de actualizaciones, su sistema recibe una solicitud POST que describe el cambio.


Configuración de webhooks

Los endpoints de webhook se configuran durante el onboarding del comercio. Contacte al equipo de Inyo para:

  1. Proporcionar su(s) URL(s) de webhook
  2. Configurar la autenticación (Basic auth)

Payloads de los eventos

Cada cambio de estado se envía como una solicitud POST a su URL de webhook, con Content-Type: application/json. El campo event indica qué tipo de pago cambió — PULL, PUSH o CHECK. Los campos de todos los eventos:

CampoTipoNotas
agentIdstringIdentificador de su agente
eventstringPULL, PUSH o CHECK
statusstringEstado del pago después del cambio. Mismo valor que newStatus
statusCodestring00 aprobado, 99 rechazado
statusDescriptionstringDescripción legible del cambio o del motivo del rechazo
paymentIduuidIdentificador del pago en Inyo
externalPaymentIdstringEl externalPaymentId enviado al crear el pago
amountobject{ "total": number, "currency": string } — monto y moneda de origen (ISO 4217)
recipientAmountobjectSolo PUSH. { "total": number, "currency": string } — monto entregado al destinatario, presente cuando el pago tiene conversión de moneda
eventDatestringMomento en que se generó la notificación, ISO 8601 en UTC
oldStatusstring | nullEstado del pago antes del cambio
newStatusstringEstado del pago después del cambio

1. PULL

Se dispara cuando un pago pull es autorizado, capturado, desafiado, rechazado, anulado o reembolsado.

{
  "agentId": "YOUR.AGENT",
  "event": "PULL",
  "status": "AUTHORIZED",
  "statusCode": "00",
  "statusDescription": "Payment authorized successfully",
  "paymentId": "469670e2-31e3-4700-b9f2-abee99418dc4",
  "externalPaymentId": "order-12345",
  "amount": {
    "total": 95.00,
    "currency": "USD"
  },
  "eventDate": "2026-10-08T16:31:02.120Z",
  "oldStatus": "PENDING",
  "newStatus": "AUTHORIZED"
}

Valores de estado: PENDING, AUTHORIZED, CAPTURED, CHALLENGE, DECLINED, VOIDED, REFUNDED.

flowchart TD
    P[PENDING] -->|3DS| C[CHALLENGE]
    P --> A[AUTHORIZED]
    P -->|capture: true| K[CAPTURED]
    P -->|rechazado| D[DECLINED]
    C --> A
    C -->|rechazado| D
    A -->|captura| K
    A -->|void| V[VOIDED]
    K -->|reembolso| R[REFUNDED]

Con capture: true el pago pasa directo a CAPTURED; sin él, se queda en AUTHORIZED hasta que lo capture o anule. DECLINED, VOIDED y REFUNDED son finales.

2. PUSH

Se dispara cuando un pago push es aceptado, pagado o rechazado. La creación responde PENDING y el resultado llega después por webhook.

{
  "agentId": "YOUR.AGENT",
  "event": "PUSH",
  "status": "CAPTURED",
  "statusCode": "00",
  "statusDescription": "Payment captured successfully",
  "paymentId": "c9036407-555a-46ed-a602-e8179857b28f",
  "externalPaymentId": "payout-12345",
  "amount": {
    "total": 98.20,
    "currency": "USD"
  },
  "recipientAmount": {
    "total": 1775.00,
    "currency": "MXN"
  },
  "eventDate": "2026-10-08T18:30:10.935Z",
  "oldStatus": "AUTHORIZED",
  "newStatus": "CAPTURED"
}

Valores de estado: PENDING, AUTHORIZED, CAPTURED, DECLINED.

flowchart TD
    A[PENDING<br/>push aceptado] -->|destinatario pagado| B[AUTHORIZED]
    B --> C[CAPTURED<br/>fondos entregados]
    A -->|rechazado| D[DECLINED]

Un push exitoso envía dos webhooks en secuencia, AUTHORIZED y luego CAPTURED. Trate CAPTURED como el éxito final y DECLINED como el fallo final; en un rechazo, statusDescription trae el motivo.

3. CHECK

Se dispara cuando termina una verificación de Check Card Account. No se mueven fondos.

{
  "agentId": "YOUR.AGENT",
  "event": "CHECK",
  "status": "AUTHORIZED",
  "statusCode": "00",
  "statusDescription": "Payment authorized successfully",
  "paymentId": "5b0e2f4c-8d1a-4c7e-9a33-2f6b1d0e7c58",
  "externalPaymentId": "check-12345",
  "amount": {
    "total": 0.00,
    "currency": "USD"
  },
  "eventDate": "2026-10-08T14:02:44.508Z",
  "oldStatus": "CHALLENGE",
  "newStatus": "AUTHORIZED"
}

Valores de estado: AUTHORIZED (tarjeta verificada), CHALLENGE, DECLINED, VOIDED.


Entrega y confiabilidad

  • Autenticación: cuando Basic auth está configurado, cada entrega lleva Authorization: Basic <credenciales>. Valídelo en cada solicitud. Las entregas no están firmadas.
  • Reintentos: las respuestas distintas de 2xx y los timeouts se reintentan hasta el límite de intentos configurado para su cuenta. Responda 2xx de inmediato y procese de forma asíncrona.
  • Duplicados: los reintentos pueden entregar la misma notificación más de una vez. Use (paymentId, newStatus) como clave en su manejador y trate las repeticiones como no-op.
  • Orden: no está garantizado, y eventDate se define cuando se genera la notificación, no cuando cambió el estado. Si la secuencia importa, compare el oldStatus recibido con el estado que tiene guardado; si no coincide, ignore la entrega y concilie con una consulta.
  • Fuente de verdad: el webhook es una notificación, no el pago completo. Confirme el estado — y lea datos de tarjeta, facturación o comisiones — con el endpoint GET de pago antes de completar pedidos.

Ejemplo de manejador (Node.js)

app.post('/webhooks/inyo', async (req, res) => {
  // Confirma de inmediato
  res.status(200).send('OK');

  const notification = req.body;
  const { externalPaymentId, paymentId, event, newStatus } = notification;
  if (await alreadyProcessed(paymentId, newStatus)) return;

  switch (newStatus) {
    case 'AUTHORIZED':
      markAsAuthorized(externalPaymentId);
      break;
    case 'CAPTURED':
      // PULL: fondos liquidados — completa el pedido. PUSH: destinatario pagado.
      event === 'PUSH'
        ? markPayoutDelivered(externalPaymentId)
        : fulfillOrder(externalPaymentId);
      break;
    case 'DECLINED':
      notifyDecline(externalPaymentId, notification.statusDescription);
      break;
    case 'VOIDED':
      cancelOrder(externalPaymentId);
      break;
    case 'REFUNDED':
      processRefund(externalPaymentId, notification.amount.total);
      break;
  }

  await markProcessed(paymentId, newStatus);
});