Ir directamente al contenido principal

Guía para desarrolladores

Integración de notificaciones de terceros

Contrato actual de autenticación, solicitud, idempotencia, límites, resultados y seguridad.

Inicio rápido

Crea en la administración web una aplicación vinculada a la empresa de destino. Copia su App ID y App Secret y, si necesitas el resultado final, configura un Callback URL opcional.

Engine crea entradas para los usuarios elegidos por el audience opcional (toda la empresa elegible por defecto) y solo intenta el Push del sistema en dispositivos registrados válidos.

Endpoint y autenticación

Entornos de API:

Cada solicitud JSON de servidor a servidor debe incluir Authorization: Basic Base64(KEY:SECRET) mediante HTTP Basic Authentication, donde KEY es el App ID y SECRET es el App Secret:

Endpoint: POST /openapi/v1/notifications.

bash
curl --request POST 'https://<your-engine-host>/openapi/v1/notifications' \
  --header 'Authorization: Basic <Base64(AppID:AppSecret)>' \
  --header 'Content-Type: application/json' \
  --data '{"requestId":"order-20260819-001","title":"Pedido completado","body":"Tu pedido se ha completado.","imageUrls":["https://cdn.example.com/order/001-1.webp","https://cdn.example.com/order/001-2.webp"],"displayFields":[{"label":"Nombre de la tienda","value":"Fideos Xiao Han (Wangjing)"},{"value":"ORD-10086"}],"tags":["Completado","Tienda principal"]}'

Contrato de solicitud

Resumen de campos

CampoObligatorioTipoSignificado
requestIdSístringIdentificador único del emisor y clave de idempotencia. Se recorta y no puede quedar vacío.
titleSístringTítulo de la notificación. Se recorta y no puede quedar vacío.
bodySístringCuerpo de la notificación. Se recorta y no puede quedar vacío.
imageUrlsNostring[]Imágenes del detalle, en orden.
displayFieldsNoobject[]Campos de texto adicionales del detalle, en orden.
tagsNostring[]Etiquetas de plain text mostradas solo en el detalle, en orden.
audienceNoobjectLimita el envío a usuarios o roles; omitido incluye a toda la empresa elegible.

Imágenes: imageUrls

  • Omite el campo, envía null o [] si no hay imágenes; si las hay, envía 1-9 URL en orden.
  • Cada URL se recorta, debe ser única y debe ser una URL HTTPS absoluta sin usuario ni contraseña.
  • Cada URL admite hasta 2048 caracteres Unicode. Una URL no válida rechaza toda la solicitud.
  • Engine guarda las URL, pero no obtiene, comprueba, sirve como proxy ni almacena las imágenes en caché.

Campos de detalle: displayFields

SubcampoObligatorioLímitePresentación
labelNoSe recorta, no puede quedar vacío y admite 32 Unicode caracteresNombre del campo.
valueSíSe recorta, no puede quedar vacío y admite 256 Unicode caracteresValor del campo.
json
{
  "displayFields": [
    { "label": "Tienda", "value": "Little Han Noodles (Wangjing)" },
    { "value": "ORD-10086" }
  ]
}
  • Omitirlo, enviar null o [] significa que no hay filas adicionales; se admiten hasta 10 objetos.
  • Sin label o con label: null, el value ocupa una línea completa.
  • El contenido siempre es plain text; no se admiten HTML, Markdown, enlaces, datos anidados, tipos ni estilos.

Etiquetas del detalle: tags

  • Omite el campo, envía null o [] si no hay etiquetas. Si las hay, envía como máximo 8 strings en orden.
  • Cada etiqueta se recorta y debe tener 1-20 caracteres Unicode. Un valor vacío, no string, demasiado largo o duplicado tras recortarlo rechaza toda la solicitud con INVALID_REQUEST.
  • Las etiquetas son plain text no interactivo, aparecen solo en el detalle y conservan su orden.

Destinatarios: audience

typeSelectorSignificado del ID
USERSuserIdsID de miembro de la empresa
ROLESrolesCompanyRole ID; reciben los miembros válidos de cualquiera de los roles.

Copia el ID de miembro de la empresa desde la lista de miembros de la empresa en Web Admin. El miembro debe pertenecer a la empresa vinculada a la aplicación de terceros.

json
{
  "audience": { "type": "USERS", "userIds": ["companyMemberId"] }
}
json
{
  "audience": { "type": "ROLES", "roles": ["roleId"] }
}
  • Omite audience o envía null para todos los usuarios activos elegibles de la empresa vinculada.
  • La lista admite 1-100 strings originales; los ID se recortan, los vacíos se ignoran y el conjunto se deduplica y ordena.
  • Los IDs inexistentes, inactivos, eliminados o de otra empresa se ignoran; los objetivos válidos restantes reciben el aviso.
  • Un selector válido sin objetivos se acepta y termina con recipientCount=0; nunca vuelve al envío para toda la empresa.
  • El selector no correspondiente puede omitirse o ser null. Mezclas no nulas, types o campos desconocidos, listas ausentes o vacías, valores no string y más de 100 entradas producen INVALID_REQUEST.

