Saltar al contenido
iRoamly Shop

Notificaciones Webhook

Usa webhooks para recibir en tu aplicación los resultados de entrega de códigos QR y de renovaciones.

Notificaciones Webhook

Introducción

Usa webhooks para recibir en tu aplicación los resultados de entrega de códigos QR y de renovaciones.

¿Qué es un webhook?

iRoamly envía notificaciones de webhook con los resultados de entrega de códigos QR y de renovaciones. Cada webhook usa HTTPS e incluye un payload JSON. Usa los webhooks para:

  • Recibir la información del código QR tras convertir un código de canje o completar una compra directa de código QR.
  • Recibir los resultados de las renovaciones por webhook: esim.renewal.success cuando el código QR de la renovación está listo y esim.renewal.failed cuando falla el pedido de renovación con el proveedor.

Si tu endpoint no responde con un estado 2xx, iRoamly realiza hasta 5 intentos de entrega en total: el primero de inmediato y los reintentos a los 30 segundos, 2 minutos, 3 minutos y 5 minutos.

Pasos para recibir un webhook

Puedes empezar a recibir eventos en tiempo real en tu aplicación con estos pasos:

  • Crea un endpoint local para recibir las solicitudes
  • Registra tu endpoint de webhook en Desarrolladores > Notificaciones Webhook en el Panel de iRoamly Shop

1. Crea un endpoint local para recibir las solicitudes

En tu aplicación local, crea una nueva ruta que acepte solicitudes POST.

Por ejemplo, puedes añadir una ruta de API en Next.js:

typescript
import type { NextApiRequest, NextApiResponse } from 'next';

export default (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === 'POST') {
    const payload = req.body;
    console.log(payload);
    res.status(200);
  }
};

Al recibir un evento, debes responder con HTTP 200 OK para indicar a iRoamly que el evento se entregó correctamente.

2. Registra tu endpoint de webhook de desarrollo

Registra tu URL HTTPS de acceso público en el Panel de iRoamly Shop.

Puedes crear un túnel hacia tu servidor localhost con una herramienta como ngrok.

Página Notificaciones Webhook del Panel con el panel “New webhook” abierto: campo Webhook URL y estado Enabled / Disabled

3. Comprueba que tu endpoint de webhook funciona correctamente

Convierte un código de canje de prueba en código QR, o haz una compra directa de código QR, para comprobar que tu endpoint de webhook recibe el evento.

Notificaciones Webhook

Tipos de evento

Lista de los tipos de evento admitidos y sus payloads.

Tipo de eventoSe envía cuandoNotas
esim.qrcodeSe ha convertido un código de canje en código QR o se ha completado una compra directa de código QR.Sin cambios. isrenew siempre es 0.
esim.renewal.successUna renovación se ha completado y el código QR del código de renovación está listo.Nuevo. Las renovaciones ya no envían esim.qrcode.
esim.renewal.failedUna renovación ha fallado porque no se pudo realizar el pedido con el proveedor.Nuevo. Solo se envía cuando falla el pedido con el proveedor.

Entrega

Todos los eventos se entregan de la misma forma: una solicitud POST con un body JSON a cada endpoint suscrito al evento. Cualquier respuesta 2xx cuenta como entregada; si no, se reintenta, hasta 5 intentos en total (el primero de inmediato y los reintentos a los 30 segundos, 2 minutos, 3 minutos y 5 minutos). Cada solicitud incluye estos headers:

HeaderDescripciónTipo
X-Webhook-EventTipo de evento: esim.qrcode, esim.renewal.success o esim.renewal.failed.String
X-Webhook-DeliveryID de la entrega.String
X-Webhook-TimestampMomento en que se firmó la solicitud, en segundos Unix.String
X-Webhook-Signaturesha256= seguido del HMAC-SHA256 en hexadecimal del body sin procesar de la solicitud.String
X-Webhook-Signature-V2v1= seguido del HMAC-SHA256 en hexadecimal de "{timestamp}.{body}". Durante una rotación del secreto contiene varios valores v1= separados por comas.String

Consulta Verificar las solicitudes de webhook para saber cómo comprobar las firmas.

esim.qrcode

Información del código QR de la eSIM que se devuelve tras canjear o comprar el código QR de la eSIM.

Body de solicitud de ejemplo

