Volver al portal
Mati API v1
Volver a DevelopersPaneles embebidos

Paneles embebidos

El panel se embebe en un iframe, pero nunca recibe credenciales por URL. Tu servidor guarda un secreto de larga duración; el navegador solo recibe un código de un solo uso.

La trampa que rompe la mayoría de las integraciones

Todos los mensajes del host llevan source: 'mati-wordpress', incluso fuera de WordPress. Es un nombre heredado que quedó como constante del protocolo. Si mandás otro valor, el panel descarta los mensajes en silencio y se queda para siempre en «Conectando…».

1. Vincular el origen (una sola vez por dominio)

PUT https://app.mati-ia.com/api/integrations/wordpress/panel/origin
Authorization: MatiPair <codigo-de-vinculacion>
Content-Type: application/json

{ "version": 1, "workspaceSlug": "mi-negocio", "origin": "https://misitio.com" }

→ 201  { "hostCredential": "..." }

2. Bootstrap (en cada carga de página, servidor a servidor)

POST https://app.mati-ia.com/api/integrations/wordpress/panel/bootstrap
Authorization: MatiHost <hostCredential>
Content-Type: application/json

{
  "version": 1,
  "workspaceSlug": "mi-negocio",
  "origin": "https://misitio.com",
  "subject": "usuario-42",
  "role": "ADMIN",
  "capabilities": ["mati_manage_operations", "mati_manage_settings"]
}

→ 201  { "code": "mpb_...", "frameContext": "...", "expiresAt": "..." }

Hoy solo role: "ADMIN" emite sesión. Provider y customer devuelven 401 por diseño fail-closed.

La autorización del usuario final es tuya: Mati verifica que el host sea legítimo, no que quien mira la página deba ver el panel.

3. Construir la URL del iframe

https://app.mati-ia.com/widget/panel/admin/{slug}
  ?channelId={channelId}
  &frameContext={frameContext}

// encodeURIComponent en ambos: un '#' sin escapar corta el frameContext.

4. Handshake por postMessage

Panel  →  Host :  mati:panel:ready
Host   →  Panel:  mati:panel:bootstrap  { code, origin }

// Validar SIEMPRE, en cada mensaje recibido:
if (event.origin !== panelOrigin) return;
if (data.source !== 'mati-panel') return;
if (data.version !== 1) return;
if (data.channelId !== channelId) return;

// Y al enviar: origen exacto, nunca '*'
frame.contentWindow.postMessage(message, panelOrigin);

Panel → Host

  • mati:panel:ready
  • mati:panel:resize{ height }
  • mati:panel:changed
  • mati:panel:session-expiring
  • mati:panel:open-admin
  • mati:panel:focus-mode{ enabled }
  • mati:panel:select-logo

Host → Panel

  • mati:panel:bootstrap{ code, origin }
  • mati:panel:logo-selected{ url }
  • mati:panel:logo-cancelled

Cliente listo para usar

mati-panel-host.js implementa todo el protocolo y es agnóstico de plataforma: sirve para Shopify, Wix, Squarespace, Laravel o HTML plano.

<div id="mati-panel-host"></div>
<script src="https://app.mati-ia.com/mati-panel-host.js"></script>
<script>
  MatiPanelHost.mount({
    container: document.getElementById('mati-panel-host'),
    panelOrigin: 'https://app.mati-ia.com',
    bootstrapUrl: '/mi-backend/mati/bootstrap',
    section: 'dashboard',
  });
</script>

Diagnóstico

  • "Conectando…" — el source no es mati-wordpress, o el channelId no coincide.
  • 401 — el origin no es el vinculado, o roleADMIN.
  • 429 — 10/min en vinculación, 60/min en bootstrap.
  • frameContext truncado — falta encodeURIComponent.