Resumen del contrato
- Método y destino:
POSTa una URLhttpsen el puerto 443 u 8443 con nombre DNS público. - Cuerpo: un envoltorio CloudEvents 1.0 en JSON de hasta 256 KiB.
- Firma: HMAC-SHA256 según Standard Webhooks, presente en todo envío con cualquier método de autenticación.
- Éxito: cualquier respuesta
2xx. Significa recepción, no procesamiento de negocio; responda en menos de 5 s y procese de forma asíncrona. - Plazo: 5 s para conectar y 15 s en total, con DNS y TLS incluidos.
- Entrega: al menos una vez. El receptor debe ser idempotente por
webhook-id.
Los tipos de evento están en el catálogo de eventos y la forma de data, en los esquemas JSON. Los códigos de error de la API figuran en Errores.
Envoltorio y formatos
El cuerpo se serializa en JSON canónico: claves ordenadas en todos los niveles y sin espacios. El ejemplo siguiente es la salida real del código de envío de Masnet para un cambio de estado de contrato, con datos ficticios, mostrado con sangría solo por legibilidad.
{
"data": {
"actor": {
"type": "user"
},
"changed_fields": [
"status"
],
"evidence": "masnet_record",
"object": {
"contract_code": "CT-0001",
"id": "2f0c7a2e-6b1d-4e57-9a40-1c3f5d2b8e91",
"status": "active",
"tender": {
"code": "1234-56-LE26"
},
"version": 14
},
"previous": {
"status": "pending_formalization"
}
},
"datacontenttype": "application/json",
"dataschema": "https://masnet.com/developers/schemas/contract/v1.json",
"environment": "test",
"id": "evt_01JBE6Q0Z8B3V4R7T2M9K1N5XH",
"sequence": 14,
"source": "https://daas.masnet.com/api/v1/integrations/companies/0b9e3c1a-7d42-4f0e-8a51-6c2b9d4e7f10",
"specversion": "1.0",
"subject": "contracts/2f0c7a2e-6b1d-4e57-9a40-1c3f5d2b8e91",
"tenantid": "0b9e3c1a-7d42-4f0e-8a51-6c2b9d4e7f10",
"time": "2026-10-28T12:00:00.000Z",
"type": "com.masnet.contract.status_changed.v1"
}| Miembro | Significado |
|---|---|
specversion, datacontenttype | 1.0 y application/json. |
id | Identificador del evento con prefijo evt_. Es el mismo en reintentos y reenvíos, y coincide con webhook-id. |
type | Tipo del catálogo, con la versión mayor al final (.v1). |
source | Origen de la empresa que emite el evento. |
subject | Recurso afectado, con la forma <tipo>/<identificador>. |
time | Instante del hecho en UTC. |
dataschema | Esquema JSON del objeto de data: https://masnet.com/developers/schemas/<objeto>/v1.json. |
tenantid | Identificador de la empresa. |
sequence | Versión del recurso tras el cambio; crece por subject. |
environment | production o test. |
data.object | Representación del recurso con los grupos de campos otorgados al destino (public, business, confidential, people) unidos en un nivel. |
data.previous | Solo los campos cambiados que el permiso otorgado permite ver; puede ser null. |
data.changed_fields | Nombres de los campos que cambiaron y que el destino puede ver. |
data.changed_groups | Solo en catalog_item.updated: grupos de campos que cambiaron dentro del permiso otorgado. |
data.actor | type más, con el grupo people, los datos del actor humano. |
data.evidence | masnet_record, mp_observed o mp_confirmed. |
data.truncated | Presente si una colección de más de 200 elementos se recortó o si el cuerpo habría superado 256 KiB. |
El destino elige uno de dos formatos con el mismo envoltorio: JSON estándar (Content-Type: application/json) y CloudEvents estructurado (Content-Type: application/cloudevents+json). El evento audit.user_actions es la excepción: su data es { "batch": …, "actions": […] }, sin object; se describe en su esquema. Las enumeraciones de estado son abiertas: ignore los valores que no conozca.
Cabeceras de cada envío
| Cabecera | Valor |
|---|---|
Content-Type | application/json o application/cloudevents+json, según el formato del destino. |
User-Agent | Masnet-Webhooks/1.0 (+https://masnet.com/developers/webhooks) |
webhook-id | Identificador del evento (id del cuerpo). Clave de idempotencia. |
webhook-timestamp | Segundos Unix del intento. Se firma junto con el cuerpo. |
webhook-signature | Una o dos firmas v1,<base64> separadas por un espacio. |
masnet-event-type | Tipo del evento, para enrutar sin leer el cuerpo. |
masnet-delivery-attempt | Número del intento, desde 1. |
Según el método de autenticación elegido se agrega además una cabecera Authorization o la cabecera de clave de API que el administrador definió; véase Autenticación hacia su receptor.
Verificación de la firma
Masnet implementa Standard Webhooks. El secreto tiene la forma whsec_ seguido de 32 bytes aleatorios en base64; Masnet lo genera y lo muestra una sola vez.
- Lea el cuerpo sin modificarlo: los bytes recibidos, no una reserialización del JSON.
- Rechace el mensaje si
webhook-timestampdifiere de su reloj en más de 5 minutos (tolerancia recomendada). - Calcule
HMAC-SHA256con clave igual a la decodificación base64 del secreto sin el prefijowhsec_, sobre los byteswebhook-id+.+webhook-timestamp+.+ cuerpo. - Codifique el resultado en base64 y compárelo, en tiempo constante, con cada firma de
webhook-signatureque empiece porv1,. Basta con que una coincida.
Las implementaciones verificadas contra vectores generados con el código de firma de Masnet están en las guías Node.js, Python, Java y C#.
Rotación del secreto
En una rotación planificada el secreto nuevo convive 24 horas con el anterior y cada envío lleva ambas firmas en webhook-signature, separadas por un espacio; el verificador debe aceptar el mensaje si cualquiera coincide. Si el administrador marca un compromiso del secreto, el anterior se revoca de inmediato y no hay superposición.
webhook-signature: v1,S01nQT5xCo7TbAw+szB3vn4tFuJWRq+1Kzf/RQ9r5u4= v1,xcJ6+lQM63rZrPcdOoFUO1JJJYzxs1QY1uW1vUTyp6g=Respuestas y reintentos
| Respuesta del receptor | Efecto en Masnet |
|---|---|
2xx | Entrega exitosa. Se leen como máximo 2 KiB de la respuesta, solo como diagnóstico. |
3xx | No se sigue. Cuenta como fallo y se reintenta; el historial registra la ubicación sin usuario, contraseña, query ni fragmento. |
410 Gone | Definitivo: el destino se desactiva y se cancelan sus entregas abiertas. |
413 | Definitivo para ese evento: se marca como no entregable a ese destino y no se reintenta. |
429 y 503 | Se reintenta. Si trae Retry-After (segundos o fecha HTTP), el destino se pausa hasta esa hora, con un máximo de 1 hora. |
| Cualquier otro código, tiempo agotado, error de conexión o de TLS | Se reintenta según el calendario. |
El calendario ofrece hasta 15 intentos, medidos desde el inicio del ciclo: inmediato, 1 min, 5 min, 15 min, 30 min, 1 h, 2 h, 4 h, 8 h, 12 h, 24 h, 36 h, 48 h, 60 h y 72 h. Ningún intento ocurre después de 72 horas del inicio del ciclo; si se agota, la entrega queda fallida. Un reenvío desde la aplicación abre un ciclo nuevo con el mismo id.
La conexión tiene un plazo de 5 s y la solicitud completa de 15 s. Con un método de autenticación OAuth 2.0, ante un 401 Masnet renueva el token una vez y repite el envío dentro del mismo intento.
Un cuerpo que, aun truncando colecciones, supera 256 KiB no se envía y la entrega queda fallida por tamaño.
Idempotencia, orden y duplicados
- La entrega es al menos una vez: guarde
webhook-idy descarte los repetidos antes de producir efectos. sequencees la versión del recurso y crece porsubject. Descarte un evento cuyosequencesea menor o igual al último que aplicó para esesubject.- El administrador puede activar en el destino la entrega en orden por recurso: entonces cada
subjecttiene a lo sumo una entrega en curso y las siguientes esperan. Sin esa opción el orden se reconstruye consequence. - Un reenvío de un evento antiguo puede llegar después de uno más nuevo;
sequencepermite descartarlo.
Autenticación hacia su receptor
La firma va siempre. Además, el destino puede presentar una credencial. Se configura en la aplicación, por destino.
| Método | Qué envía Masnet |
|---|---|
| Solo firma | Únicamente las cabeceras de firma. |
| Cabecera con clave de API | La cabecera con el nombre que usted defina (letras, dígitos y guiones, de 1 a 64 caracteres) y su valor. No puede reemplazar Host, Content-Type, Content-Length, User-Agent, Authorization, Cookie, Connection, Transfer-Encoding, Proxy-Authorization, webhook-id, webhook-timestamp, webhook-signature, masnet-event-type ni masnet-delivery-attempt. |
| Basic | Authorization: Basic con el usuario y la contraseña. |
| Bearer estático | Authorization: Bearer con el token. |
| OAuth 2.0, credenciales de cliente | Masnet pide un token a su servidor de autorización con grant_type=client_credentials y envía Authorization: Bearer. El token se guarda en memoria hasta el 80 % de su vida (300 s si no informa expires_in; máximo 24 h). |
| mTLS | Un certificado de cliente emitido por Masnet para su destino. |
OAuth 2.0 con secreto de cliente
Masnet autentica al cliente con client_secret_basic (por omisión) o client_secret_post, y puede enviar scope y audience. El servidor de autorización debe responder 200 con access_token y, si informa token_type, que sea Bearer.
OAuth 2.0 con private_key_jwt
Sin secreto de cliente: Masnet firma una aserción JWT (RFC 7523) con una llave propia del destino, con iss y sub iguales al client_id, aud igual al token endpoint, vigencia de 60 s y un jti único. Los algoritmos son RS256 y ES256. La clave pública se publica de dos formas, según lo que admita su servidor de autorización:
- JWKS, para Okta, Auth0, Ping y similares:
https://daas.masnet.com/api/v1/integrations/public/endpoints/{id}/jwks.json. Cada llave incluyex5c. - Certificado X.509 autofirmado con la misma llave, para Microsoft Entra ID:
https://daas.masnet.com/api/v1/integrations/public/endpoints/{id}/oauth-cert.pem. La aserción llevax5t#S256yx5t. El certificado tiene una vigencia de 730 días.
{id} es el identificador del destino que muestra la aplicación. Al rotar la llave se generan una llave y un certificado nuevos, y debe subir el certificado nuevo a su servidor de autorización dentro de la superposición de 24 horas.
mTLS
Masnet presenta un certificado de cliente por destino. Para que su receptor lo valide, confíe en la autoridad certificadora publicada en https://daas.masnet.com/api/v1/integrations/public/mtls-ca.pem. Los certificados se renuevan antes de vencer y durante la superposición el destino conserva ambos.
URL del destino y credenciales en la query
La URL debe usar https, puerto 443 u 8443 y un nombre DNS público; no se admiten usuario en la URL, fragmento, direcciones IP literales ni nombres internos. Se admite una query: plataformas como Azure Logic Apps y Power Automate firman la URL con un parámetro sig. Masnet trata la URL completa como una credencial: la cifra como un secreto, la aplicación muestra solo el host y la ruta con la query enmascarada, y no figura en registros ni métricas. Cambiar la URL crea una nueva generación del destino: pausa el destino, cancela lo pendiente de la generación anterior y exige una prueba exitosa.
Eventos de prueba
Un destino debe superar una prueba antes de recibir eventos reales. La prueba envía el tipo com.masnet.integration.test.v1 con la misma firma, autenticación y validación de red que un evento real. Su environment es test, su subject es integration/<destino> y su data.object es { "message": "Evento de prueba de Masnet", "test": true }. No requiere permiso de datos. El esquema está en /developers/schemas/integration/v1.json.
Recuperación por lectura
Si el receptor estuvo caído más de 72 horas o no puede exponer un punto público, los mismos envoltorios están disponibles en la API de eventos (https://daas.masnet.com/api/v1/integrations/data/events) durante 30 días.