Límites e idempotencia

  • El cuerpo completo admite 256 KiB. requestId, title y body admiten 128, 100 y 1000 caracteres Unicode.
  • Cada App ID admite 10 solicitudes por minuto y 100 por hora.
  • Repetir requestId con contenido normalizado equivalente devuelve el resultado guardado. El orden importa para imágenes, campos y tags; no para el conjunto audience.
  • Otro contenido con el mismo requestId devuelve IDEMPOTENCY_CONFLICT. Un resultado terminado puede ser SUCCESS, PARTIAL_SUCCESS o FAILED.

Respuesta de aceptación

Una solicitud válida devuelve HTTP 202:

json
{
  "requestId": "order-20260819-001",
  "notificationId": "00000000-0000-0000-0000-000000000001",
  "status": "ACCEPTED"
}

ACCEPTED solo indica que Engine guardó la solicitud para distribuirla; no confirma que APNs/FCM ni el dispositivo hayan mostrado la notificación.

Resultado del Callback

Con Callback URL configurado, Engine envía un resultado terminal:

json
{
  "requestId": "order-20260819-001",
  "status": "PARTIAL_SUCCESS",
  "recipientCount": 8,
  "pushAcceptedCount": 1,
  "pushFailedCount": 1
}

recipientCount es el número de usuarios destinatarios del centro de notificaciones. pushAcceptedCount y pushFailedCount son recuentos de lotes de Push Outbox, no recuentos de usuarios o dispositivos ni prueba de entrega del banner del sistema.

Prueba de Callback

Cada prueba de Callback del panel de administración envía una sonda distinta:

json
{
  "requestId": "callback-test-<unique-id>",
  "status": "SUCCESS",
  "recipientCount": 1,
  "pushAcceptedCount": 1,
  "pushFailedCount": 0,
  "test": true
}

Cuando test sea true, valida la estructura y responde con 2xx, pero no relaciones la sonda con una solicitud de notificación ni actualices el estado de entrega del negocio. Sus recuentos son valores fijos de prueba, no destinatarios ni lotes reales de Push Outbox.

El status final es SUCCESS, PARTIAL_SUCCESS o FAILED. Responde con cualquier 2xx para confirmarlo.

Si no, Engine reintenta tras 1 minuto, 5 minutos, 30 minutos, 2 horas, 6 horas y 24 horas. Actualmente no hay firma HMAC: exige HTTPS, valida el requestId de los resultados que no sean de prueba, limita la exposición y procesa cada Callback de forma idempotente.

Referencia de errores

HTTPCodeSignificado
400INVALID_REQUESTFalló Content-Type, JSON, tamaño o validación.
401INVALID_APP_CREDENTIALSApp ID o App Secret no válidos.
403APPLICATION_INACTIVELa aplicación o empresa está inactiva.
409IDEMPOTENCY_CONFLICTrequestId se reutilizó con otro contenido.
429RATE_LIMITEDSe superó el límite de la aplicación.
503NOTIFICATION_UNAVAILABLEEl servicio no está disponible temporalmente.

Seguridad y ámbito de envío

  • App ID y App Secret son credenciales entre servidores. No las incluyas en navegador, aplicación móvil, repositorio público, URL ni almacenamiento del cliente. Restablece App Secret si se filtra.
  • Los IDs objetivo privados nunca se escriben en los logs de la aplicación. El selector privado y sus IDs tampoco aparecen en GraphQL, Push, Callback, realtime ni navigation.
  • Sin audience, se incluyen todos los usuarios activos elegibles de la empresa; con audience, solo los objetivos válidos resueltos. Cada destinatario válido recibe una entrada y se cuenta en recipientCount.
  • El Push del sistema solo se intenta en dispositivos con un PushInstallation activo que permita la categoría BUSINESS, sin garantizar un banner en cada dispositivo.
  • La lista completa de imageUrls solo está en el detalle autorizado. Engine puede enviar la primera URL de imageUrls a APNs/FCM para un banner nativo. displayFields y tags no se incluyen en Push ni Callback y son plain text no interactivo; no incluyas secretos, tokens de acceso, datos de pago ni valores sensibles.
  • title y body deben seguir siendo completos y comprensibles sin las imágenes. Un fallo al descargar o mostrar una imagen no cambia el estado de accepted, Callback ni Push.
  • El cliente móvil acepta como máximo 5 MiB por imagen y concede 10 segundos a toda la operación de descarga. No sigue redirecciones 3xx, por lo que cada URL debe devolver la imagen directamente.
  • El cliente móvil descarga cada imagen directamente del CDN público. Usa URL sin autenticación ni cookies, mantenlas disponibles al menos 90 días y considera que el CDN recibe la IP, la hora de solicitud y el User-Agent del usuario.
  • Usa URL de objetos inmutables si necesitas una visualización histórica estable.