json
{
	"code": 0,
	"data": {
		"activation_code": "CD112885573C49DDA42F64C905B925F4",
		"code": "UtTpoKCe769u2tt",
		"create_at": "2025-09-01 11:34:30",
		"isrenew": 0,
		"order_id": "ESIM202509021134343282",
		"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
		"qrcode": "https://www.iroamly.com/qrcode/20250901/xSQfryvOWo0QUhsGcbpeTm9wWYfGu9BQ.png",
		"qrcode_content": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
		"sm_dp_address": "rsp1.cmlink.com"
	},
	"event_type": "esim.qrcode"
	}
Notificaciones Webhook

esim.renewal.success

Se envía cuando una renovación se completa: en cuanto el proveedor devuelve los datos de descarga del pedido de renovación, se genera el código QR del código de renovación y su status pasa a 2 (Canjeado).

Headers de la solicitud

X-Webhook-Event:esim.renewal.success

La solicitud también incluye X-Webhook-Delivery, X-Webhook-Timestamp, X-Webhook-Signature y X-Webhook-Signature-V2, como todos los eventos (consulta Tipos de evento).

Body de solicitud de ejemplo

json
{
	"code": 0,
	"data": {
		"activation_code": "CD112885573C49DDA42F64C905B925F4",
		"code": "RnB7xTq2Lm9pQaZ",
		"create_at": "2026-10-28 09:12:41",
		"download_url": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
		"iccid": "8944501234567890123",
		"iscouldrenewal": 1,
		"isrenew": 1,
		"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
		"qrcode": "https://www.iroamly.com/qrcode/20261028/xSQfryvOWo0QUhsGcbpeTm9wWYfGu9BQ.png",
		"qrcode_content": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
		"renew_order_id": "TG202610280912410001",
		"renewal_father_code": "UtTpoKCe769u2tt",
		"sm_dp_address": "rsp1.cmlink.com"
	},
	"event_type": "esim.renewal.success"
}

Campos

CampoDescripciónTipo
codeSiempre 0.Int
event_typeesim.renewal.successString
data.codeEl nuevo código de canje generado para esta renovación. Úsalo con Query QR Code (qrcodeQuery) o para volver a renovar.String
data.renewal_father_codeEl código de canje original (principal) que se renovó.String
data.renew_order_idID del pedido de renovación del proveedor.String
data.plan_nameNombre del plan de renovación.String
data.qrcodeURL de la imagen del código QR.String
data.qrcode_contentCadena LPA; se puede importar directamente.String
data.sm_dp_addressDirección SM-DP+.String
data.activation_codeCódigo de activación.String
data.iccidICCID. Puede estar vacío.String
data.download_urlCadena de descarga devuelta por el proveedor.String
data.create_atFecha de creación: hora del servidor, en formato YYYY-MM-DD HH:mm:ss.String
data.isrenewSiempre 1.Int
data.iscouldrenewalIndica si el nuevo código de canje se puede volver a renovar: 1 - se puede renovar 2 - no se puede renovar 3 - caducadoInt
Notificaciones Webhook

esim.renewal.failed

Se envía cuando una renovación falla: el proveedor responde al pedido de renovación con un código distinto de 0000, o la solicitud al proveedor falla.

(Nota: si el proveedor no envía la respuesta o la envía tarde, este evento no se activa. Define un tiempo de espera y, como alternativa, consulta el código: consulta Gestionar los eventos de renovación.)

Headers de la solicitud

X-Webhook-Event:esim.renewal.failed

La solicitud también incluye X-Webhook-Delivery, X-Webhook-Timestamp, X-Webhook-Signature y X-Webhook-Signature-V2, como todos los eventos (consulta Tipos de evento).

Body de solicitud de ejemplo

json
{
	"code": -1,
	"data": {
		"code": "RnB7xTq2Lm9pQaZ",
		"create_at": "2026-10-28 09:12:41",
		"error_msg": "TuGe_RenewOrderEx RespCode: 9999",
		"isrenew": 1,
		"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
		"renewal_father_code": "UtTpoKCe769u2tt"
	},
	"event_type": "esim.renewal.failed"
}

Campos

