imagy-notifications — API Reference
Endpoints Publicos (via Gateway)
Todos requieren autenticacion JWT.
Envio de Notificaciones
| Metodo | Endpoint | Rol requerido | Descripcion |
|---|---|---|---|
POST | /api/v1/notifications/send | operator, system | Enviar notificacion por canal(es) especifico(s) (async) |
POST | /api/v1/notifications/dispatch | operator, system | Enviar notificacion con resolucion automatica de canales (async) |
POST | /api/v1/notifications/bulk | operator, system | Enviar notificacion masiva |
OTP (One-Time Password)
| Metodo | Endpoint | Rol requerido | Descripcion |
|---|---|---|---|
POST | /api/v1/notifications/otp/send | operator, system | Enviar codigo OTP (sync) |
POST | /api/v1/notifications/otp/verify | operator, system | Verificar codigo OTP (sync) |
Plantillas
| Metodo | Endpoint | Rol requerido | Descripcion |
|---|---|---|---|
GET | /api/v1/notifications/templates | tenant_admin, operator | Listar plantillas (paginado) |
POST | /api/v1/notifications/templates | tenant_admin | Crear plantilla |
GET | /api/v1/notifications/templates/{id} | tenant_admin, operator | Obtener plantilla |
PATCH | /api/v1/notifications/templates/{id} | tenant_admin | Actualizar plantilla |
DELETE | /api/v1/notifications/templates/{id} | tenant_admin | Desactivar plantilla |
Logs de Notificaciones
| Metodo | Endpoint | Rol requerido | Descripcion |
|---|---|---|---|
GET | /api/v1/notifications/logs | tenant_admin, operator | Consultar notificaciones enviadas (paginado, filtrable) |
GET | /api/v1/notifications/logs/{id} | tenant_admin, operator | Detalle de una notificacion enviada |
Configuracion de Canales (Platform Admin)
| Metodo | Endpoint | Rol requerido | Descripcion |
|---|---|---|---|
GET | /api/v1/notifications/channels | platform_admin, tenant_admin | Listar canales configurados |
POST | /api/v1/notifications/channels | platform_admin | Configurar canal para tenant |
PATCH | /api/v1/notifications/channels/{id} | platform_admin | Actualizar configuracion de canal |
DELETE | /api/v1/notifications/channels/{id} | platform_admin | Desactivar canal |
POST | /api/v1/notifications/channels/{id}/test | platform_admin | Enviar notificacion de prueba |
Endpoints Internos (servicio-a-servicio)
Invocados por otros servicios de la plataforma con JWT propagado y header X-Internal-Service.
| Metodo | Endpoint | Consumidor | Descripcion |
|---|---|---|---|
POST | /api/v1/notifications/send | ImagFlow, ImagLend, ImagSign | Enviar notificacion por canal(es) explicito(s) |
POST | /api/v1/notifications/dispatch | ImagFlow, ImagLend, ImagSign | Enviar con resolucion automatica de canales |
POST | /api/v1/notifications/otp/send | ImagSign, ImagLend, ImagID | Enviar OTP |
POST | /api/v1/notifications/otp/verify | ImagSign, ImagLend, ImagID | Verificar OTP |
Ejemplos de Request/Response
Enviar Notificacion — Canal Unico (modo basico)
Envio asincronico de una notificacion usando una plantilla configurada por un canal especifico. El caller indica exactamente que template, canal y destinatario usar.
POST /api/v1/notifications/send
Content-Type: application/json
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
Authorization: Bearer {jwt}{
"template_code": "loan_approved",
"channel": "sms",
"recipient": "+593991234567",
"variables": {
"borrower_name": "Maria Garcia",
"amount": "5,000.00",
"currency": "USD",
"loan_id": "LOAN-2026-001"
},
"metadata": {
"origin_service": "imaglend",
"origin_reference": "loan-uuid-001"
}
}Response 202:
{
"data": {
"id": "notif-uuid-001",
"status": "queued",
"template_code": "loan_approved",
"channel": "sms",
"recipient": "+593991234567",
"queued_at": "2026-05-18T10:30:00Z"
},
"metadata": {
"request_id": "req-abc123",
"timestamp": "2026-05-18T10:30:00Z"
}
}Enviar Notificacion — Multi-Canal (canales explicitos)
El campo channel acepta un string (un canal) o un array (multiples canales). Cuando es array, el servicio busca la plantilla para cada canal y despacha a todos.
POST /api/v1/notifications/send
Content-Type: application/json
Idempotency-Key: 770e8400-e29b-41d4-a716-446655440010
Authorization: Bearer {jwt}{
"template_code": "loan_approved",
"channel": ["sms", "email", "push"],
"recipients": {
"sms": "+593991234567",
"email": "maria.garcia@email.com",
"push": "device-token-fcm-xyz"
},
"variables": {
"borrower_name": "Maria Garcia",
"amount": "5,000.00",
"currency": "USD",
"loan_id": "LOAN-2026-001",
"portal_url": "https://portal.fintech-abc.reimaginetech.io/loans/LOAN-2026-001"
},
"metadata": {
"origin_service": "imaglend",
"origin_reference": "loan-uuid-001"
}
}Response 202:
{
"data": {
"batch_id": "batch-uuid-010",
"dispatches": [
{ "id": "notif-uuid-010", "channel": "sms", "status": "queued" },
{ "id": "notif-uuid-011", "channel": "email", "status": "queued" },
{ "id": "notif-uuid-012", "channel": "push", "status": "queued" }
],
"queued_at": "2026-05-18T10:30:00Z"
},
"metadata": {
"request_id": "req-multi-001",
"timestamp": "2026-05-18T10:30:00Z"
}
}Reglas multi-canal:
- Si no existe plantilla para un canal especificado, ese canal se salta (no falla el request completo)
- Si el canal no esta activo para el tenant, se salta
- El response indica el status de cada canal individualmente
- Cada despacho genera su propio registro en
notification_logs
Enviar Notificacion — Dispatch (resolucion automatica de canales)
El endpoint /dispatch es el modo declarativo: el caller dice "notifica a este usuario sobre este evento" y el servicio resuelve automaticamente por que canales enviar, basandose en la configuracion del tenant y las preferencias del destinatario.
POST /api/v1/notifications/dispatch
Content-Type: application/json
Idempotency-Key: 880e8400-e29b-41d4-a716-446655440020
Authorization: Bearer {jwt}{
"template_code": "loan_approved",
"subject_id": "subj-uuid-001",
"variables": {
"borrower_name": "Maria Garcia",
"amount": "5,000.00",
"currency": "USD",
"loan_id": "LOAN-2026-001",
"portal_url": "https://portal.fintech-abc.reimaginetech.io/loans/LOAN-2026-001"
},
"metadata": {
"origin_service": "imaglend",
"origin_reference": "loan-uuid-001"
}
}Response 202:
{
"data": {
"dispatch_id": "dispatch-uuid-020",
"resolved_channels": ["sms", "email"],
"skipped_channels": {
"push": "no_device_token",
"whatsapp": "channel_not_configured"
},
"dispatches": [
{ "id": "notif-uuid-020", "channel": "sms", "recipient": "+593991234567", "status": "queued" },
{ "id": "notif-uuid-021", "channel": "email", "recipient": "maria.garcia@email.com", "status": "queued" }
],
"queued_at": "2026-05-18T10:30:00Z"
},
"metadata": {
"request_id": "req-dispatch-001",
"timestamp": "2026-05-18T10:30:00Z"
}
}Logica de resolucion del dispatch:
Resolucion de destinatario por canal:
| Canal | Fuente del destinatario |
|---|---|
sms | subject.phone o user.phone |
email | subject.email o user.email |
whatsapp | subject.phone (mismo que SMS) |
push | subject_devices con push_token activo |
webhook | notification_channels.config.endpoint_url del tenant |
Diferencias entre /send y /dispatch:
| Aspecto | /send | /dispatch |
|---|---|---|
| Canal | Caller lo especifica (string o array) | Servicio lo resuelve automaticamente |
| Destinatario | Caller lo proporciona | Servicio lo busca por subject_id |
| Control | Total — el caller decide todo | Delegado — el servicio decide canales |
| Cuando usar | Integraciones especificas, OTP, envios puntuales | Notificaciones de negocio (aprobacion, rechazo, mora) |
| Fallo parcial | Falla si el canal no existe | Salta canales no disponibles (nunca falla por canal) |
Enviar Notificacion por Email
POST /api/v1/notifications/send
Content-Type: application/json
Idempotency-Key: 660e8400-e29b-41d4-a716-446655440001
Authorization: Bearer {jwt}{
"template_code": "loan_approved",
"channel": "email",
"recipient": "maria.garcia@email.com",
"variables": {
"borrower_name": "Maria Garcia",
"amount": "5,000.00",
"currency": "USD",
"loan_id": "LOAN-2026-001",
"portal_url": "https://portal.fintech-abc.reimaginetech.io/loans/LOAN-2026-001"
}
}Response 202:
{
"data": {
"id": "notif-uuid-002",
"status": "queued",
"template_code": "loan_approved",
"channel": "email",
"recipient": "maria.garcia@email.com",
"queued_at": "2026-05-18T10:31:00Z"
},
"metadata": {
"request_id": "req-def456",
"timestamp": "2026-05-18T10:31:00Z"
}
}Enviar OTP (Sincronico)
Genera un codigo OTP, lo envia por el canal indicado y retorna el identificador para posterior verificacion.
POST /api/v1/notifications/otp/send
Content-Type: application/json
Authorization: Bearer {jwt}
X-Internal-Service: imagy-sign{
"channel": "sms",
"destination": "+593991234567",
"purpose": "signature_otp",
"origin_service": "imagsign",
"origin_reference": "sr-uuid-001",
"locale": "es"
}Response 200:
{
"data": {
"otp_id": "otp-uuid-001",
"channel": "sms",
"masked_destination": "+5939912***67",
"expires_in_seconds": 300,
"max_attempts": 3
},
"metadata": {
"request_id": "req-ghi789",
"timestamp": "2026-05-18T10:32:00Z"
}
}Verificar OTP (Sincronico)
Valida el codigo ingresado por el usuario contra el OTP generado.
POST /api/v1/notifications/otp/verify
Content-Type: application/json
Authorization: Bearer {jwt}
X-Internal-Service: imagy-sign{
"otp_id": "otp-uuid-001",
"code": "847291"
}Response 200 (verificacion exitosa):
{
"data": {
"verified": true,
"otp_id": "otp-uuid-001",
"verified_at": "2026-05-18T10:33:00Z"
},
"metadata": {
"request_id": "req-jkl012",
"timestamp": "2026-05-18T10:33:00Z"
}
}Response 200 (codigo incorrecto):
{
"data": {
"verified": false,
"otp_id": "otp-uuid-001",
"attempts_remaining": 2,
"reason": "invalid_code"
},
"metadata": {
"request_id": "req-mno345",
"timestamp": "2026-05-18T10:33:15Z"
}
}Response 200 (OTP expirado):
{
"data": {
"verified": false,
"otp_id": "otp-uuid-001",
"attempts_remaining": 0,
"reason": "expired"
},
"metadata": {
"request_id": "req-pqr678",
"timestamp": "2026-05-18T10:40:00Z"
}
}Envio Masivo (Bulk)
Envia la misma plantilla a multiples destinatarios. Util para campanas o alertas masivas.
POST /api/v1/notifications/bulk
Content-Type: application/json
Idempotency-Key: 770e8400-e29b-41d4-a716-446655440002
Authorization: Bearer {jwt}{
"template_code": "payment_reminder",
"channel": "sms",
"recipients": [
{
"destination": "+593991234567",
"variables": {
"borrower_name": "Maria Garcia",
"due_date": "2026-05-25",
"amount": "250.00"
}
},
{
"destination": "+573001234567",
"variables": {
"borrower_name": "Juan Perez",
"due_date": "2026-05-25",
"amount": "180.00"
}
}
],
"metadata": {
"origin_service": "imaglend",
"batch_id": "batch-2026-05-18"
}
}Response 202:
{
"data": {
"batch_id": "batch-uuid-001",
"total_recipients": 2,
"status": "processing",
"queued_at": "2026-05-18T10:35:00Z"
},
"metadata": {
"request_id": "req-stu901",
"timestamp": "2026-05-18T10:35:00Z"
}
}Listar Plantillas
GET /api/v1/notifications/templates?channel=sms&locale=es&page=1&page_size=20
Authorization: Bearer {jwt}Response 200:
{
"data": [
{
"id": "tpl-uuid-001",
"code": "loan_approved",
"channel": "sms",
"locale": "es",
"subject": null,
"body": "Hola {{borrower_name}}, tu credito por {{amount}} {{currency}} ha sido aprobado. Ref: {{loan_id}}",
"variables": ["borrower_name", "amount", "currency", "loan_id"],
"is_active": true,
"created_at": "2026-01-15T08:00:00Z",
"updated_at": "2026-03-10T14:20:00Z"
},
{
"id": "tpl-uuid-002",
"code": "payment_reminder",
"channel": "sms",
"locale": "es",
"subject": null,
"body": "Hola {{borrower_name}}, tu pago de {{amount}} vence el {{due_date}}. Evita recargos.",
"variables": ["borrower_name", "amount", "due_date"],
"is_active": true,
"created_at": "2026-01-15T08:00:00Z",
"updated_at": "2026-01-15T08:00:00Z"
}
],
"pagination": {
"page": 1,
"page_size": 20,
"total_items": 2,
"total_pages": 1
}
}Crear Plantilla
POST /api/v1/notifications/templates
Content-Type: application/json
Authorization: Bearer {jwt}{
"code": "loan_disbursed",
"channel": "email",
"locale": "es",
"subject": "Tu credito ha sido desembolsado - {{loan_id}}",
"body": "<h1>Desembolso Exitoso</h1><p>Hola {{borrower_name}},</p><p>Tu credito por <strong>{{amount}} {{currency}}</strong> ha sido desembolsado a la cuenta {{account_number}}.</p>",
"variables": ["borrower_name", "amount", "currency", "loan_id", "account_number"]
}Response 201:
{
"data": {
"id": "tpl-uuid-003",
"code": "loan_disbursed",
"channel": "email",
"locale": "es",
"is_active": true,
"created_at": "2026-05-18T10:40:00Z"
},
"metadata": {
"request_id": "req-vwx234",
"timestamp": "2026-05-18T10:40:00Z"
}
}Actualizar Plantilla
PATCH /api/v1/notifications/templates/tpl-uuid-001
Content-Type: application/json
Authorization: Bearer {jwt}
If-Match: "v3"{
"body": "Hola {{borrower_name}}, tu credito #{{loan_id}} por {{amount}} {{currency}} fue aprobado. Consulta detalles en {{portal_url}}.",
"variables": ["borrower_name", "amount", "currency", "loan_id", "portal_url"]
}Response 200:
{
"data": {
"id": "tpl-uuid-001",
"code": "loan_approved",
"channel": "sms",
"locale": "es",
"body": "Hola {{borrower_name}}, tu credito #{{loan_id}} por {{amount}} {{currency}} fue aprobado. Consulta detalles en {{portal_url}}.",
"variables": ["borrower_name", "amount", "currency", "loan_id", "portal_url"],
"row_version": 4,
"updated_at": "2026-05-18T10:45:00Z"
},
"metadata": {
"request_id": "req-yza567",
"timestamp": "2026-05-18T10:45:00Z"
}
}Consultar Logs de Notificaciones
GET /api/v1/notifications/logs?channel=sms&status=delivered&from=2026-05-01&to=2026-05-18&page=1&page_size=50
Authorization: Bearer {jwt}Response 200:
{
"data": [
{
"id": "notif-uuid-001",
"template_code": "loan_approved",
"channel": "sms",
"recipient": "+593991234567",
"status": "delivered",
"provider": "twilio",
"provider_message_id": "SM1234567890abcdef",
"sent_at": "2026-05-18T10:30:01Z",
"delivered_at": "2026-05-18T10:30:03Z",
"metadata": {
"origin_service": "imaglend",
"origin_reference": "loan-uuid-001"
}
}
],
"pagination": {
"page": 1,
"page_size": 50,
"total_items": 1,
"total_pages": 1
}
}Formato de Entrega Webhook
Cuando el canal configurado es webhook, imagy-notifications realiza un HTTP POST al endpoint configurado por el tenant. El formato de entrega es el siguiente:
Request al Endpoint del Tenant
POST https://api.cliente.com/webhooks/notifications
Content-Type: application/json
X-Webhook-Signature: sha256=abc123def456...
X-Webhook-Timestamp: 1716030000
X-Webhook-Id: notif-uuid-003{
"id": "notif-uuid-003",
"event_type": "notification.sent",
"timestamp": "2026-05-18T10:30:00Z",
"data": {
"template_code": "loan_approved",
"channel": "webhook",
"recipient": "https://api.cliente.com/webhooks/notifications",
"variables": {
"borrower_name": "Maria Garcia",
"amount": "5,000.00",
"currency": "USD",
"loan_id": "LOAN-2026-001"
},
"rendered_body": "Hola Maria Garcia, tu credito por 5,000.00 USD ha sido aprobado. Ref: LOAN-2026-001",
"metadata": {
"origin_service": "imaglend",
"origin_reference": "loan-uuid-001",
"tenant_id": "tenant-uuid-001"
}
}
}Validacion de Firma (HMAC)
El receptor debe validar la firma HMAC para asegurar la autenticidad del webhook:
signature = HMAC-SHA256(secret, timestamp + "." + body)El header X-Webhook-Signature contiene el prefijo sha256= seguido del hash calculado. El receptor debe:
- Extraer el timestamp de
X-Webhook-Timestamp - Verificar que el timestamp no sea mayor a 5 minutos (replay protection)
- Calcular
HMAC-SHA256(secret, timestamp + "." + raw_body) - Comparar con el valor en
X-Webhook-Signature
Politica de Reintentos (Webhook)
| Intento | Delay | Descripcion |
|---|---|---|
| 1 | Inmediato | Primer envio |
| 2 | 30 segundos | Primer reintento |
| 3 | 2 minutos | Segundo reintento |
| 4 | 10 minutos | Tercer reintento (final) |
Si todos los intentos fallan, el log se marca como failed y se registra la ultima respuesta del endpoint.
Respuesta Esperada del Receptor
El endpoint del tenant debe responder con status 2xx para confirmar recepcion:
{
"received": true
}Cualquier respuesta con status 4xx o 5xx se considera fallo y dispara reintento.
Eventos Consumidos (Notificaciones Automaticas)
imagy-notifications consume eventos del bus de mensajes y dispara notificaciones automaticas basadas en la configuracion de plantillas del tenant.
Mapeo Evento-Plantilla
La relacion entre eventos y plantillas se configura por tenant. Cuando llega un evento, el servicio:
- Busca plantillas asociadas al
event_typepara el tenant - Extrae variables del payload del evento
- Determina el destinatario del payload
- Despacha por los canales configurados
Formato de Evento Consumido
{
"event_id": "evt-uuid-001",
"event_type": "lend.loan.approved",
"tenant_id": "tenant-uuid-001",
"timestamp": "2026-05-18T10:30:00Z",
"payload": {
"loan_id": "LOAN-2026-001",
"borrower_name": "Maria Garcia",
"borrower_email": "maria.garcia@email.com",
"borrower_phone": "+593991234567",
"amount": "5000.00",
"currency": "USD"
},
"metadata": {
"source": "imaglend",
"correlation_id": "corr-uuid-001"
}
}Headers Especiales
| Header | Direccion | Descripcion |
|---|---|---|
Idempotency-Key | Request (POST) | UUID para idempotencia en envios |
If-Match | Request (PATCH) | ETag para concurrencia optimista |
ETag | Response (GET) | Version del recurso |
X-Idempotent-Replayed | Response | true si es respuesta cacheada |
X-Request-Id | Response | ID de trazabilidad |
X-Internal-Service | Request | Identifica servicio interno que invoca |
X-Webhook-Signature | Request/Response (webhook) | Firma HMAC del payload |
X-Webhook-Timestamp | Request/Response (webhook) | Timestamp para replay protection |
X-Webhook-Id | Response (webhook) | ID unico del webhook enviado |
Codigos de Estado
| Status | Cuando |
|---|---|
| 200 | Operacion exitosa (GET, OTP verify) |
| 201 | Recurso creado (plantilla) |
| 202 | Notificacion aceptada y encolada |
| 400 | Validacion fallida (variables faltantes, canal no configurado) |
| 401 | No autenticado |
| 403 | Sin permisos para la operacion |
| 404 | Recurso no encontrado (plantilla, OTP, log) |
| 409 | Conflicto (plantilla duplicada) |
| 412 | ETag mismatch (concurrencia) |
| 422 | Error de procesamiento (proveedor rechazo, destino invalido) |
| 429 | Rate limit excedido (OTP: max 5 por destino en 15 min) |
| 500 | Error interno |
| 502 | Error de comunicacion con proveedor externo |
Rate Limiting
| Operacion | Limite | Ventana |
|---|---|---|
| OTP send (por destino) | 5 solicitudes | 15 minutos |
| OTP verify (por otp_id) | 3 intentos | Vida del OTP |
| Notifications send (por tenant) | 100 solicitudes | 1 minuto |
| Bulk send (por tenant) | 10 solicitudes | 1 minuto |
| Bulk recipients (por request) | 1000 destinatarios | Por request |