---
title: "Esquema del grafo de campaña"
description: "La forma de un grafo de campaña guardado — los campos de nodo y arista, el objeto de configuración para cada tipo de nodo, y las restricciones que satisface un grafo válido."
canonical: https://docs.afp.monster/es/reference/campaign-graph-schema
updated: 2026-08-19
pageType: reference
---

Un grafo de campaña guardado son dos arreglos: `nodes`, cada uno con un tipo y un objeto de configuración, y `edges`, cada uno uniendo la salida numerada de un nodo con la entrada de otro. Nada más se guarda en el grafo — el nombre de la campaña, su página, y su estado activo viven en la campaña, no en el grafo. Guardar escribe una nueva versión de ambos arreglos.

## Campos de nodo

| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| `id` | string | sí | Identifica al nodo dentro de este grafo, y es a lo que apuntan las conexiones. Se reemplaza con un identificador nuevo cuando el grafo se guarda, así que es estable solo dentro de una versión. |
| `type` | string | sí | Uno de los tipos en [tipos de nodo](/es/reference/node-types), o uno de los tipos solo de runtime listados abajo. |
| `config` | object | sí | La configuración del nodo. Un objeto vacío es válido, y es con lo que empieza un nodo recién agregado. |
| `canvas_x` | number | sí | Posición horizontal del nodo en el lienzo. Se restaura cuando el grafo se abre. |
| `canvas_y` | number | sí | Posición vertical del nodo en el lienzo. Se restaura cuando el grafo se abre. |

## Campos de conexión

| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
| `id` | string | sí | Identifica la conexión dentro de este grafo. |
| `from_node_id` | string | sí | El `id` del nodo del que sale la conexión. Debe aparecer en el mismo arreglo `nodes`, o la conexión se descarta al guardar. |
| `to_node_id` | string | sí | El `id` del nodo en el que entra la conexión. Debe aparecer en el mismo arreglo `nodes`, o la conexión se descarta al guardar. |
| `output_index` | number | sí | De qué salida del nodo de origen sale la conexión. `0` es la salida por defecto; en una `condition`, `0` es Coincidencia y `1` es Sin coincidencia; en un `random_split`, de `0` a N-1 son los brazos en el orden configurado. |
| `label` | string | no | Texto que se muestra en la conexión, tomado del nombre de la salida de origen — por ejemplo `Match` o `No Match`. Las ejecuciones se enrutan por `output_index`, nunca por `label`. |

## Ejemplo trabajado

Un comentario activa la campaña, una lista de palabras clave decide la rama, las personas que coinciden reciben un mensaje directo y una etiqueta una hora después, y toda otra ejecución termina de inmediato.

```d2 title="A saved graph: trigger to condition, then send DM, delay and add tag on match, and stop on no match"
direction: down
trigger: trigger_comment
cond: "condition\nkeyword_list" {shape: diamond}
dm: send_dm
wait: "delay 3600s"
tag: add_tag
halt: stop
trigger -> cond
cond -> dm: "Coincidencia (salida 0)"
dm -> wait -> tag
cond -> halt: "Sin coincidencia (salida 1)"
```

