From 76d3ba7629bac09ff41da21e2557e42105bd8123 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 14:00:26 +0000 Subject: [PATCH 1/4] docs(automation): document Graph Context multi-hop relation mapping Adds a new "Multi-Hop Relations (Graph Context)" section to the Entity Mapping docs, covering graph_context's seed/graph structure and the cardinality/filter options, for cases where the target entity isn't directly related to the trigger entity. Co-authored-by: Claude --- docs/automation/entity-mapping.md | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/docs/automation/entity-mapping.md b/docs/automation/entity-mapping.md index 4f9c5be4..cf0b83b7 100644 --- a/docs/automation/entity-mapping.md +++ b/docs/automation/entity-mapping.md @@ -285,4 +285,60 @@ When choosing a relation attribute for mapping, you define which entities from t Define a filter to select the related entities. For example, to relate a Contact created earlier in the automation with a "primary" label, filter by `Schema: contact` and `Relation Label: primary`. +## Multi-Hop Relations (Graph Context) + +`_copy` and `_template` can read directly related entities out of the box (e.g. `contact.first_name`). But sometimes the entity you need data from isn't directly related to the trigger entity — it's only reachable by following a chain of relations. **Graph Context** lets you define that chain once, and every entity along the way becomes available for mapping, the same way a direct relation would. + +For example, a Contract might not have a direct relation to an Order, but both are linked to the same Contact. To pull data from that Order, define a graph query that starts at the Contract, hops to the Contact, and from there to the Order: + +```json +{ + "seed": { + "entity_id": "{{_id}}", + "node_id": "contract" + }, + "graph": { + "nodes": [ + { "id": "contract", "schema": "contract" }, + { "id": "contact", "schema": "contact" }, + { + "id": "order", + "schema": "order", + "cardinality": "one" + } + ], + "edges": [ + { "from": "contract", "to": "contact" }, + { "from": "contact", "to": "order" } + ] + } +} +``` + +Once resolved, the `order` node is merged into the mapping context under its own id, so you can reference it just like a direct relation: + +```json +{ + "target": "line_items", + "operation": { + "_copy": "order.line_items" + } +} +``` + +### Structure + +| Key | Description | +|-----|-------------| +| `seed.entity_id` | The entity to start traversing from. Supports `{{handlebars}}` placeholders resolved against the mapping context — `{{_id}}` refers to the trigger entity. | +| `seed.node_id` | Which node in `graph.nodes` the seed corresponds to. | +| `graph.nodes` | The entities to resolve along the path, each with an `id` (how you'll reference it in `_copy`/`_template`), a `schema`, and optionally `cardinality` and `filter`. | +| `graph.edges` | The relation hops between nodes, as `{ "from": "", "to": "" }` pairs. | + +- **`cardinality`** — set to `"one"` when a node should resolve to exactly one entity (fails the mapping if zero or more than one match). Omit it, or set `"many"`, when a node can resolve to multiple entities — it's then made available as an array. +- **`filter`** — narrows a node down to entities matching specific attribute values, e.g. `{ "attribute": "order_number", "value": "{{contract.order_number}}" }`. Filter values also support `{{handlebars}}` placeholders. + +:::tip +Only one Graph Context entry is supported per Create/Edit Entity action. If you need data from more than one unrelated path, resolve the most specific one and reference simpler attributes directly. +::: From 3f50ff312d8d95b20a1d097e0092280e78860c8b Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 14:56:13 +0000 Subject: [PATCH 2/4] docs(automation): add graph diagram and API link to Graph Context section Addresses review feedback: adds a mermaid flowchart illustrating the contract -> contact -> order example, and links to the Entity API's Graph Query endpoint that powers graph_context resolution. Co-authored-by: Claude --- docs/automation/entity-mapping.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/automation/entity-mapping.md b/docs/automation/entity-mapping.md index cf0b83b7..678c6451 100644 --- a/docs/automation/entity-mapping.md +++ b/docs/automation/entity-mapping.md @@ -287,10 +287,16 @@ Define a filter to select the related entities. For example, to relate a Contact ## Multi-Hop Relations (Graph Context) -`_copy` and `_template` can read directly related entities out of the box (e.g. `contact.first_name`). But sometimes the entity you need data from isn't directly related to the trigger entity — it's only reachable by following a chain of relations. **Graph Context** lets you define that chain once, and every entity along the way becomes available for mapping, the same way a direct relation would. +`_copy` and `_template` can read directly related entities out of the box (e.g. `contact.first_name`). But sometimes the entity you need data from isn't directly related to the trigger entity — it's only reachable by following a chain of relations. **Graph Context** lets you define that chain once, and every entity along the way becomes available for mapping, the same way a direct relation would. Under the hood, it's powered by the Entity API's [Graph Query](/api/entity#tag/Entities/operation/queryEntityGraph) endpoint. For example, a Contract might not have a direct relation to an Order, but both are linked to the same Contact. To pull data from that Order, define a graph query that starts at the Contract, hops to the Contact, and from there to the Order: +```mermaid +flowchart LR + Contract["Contract\n(seed)"] --> Contact["Contact"] + Contact --> Order["Order\n(cardinality: one)"] +``` + ```json { "seed": { From 8cc4ad9fec42a8f43f3d7035a70b19fac1476f6a Mon Sep 17 00:00:00 2001 From: Paulo Henriques Date: Tue, 1 Sep 2026 16:06:41 +0100 Subject: [PATCH 3/4] Adjust text --- docs/automation/entity-mapping.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/automation/entity-mapping.md b/docs/automation/entity-mapping.md index 678c6451..f696350b 100644 --- a/docs/automation/entity-mapping.md +++ b/docs/automation/entity-mapping.md @@ -293,8 +293,8 @@ For example, a Contract might not have a direct relation to an Order, but both a ```mermaid flowchart LR - Contract["Contract\n(seed)"] --> Contact["Contact"] - Contact --> Order["Order\n(cardinality: one)"] + Contract["Contract (seed)"] --> Contact["Contact"] + Contact --> Order["Order"] ``` ```json @@ -343,8 +343,3 @@ Once resolved, the `order` node is merged into the mapping context under its own - **`cardinality`** — set to `"one"` when a node should resolve to exactly one entity (fails the mapping if zero or more than one match). Omit it, or set `"many"`, when a node can resolve to multiple entities — it's then made available as an array. - **`filter`** — narrows a node down to entities matching specific attribute values, e.g. `{ "attribute": "order_number", "value": "{{contract.order_number}}" }`. Filter values also support `{{handlebars}}` placeholders. - -:::tip -Only one Graph Context entry is supported per Create/Edit Entity action. If you need data from more than one unrelated path, resolve the most specific one and reference simpler attributes directly. -::: - From a0bc3c8b3b819dcb7604bd6a088ec83b2cdbb3ec Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 2 Sep 2026 08:20:45 +0000 Subject: [PATCH 4/4] docs(automation): show filter usage on the order node in Graph Context example Addresses review feedback: the example now filters the order node by status instead of just cardinality, and the Structure section's filter bullet points back to it instead of a separate, unrelated example. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01RKQ4pLfRF64YRFcTvFHcVB --- docs/automation/entity-mapping.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/automation/entity-mapping.md b/docs/automation/entity-mapping.md index 678c6451..2f2fcb96 100644 --- a/docs/automation/entity-mapping.md +++ b/docs/automation/entity-mapping.md @@ -294,7 +294,7 @@ For example, a Contract might not have a direct relation to an Order, but both a ```mermaid flowchart LR Contract["Contract\n(seed)"] --> Contact["Contact"] - Contact --> Order["Order\n(cardinality: one)"] + Contact --> Order["Order\n(cardinality: one)\nfilter: status = active"] ``` ```json @@ -310,7 +310,10 @@ flowchart LR { "id": "order", "schema": "order", - "cardinality": "one" + "cardinality": "one", + "filter": [ + { "attribute": "status", "value": "active" } + ] } ], "edges": [ @@ -321,6 +324,8 @@ flowchart LR } ``` +The `filter` narrows the `order` node down to entities matching specific attribute values — here, only an Order with `status: "active"` is considered. Combined with `cardinality: "one"`, the mapping fails loudly if zero or more than one active order is found, instead of resolving an arbitrary one. + Once resolved, the `order` node is merged into the mapping context under its own id, so you can reference it just like a direct relation: ```json @@ -342,7 +347,7 @@ Once resolved, the `order` node is merged into the mapping context under its own | `graph.edges` | The relation hops between nodes, as `{ "from": "", "to": "" }` pairs. | - **`cardinality`** — set to `"one"` when a node should resolve to exactly one entity (fails the mapping if zero or more than one match). Omit it, or set `"many"`, when a node can resolve to multiple entities — it's then made available as an array. -- **`filter`** — narrows a node down to entities matching specific attribute values, e.g. `{ "attribute": "order_number", "value": "{{contract.order_number}}" }`. Filter values also support `{{handlebars}}` placeholders. +- **`filter`** — narrows a node down to entities matching specific attribute values, as shown on the `order` node above. Filter values also support `{{handlebars}}` placeholders, e.g. `{ "attribute": "order_number", "value": "{{contract.order_number}}" }`. :::tip Only one Graph Context entry is supported per Create/Edit Entity action. If you need data from more than one unrelated path, resolve the most specific one and reference simpler attributes directly.