mirlo

Canvas, validacion e import/export

Formato de canvasData, validacion, catalogo de nodos y portabilidad de flujos

Formato de canvasData

canvasData es un objeto con dos arreglos:

{
  "nodes": [
    {
      "id": "n1",
      "type": "trigger",
      "position": { "x": 0, "y": 0 },
      "data": {
        "nodeType": "trigger",
        "name": "Mensaje entrante",
        "triggerType": "trigger_messaging",
        "organizationAddresses": ["<organizationAddress del canal>"]
      }
    },
    {
      "id": "n2",
      "type": "send_message",
      "position": { "x": 260, "y": 0 },
      "data": { "nodeType": "send_message", "name": "Respuesta", "message": "Gracias por escribirnos." }
    }
  ],
  "edges": [
    { "id": "e1", "source": "n1", "target": "n2" }
  ]
}
CampoDescripcion
nodes[].idIdentificador del nodo, unico dentro del canvas
nodes[].typeTipo del nodo. El disparador siempre es trigger (el tipo de disparador va en data.triggerType)
nodes[].position{ x, y } en el lienzo
nodes[].dataConfiguracion del nodo; sus campos dependen del tipo (data.nodeType, data.name, ...)
edges[].id, source, targetConexion entre dos nodos
edges[].sourceHandle, targetHandleSalida/entrada especifica, por ejemplo la rama de una condicion (case_b1, else)

Un type que no existe no da error al guardar: el nodo se ignora y el flujo queda dibujado sin hacer nada. Consulta el catalogo de nodos y valida antes de publicar. Un flujo necesita exactamente un nodo disparador para publicarse.


Catalogo de nodos

GET /flows/node-catalog

Metadata fija del producto (igual para todas las organizaciones): los tipos de nodo validos con sus campos, handles y runtime, el catalogo de disparadores, los operadores de condicion y un canvas de ejemplo completo. Es la referencia para armar un canvas.

curl "https://api.mirlo.com/v1/flows/node-catalog" \
  -H "X-API-Key: sk_live_..."

Respuesta

{
  "canvas_rules": [ ... ],
  "runtimes": { ... },
  "condition_operators": [ ... ],
  "triggers": { "trigger_messaging": { "summary": "...", "runtime": "messaging" } },
  "node_count": 0,
  "nodes": { "send_message": { ... } },
  "example_canvas": { "nodes": [ ... ], "edges": [ ... ] }
}

example_canvas es un flujo completo (disparador, condicion, ticket de CRM, mensaje y fin) que puedes tomar de base.


Validar

Validar un canvas sin guardarlo

POST /flows/validate-canvas

No crea nada. Corre dos chequeos: el vocabulario contra el catalogo (tipos inexistentes, campos requeridos, handles) y la validacion estructural que se aplica al publicar.

{ "canvas_data": { "nodes": [ ... ], "edges": [ ... ] } }

Tambien se acepta canvasData. Si falta, la respuesta es 400.

{
  "valid": false,
  "vocabulary_errors": ["[nodo n3] ..."],
  "structure_errors": ["Flow must have exactly one trigger node"],
  "warnings": [],
  "note": "Solo `vocabulary_errors` y `structure_errors` invalidan el canvas. Los warnings son avisos."
}

Validar un flujo guardado

POST /flows/:id/validate

Sin body. Aplica la validacion estructural al canvas guardado.

{ "valid": true, "errors": [] }

Exportar e importar

Sirven para mover un flujo entre organizaciones (por ejemplo de desarrollo a produccion).

Exportar

GET /flows/:id/export

Devuelve el flujo en un JSON portable. Las referencias propias de tu organizacion (miembros, equipos, agentes de IA, canales, pipelines, encuestas, plantillas de WhatsApp, secretos) se vacian; los disparadores y las asociaciones de canal o numero no se incluyen.

{
  "schemaVersion": 1,
  "exportedAt": "2026-10-10T18:20:00.000Z",
  "flow": {
    "name": "Atencion inicial",
    "description": "Responde y crea ticket de bajas",
    "channel": "messaging",
    "canvasData": { "nodes": [ ... ], "edges": [ ... ] }
  }
}

Importar

POST /flows/import

Recibe ese mismo JSON y crea el flujo como draft (201, devuelve el objeto Flow).

CampoTipoRequeridoDescripcion
schemaVersionnumberSiDebe ser 1; otro valor da 400
exportedAtstringNoFecha ISO del export
flow.namestringSiNombre
flow.descriptionstringNoDescripcion
flow.channelstringNomessaging (default), voice, omni
flow.canvasDataobjectSiDebe incluir nodes

Despues de importar tienes que completar en el flujo los datos de tu organizacion (canal, agentes, pipelines, etc.) y publicarlo.

En esta pagina