```json
{
  "nodes": [
    {
      "id": "3f6c1a80-5d2b-4c11-9e64-7a0b8d43f215",
      "type": "trigger_comment",
      "config": { "post_scope": "all", "unique_per_user": false },
      "canvas_x": 240,
      "canvas_y": 40
    },
    {
      "id": "9b1d47e2-08af-4d5c-bb37-2c6e5f90a4d1",
      "type": "condition",
      "config": {
        "match_type": "keyword_list",
        "keyword_list_id": 41,
        "reverse_keywords": false,
        "wait_for_reply": false
      },
      "canvas_x": 240,
      "canvas_y": 200
    },
    {
      "id": "c74a2f19-6e30-4b8d-8f52-19d7c3b6e084",
      "type": "send_dm",
      "config": {
        "message_type": "text",
        "text": "Thanks for commenting. The price list is on its way."
      },
      "canvas_x": 80,
      "canvas_y": 380
    },
    {
      "id": "1a58e63d-4c97-42f0-9b18-6d2f7ae5c390",
      "type": "delay",
      "config": { "delay_seconds": 3600, "only_if_no_reply": true },
      "canvas_x": 80,
      "canvas_y": 540
    },
    {
      "id": "e2079b45-13cd-4a6e-8c71-5f83d0b29a6c",
      "type": "add_tag",
      "config": { "tag_ids": [12] },
      "canvas_x": 80,
      "canvas_y": 700
    },
    {
      "id": "7d3fb0c6-92e1-4f57-a840-3b6c1d5e2087",
      "type": "stop",
      "config": {},
      "canvas_x": 440,
      "canvas_y": 380
    }
  ],
  "edges": [
    {
      "id": "5c8e1b73-2f40-4d19-9a6b-8e7d0c34f512",
      "from_node_id": "3f6c1a80-5d2b-4c11-9e64-7a0b8d43f215",
      "to_node_id": "9b1d47e2-08af-4d5c-bb37-2c6e5f90a4d1",
      "output_index": 0,
      "label": ""
    },
    {
      "id": "b06d4a92-7e15-48c3-bf20-6a9c2d813e47",
      "from_node_id": "9b1d47e2-08af-4d5c-bb37-2c6e5f90a4d1",
      "to_node_id": "c74a2f19-6e30-4b8d-8f52-19d7c3b6e084",
      "output_index": 0,
      "label": "Match"
    },
    {
      "id": "48f1c25e-3b7d-4096-8ea4-1c5b7f02d9a3",
      "from_node_id": "9b1d47e2-08af-4d5c-bb37-2c6e5f90a4d1",
      "to_node_id": "7d3fb0c6-92e1-4f57-a840-3b6c1d5e2087",
      "output_index": 1,
      "label": "No Match"
    },
    {
      "id": "a91b7e04-6c58-4d2f-93a1-7e04b8c5f261",
      "from_node_id": "c74a2f19-6e30-4b8d-8f52-19d7c3b6e084",
      "to_node_id": "1a58e63d-4c97-42f0-9b18-6d2f7ae5c390",
      "output_index": 0,
      "label": ""
    },
    {
      "id": "d5720af8-9134-4be6-8c07-2f6a5d18b3e9",
      "from_node_id": "1a58e63d-4c97-42f0-9b18-6d2f7ae5c390",
      "to_node_id": "e2079b45-13cd-4a6e-8c71-5f83d0b29a6c",
      "output_index": 0,
      "label": ""
    }
  ]
}
```

## Claves de configuración por tipo de nodo

| Tipo de nodo | Claves en `config` |
|---|---|
| `trigger_comment` | `post_scope` (`all` o `specific`), `post_id` (requerido cuando `post_scope` es `specific`), `unique_per_user` |
| `trigger_dm` | `unique_per_user` |
| `condition` | `match_type` (`any`, `contains`, `exact`, `keyword_list`), `text`, `keyword_list_id`, `reverse_keywords`, `wait_for_reply`, `filter_images`, `filter_gifs`, `filter_links` |
| `send_dm` | `message_type` (`text`, `image`, `card`, `text_with_buttons`), `text`, `image_url`, `title`, `subtitle`, `buttons`, `buttons_text` |
| `reply_comment` | `text` |
| `send_comment` | `text`, `post_id` |
| `hide_comment`, `delete_comment` | `also_block_user` (solo Facebook) |
| `delay` | `delay_seconds` (1 a 31536000), `only_if_no_reply` |
| `random_split` | `paths`, un arreglo de `{ "percent": number }` con cada porcentaje de 0 a 100 y el total no más de 100 |
| `add_tag`, `remove_tag` | `tag_ids`, un arreglo de identificadores numéricos de etiqueta |
| `stop` | ninguna |

[Tipos de nodo](/es/reference/node-types) describe qué hace cada clave y qué hace cada nodo cuando una ejecución lo alcanza.

## Restricciones de conexión

El lienzo aplica esto mientras una conexión se está arrastrando, así que una conexión inválida nunca llega a un grafo guardado.