CampoDescripciónTipo
codeSiempre -1.Int
event_typeesim.renewal.failedString
data.codeEl código de renovación generado para este intento. No se aprovisionó y no tiene código QR.String
data.renewal_father_codeEl código de canje original (principal) que se iba a renovar.String
data.plan_nameNombre del plan de renovación.String
data.error_msgError devuelto por el proveedor, para diagnosticar problemas.String
data.create_atFecha de creación: hora del servidor, en formato YYYY-MM-DD HH:mm:ss.String
data.isrenewSiempre 1.Int
Notificaciones Webhook

Renovaciones y esim.qrcode

Las renovaciones ya no se entregan como esim.qrcode; ese evento se envía para las conversiones en código QR y las compras directas de código QR. En comparación con el payload de esim.qrcode:

  • event_type y el header X-Webhook-Event son esim.renewal.success o esim.renewal.failed, e isrenew es 1.
  • data.code es el nuevo código de canje creado por la renovación; el código que se renovó es data.renewal_father_code.
  • esim.renewal.success añade renew_order_id, renewal_father_code, iscouldrenewal, download_url e iccid, y no incluye order_id.
  • Una renovación fallida se notifica con esim.renewal.failed, con code de nivel superior -1 y el error del proveedor en data.error_msg.
Notificaciones Webhook

Suscripciones a eventos

Los endpoints nuevos se suscriben por defecto a los tres eventos. Los endpoints existentes reciben esim.renewal.success y esim.renewal.failed automáticamente: no hace falta ningún cambio.

Notificaciones Webhook

Gestionar los eventos de renovación

  • Haz que tu handler sea idempotente. Un reintento puede entregar el mismo evento más de una vez, así que elimina duplicados por X-Webhook-Delivery o por event_type + data.code, e ignora los eventos que ya hayas procesado.
  • Usa un tiempo de espera como alternativa. Si no llega ni esim.renewal.success ni esim.renewal.failed en un tiempo razonable, consulta el código con la API de consulta (por ejemplo, Query QR Code) en lugar de suponer que la renovación falló.
  • No uses esim.renewal.failed para decidir reembolsos. Solo indica que falló el pedido con el proveedor; si se devuelven los créditos y cuándo se decide por separado, así que no abones importes a tus clientes en función de este evento.
Notificaciones Webhook

Verificar las solicitudes de webhook

Verifica la firma de iRoamly en las solicitudes de webhook.

¿Cómo verificar la firma de iRoamly?

La firma de iRoamly se envía en el header X-Webhook-Signature de la solicitud del webhook, como sha256= seguido de la firma codificada en hexadecimal. La firma se genera con el algoritmo HMAC-SHA256, usando el secreto del webhook como clave y el body sin procesar de la solicitud (tal como se recibe, antes de cualquier análisis JSON) como mensaje.

Header de webhook de ejemplo

json
{
'X-Webhook-Signature': 'sha256=dd7bdd2cf1f6bac6e171c6c508c157b7cd3cc1fd196394277fb59ba0bdd9b87b'
}

Encontrarás el secreto de tu webhook en Desarrolladores > Notificaciones Webhook en el Panel.

Página Notificaciones Webhook del Panel: endpoint del webhook con su URL y el secreto de firma (Reveal), y el historial de entregas

Para generar la firma, puedes usar el siguiente fragmento de código:

typescript
import * as crypto from 'crypto';

  generateSignature(payload: string, secret: string): string {
    const computedSignature = crypto
      .createHmac('sha256', secret)
      .update(payload)
      .digest('hex');
    return 'sha256=' + computedSignature;
  }

En el fragmento de código anterior, payload es el body sin procesar de la solicitud y secret es el secreto del webhook. Basta con comparar la firma generada (incluido el prefijo sha256=) con el valor del header X-Webhook-Signature para completar la verificación.

Firma con marca de tiempo (X-Webhook-Signature-V2)

Cada solicitud también incluye X-Webhook-Signature-V2: v1= seguido del HMAC-SHA256 codificado en hexadecimal, con el mismo secreto del webhook, de {timestamp}.{body}: el valor del header X-Webhook-Timestamp, un punto y el body sin procesar de la solicitud.

Después de rotar el secreto del webhook, el secreto anterior sigue siendo válido durante 24 horas. Durante ese periodo, X-Webhook-Signature se sigue firmando con el secreto anterior y X-Webhook-Signature-V2 incluye un valor por secreto, separados por comas (v1=<old>,v1=<new>): acepta la solicitud si alguno de los valores coincide.