1. Una activación nunca es el destino de una conexión.
2. Un nodo nunca se conecta a sí mismo.
3. Una conexión que crearía un ciclo se rechaza.
4. Un nodo acepta una conexión entrante.
5. Cada salida lleva una conexión saliente.
6. Una activación se conecta solo a una `condition`.
7. Una `condition` nunca se conecta a otra `condition`.
8. Las acciones de comentario no están disponibles cuando la activación es `trigger_dm`.
9. Después de un `delete_comment`, `reply_comment` y `hide_comment` se rechazan.

Un grafo tiene una activación en la práctica, aunque la forma de los datos permite más de una. Un grafo cuyos nodos tienen errores de configuración no puede guardarse en absoluto — el lienzo reporta los errores en su lugar. [Construir una campaña](/es/guides/build-a-campaign) recorre el ensamblaje de un grafo que satisface todo esto.

## Tipos de nodo fuera de la paleta

El runtime reconoce ocho tipos adicionales que no tienen mosaico en la paleta ni panel de configuración. Un grafo construido en el lienzo nunca los contiene; aparecen solo a través de una ruta que evita el editor, así que trátalos como solo de runtime en lugar de como funciones.

| Tipo de nodo | Qué hace la ejecución |
|---|---|
| `switch` | Evalúa las reglas de cada brazo y sigue el primer brazo que coincide, o un brazo por defecto cuando uno está configurado. Sin coincidencia y sin brazo por defecto, la ejecución termina. |
| `wait_until` | Espera hasta un momento configurado y luego continúa, programado de la misma forma que un `delay`. |
| `block_user` | Bloquea a la persona y continúa. Solo Facebook; en Instagram no hace nada y advierte. |
| `unhide_comment`, `typing_indicator`, `mark_seen`, `set_field`, `note` | Ejecutables, pero no llevan panel de configuración y las fuentes detrás de esta página no registran configuración para ellos. |

## Qué le hace guardar a un grafo

- Cada guardado escribe una nueva versión del grafo. La campaña apunta a la versión más nueva, y solo la activación de esa versión inicia nuevas ejecuciones.
- Cada identificador de nodo se regenera al guardar y las conexiones se remapean a los nuevos identificadores. Los identificadores son por lo tanto estables dentro de una versión, no entre guardados.
- Una conexión cuyo `from_node_id` o `to_node_id` no está en el mismo arreglo `nodes` se descarta, y el resto del grafo aún se guarda.
- Un grafo vacío — ambos arreglos vacíos — se guarda exitosamente. Sin activación en él, nada inicia una ejecución.
- Una ejecución ya en vuelo se queda en la versión en la que inició, así que editar y guardar una campaña nunca cambia ejecuciones que están en curso.
- Las versiones más antiguas se eliminan una vez que ninguna ejecución las referencia.

## Notas

- Un botón `postback` en un nodo `send_dm` recibe su propia salida. Al guardar, el lienzo expande cada rama de botón en nodos `condition` adicionales y etiqueta las conexiones con el identificador del botón; abrir el grafo los colapsa de vuelta en salidas de botón.
- Una ejecución sigue la conexión cuyo `output_index` coincide con la salida que el nodo seleccionó. Cuando ninguna conexión lleva ese índice, la ejecución se completa en ese nodo.
- Una ejecución que alcanza un nodo que ya visitó termina con un error de ciclo, que es por qué el editor rechaza ciclos desde el principio.
- Las claves de configuración en esta referencia son las que hay que escribir. Algunos tipos de nodo también responden a nombres de clave más antiguos, mantenidos para que los grafos guardados antes todavía se ejecuten.

## Relacionado

- [Tipos de nodo](/es/reference/node-types) — la referencia completa por nodo para cada clave en `config`
- [Construir una campaña](/es/guides/build-a-campaign) — construir un grafo que satisface las restricciones anteriores
- [Prueba y depura campañas](/es/guides/test-and-debug-campaigns) — ejecutar un grafo guardado y leer la ruta que tomó
- [Estados de ejecución](/es/reference/execution-states) — los estados por los que pasa una ejecución mientras recorre un grafo
