# Managing your flows and endpoints

After you create one or multiple flows, you can proceed with managing thm. This guide demonstrates how to view, read details, and update existing IoT Logic flows using the Navixy IoT Logic API. You'll learn how to list all your flows, examine specific flow configurations including nodes and connections, and modify flows by adding new data processing rules. The examples show practical scenarios like managing fleet vehicle data flows, adding calculated attributes for business metrics, and connecting to MQTT endpoints for external system integration.

## Prerequisites

For this example, let's presume that we have already:

1. Created an MQTT output endpoint with ID 45678 using `/iot/logic/flow/endpoint/create`
2. Created a flow with ID 1234 using `/iot/logic/flow/create` with the following components:
   * A data source node (ID: 1) that captures data from devices 12345, 12346, and 12347
   * An attribute calculation node (ID: 2) for basic metrics
   * An output endpoint node (ID: 3) that sends data to the MQTT endpoint

## Viewing your flows

The flow list endpoint provides a quick overview of all IoT Logic flows in your account. This is useful for getting flow IDs and titles before performing detailed operations. Each flow in the response includes its unique identifier and descriptive title, allowing you to identify which flows you want to examine or modify further.

## flowList

> List all flows in the user account. Returns flow IDs and titles only. Use the read endpoint to retrieve complete flow details including nodes and configuration.

```json
{"openapi":"3.1.0","info":{"title":"Navixy IoT Logic API","version":"1.0.0"},"tags":[{"name":"Flow","description":"Operations for managing data flows"}],"servers":[{"url":"https://api.eu.navixy.com/v2","description":"Navixy production server on European platform"},{"url":"https://api.us.navixy.com/v2","description":"Navixy production server on American platform"}],"security":[{"api_key":[]}],"components":{"securitySchemes":{"api_key":{"type":"apiKey","description":"Enter an API key with the \"NVX: \" prefix, e.g. \"NVX 123456abcdefg\"","name":"Authorization","in":"header"}},"responses":{"ResponseError":{"description":"Error response object","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always false."},"status":{"type":"object","description":"Error status. It only presence when an error occurred.","properties":{"code":{"type":"integer","description":"An error code in this API (not a HTTP code)"},"description":{"type":"string","description":"An error description"}}}}}}}}}},"paths":{"/iot/logic/flow/list":{"get":{"tags":["Flow"],"summary":"flowList","description":"List all flows in the user account. Returns flow IDs and titles only. Use the read endpoint to retrieve complete flow details including nodes and configuration.","operationId":"flowList","responses":{"200":{"description":"Successful response to read a list of flows","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"`true` if request finished successfully","readOnly":true},"list":{"type":"array","description":"List of user's flows","readOnly":true,"items":{"type":"object","properties":{"id":{"type":"integer","description":"Flow ID","readOnly":true},"title":{"type":"string","description":"Flow name","readOnly":true}},"readOnly":true}}}}}}},"default":{"$ref":"#/components/responses/ResponseError"}}}}}}
```

To see all your existing flows, send the request:

```bash
curl -X GET "https://api.eu.navixy.com/v2/iot/logic/flow/list" \
  -H "Authorization: NVX your_session_token_here" \
  -H "Content-Type: application/json"
```

You will receive `id` and `title` parameters in the response:

```json
{
  "success": true,
  "list": [
    {
      "id": 1234,
      "title": "Fleet Data to External System"
    }
  ]
}
```

## Viewing flow details

The flow read endpoint retrieves complete configuration details for a specific flow, including all nodes, their properties, and the connections between them. This detailed view shows you the entire data processing pipeline - from data sources through transformation nodes to output endpoints. Use this when you need to understand the current flow structure before making modifications or troubleshooting data processing issues.

## flowRead

> Retrieve complete flow configuration including all nodes, edges, and metadata. Returns the flow structure with node positions, connections, and enabled status. Use this endpoint to inspect flow architecture or retrieve configuration for duplication.

```json
{"openapi":"3.1.0","info":{"title":"Navixy IoT Logic API","version":"1.0.0"},"tags":[{"name":"Flow","description":"Operations for managing data flows"}],"servers":[{"url":"https://api.eu.navixy.com/v2","description":"Navixy production server on European platform"},{"url":"https://api.us.navixy.com/v2","description":"Navixy production server on American platform"}],"security":[{"api_key":[]}],"components":{"securitySchemes":{"api_key":{"type":"apiKey","description":"Enter an API key with the \"NVX: \" prefix, e.g. \"NVX 123456abcdefg\"","name":"Authorization","in":"header"}},"schemas":{"Flow":{"type":"object","description":"Flowchart object","allOf":[{"$ref":"#/components/schemas/FlowId"},{"$ref":"#/components/schemas/FlowDraft"}]},"FlowId":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Flow ID","readOnly":true}}},"FlowDraft":{"type":"object","description":"Flow object used with the create and update API endpoints. When calling these endpoints, this object must be nested inside a \"flow\" envelope key: {\"flow\": <FlowDraft>}. Includes runtime settings (enabled, default_flow). For a portable export/import format that omits runtime fields and is passed directly without an envelope, see FlowExport.","properties":{"title":{"type":"string","description":"Flow name"},"description":{"type":["string","null"],"description":"Flow description (optional)","readOnly":true},"enabled":{"type":"boolean","description":"Enable/disable flag"},"default_flow":{"type":"boolean","description":"Whether this is the default flow","readOnly":true},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/Node"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/Edge"}}},"required":["title"]},"Node":{"type":"object","description":"Flowchart Node","oneOf":[{"$ref":"#/components/schemas/NodeDataSource"},{"$ref":"#/components/schemas/NodeInitiateAttributes"},{"$ref":"#/components/schemas/NodeLogic"},{"$ref":"#/components/schemas/NodeAction"},{"$ref":"#/components/schemas/NodeWebhook"},{"$ref":"#/components/schemas/NodeOutputEndpoint"}]},"NodeDataSource":{"type":"object","description":"Node: Data Source","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"data_source\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"source_ids":{"type":["array","null"],"items":{"type":"integer","description":"Source ID"},"description":"Array of device/source IDs. Use null or empty array [] for all sources. Note: API normalizes null to empty array [] in responses."}}},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeID":{"type":"integer","description":"Node ID inside current flow"},"NodeView":{"type":"object","description":"Flowchart Node view properties","properties":{"position":{"type":"object","description":"Position of the left top corner","properties":{"x":{"type":"integer"},"y":{"type":"integer"}}}}},"NodeInitiateAttributes":{"type":"object","description":"Node: Initiate Attributes. Transforms device data by creating new calculated attributes based on incoming telemetry. Enables data enrichment through mathematical operations, unit conversions, bit-level manipulations, and time-based calculations using Navixy IoT Logic Expression Language (based on JEXL). Developers can consult the official JEXL specification for expression syntax and operators. Calculated attributes become available to all downstream nodes and can be displayed in Data Stream Analyzer or configured as custom sensors in Navixy tracking interface when connected to default output endpoint.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"initiate_attributes\"."},"data":{"type":"object","properties":{"title":{"type":"string","description":"Node title identifying the transformation purpose."},"items":{"type":"array","description":"List of attributes to calculate. Attributes are processed sequentially in the order defined. Each attribute can reference original device parameters and previously calculated attributes within the same node.","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique attribute identifier. This name appears in Data Stream Analyzer and can be used to create custom sensors in Navixy tracking interface. If attribute name matches existing device parameter, the calculated value replaces the original in output data packets."},"value":{"type":"string","description":"JEXL-based expression to calculate attribute value. Can reference device parameters using direct syntax (e.g., 'temperature') or value() function (e.g., value('temperature', 0, 'valid')). Supports standard JEXL operators and mathematical operations, historical value access (via index parameter), and Navixy-specific bit-level operations through util: namespace functions. Consult JEXL specification for expression syntax details. Expression errors result in null values."},"generation_time":{"type":["string","null"],"description":"JEXL-based expression for device-side generation timestamp (when data was created on device). Defaults to now() if null or not specified. Use genTime() function to reference original parameter timestamps."},"server_time":{"type":["string","null"],"description":"JEXL-based expression for server-side reception timestamp (when data was received by IoT Logic). Defaults to now() if null or not specified. Use srvTime() function to reference original parameter timestamps."}},"required":["name","value"]}}}},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeLogic":{"type":"object","description":"Node: Logic. Creates conditional branching points that route data based on boolean expressions. Logic nodes evaluate incoming data against user-defined conditions and direct data flow through THEN (true) or ELSE (false) output paths. The node creates a boolean attribute that stores evaluation results and can be used in subsequent nodes or Navixy monitoring systems. Logic nodes support multiple outgoing connections on both THEN and ELSE branches. When a THEN target is a terminal node (Action, Webhook), add a second then_edge from this Logic node directly to the Output Endpoint to ensure data is still forwarded to Navixy, both edges fire in parallel.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"logic\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"name":{"type":"string","description":"Internal identifier for the logic node"},"condition":{"type":"string","description":"Boolean expression evaluated for each incoming message. Must return true or false. Expression can reference attributes from connected upstream nodes using direct attribute syntax or value() function. Supports logical operators (&&, ||, !), comparison operators (<, >, <=, >=, ==, !=), and complex conditions. If expression cannot be evaluated (null values, syntax errors, missing attributes), result is treated as false and data flows through ELSE path."}},"required":["title","name","condition"]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeAction":{"description":"Node: Device action. Executes automated device commands when triggered by incoming data. Enables direct device control through output switching and GPRS command transmission. By default, commands are sent to the device that triggered the node. Use device_mapping to redirect commands to other target devices instead. Functions as a terminal node that cannot have outgoing connections.","type":"object","required":["type","data"],"properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"action\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"actions":{"type":["array","null"],"description":"List of actions to execute sequentially when node is triggered. Actions execute in order from first to last. Maximum 10 actions per node. Commands are sent to the trigger device by default, or to target devices specified in device_mapping.","items":{"oneOf":[{"$ref":"#/components/schemas/SetOutput"},{"$ref":"#/components/schemas/SendCommand"}]},"maxItems":10,"uniqueItems":true},"device_mapping":{"type":["array","null"],"description":"Optional cross-device command routing. Maps source devices to target devices that will receive the actions instead of the source device. If null or empty, actions are sent to the device that triggered the node.","uniqueItems":true,"items":{"$ref":"#/components/schemas/DeviceMapping"}}}},"view":{"$ref":"#/components/schemas/NodeView"}}},"SetOutput":{"type":"object","title":"SetOutput","description":"Switches a device output port to the specified on/off state.","required":["type","number","value"],"properties":{"type":{"type":"string","enum":["set_output"],"description":"Action type. Must be 'set_output'."},"number":{"type":"integer","minimum":1,"maximum":8,"description":"Output number as seen in UI."},"value":{"type":"boolean","description":"The state to set to."}}},"SendCommand":{"type":"object","title":"SendCommand","description":"Sends a custom GPRS command string to the device. Use for device-specific commands as documented by the device manufacturer.","required":["type","command"],"properties":{"type":{"type":"string","enum":["send_gprs_command"],"description":"Action type. Must be 'send_gprs_command'."},"command":{"type":"string","minLength":1,"maxLength":512,"description":"A custom command to send to the device. Consult its documentation for details."},"reliable":{"type":["boolean","null"],"default":true,"description":"Reliable commands will be retried in case if a tracker is not online at the moment."}}},"DeviceMapping":{"type":"object","description":"Maps a source device to one or more target devices for cross-device command routing. When a source device triggers the node, actions are sent to the specified target devices instead.","required":["source_id","target_source_ids"],"properties":{"source_id":{"type":"integer","description":"ID of the source device that triggers the routing rule."},"target_source_ids":{"type":"array","description":"IDs of the target devices that will receive the actions when the source device triggers the node.","minItems":1,"items":{"type":"integer"}}}},"NodeWebhook":{"type":"object","description":"Node: Webhook. Sends HTTP POST requests with IoT data to external endpoints, enabling real-time integration with third-party systems and APIs. Webhook nodes function as terminal nodes that cannot have outgoing connections to other nodes in the flow.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"webhook\"."},"data":{"type":"object","properties":{"title":{"type":"string","description":"Webhook node title.","maxLength":255},"url":{"type":"string","description":"Target URL for HTTP POST requests. Must use http:// or https:// protocol (HTTPS recommended). Executes fire-and-forget POST request on each incoming message without waiting for response or retrying on failure.","maxLength":255,"pattern":"^https?:\\/\\/\\S+$"},"headers":{"type":["array","null"],"description":"Optional HTTP headers for POST requests. All headers including Content-Type must be explicitly specified. Maximum 10 headers.","maxItems":10,"items":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","description":"Header name.","maxLength":255},"value":{"type":"string","description":"Header value (static only).","maxLength":255}}}},"body":{"type":["string","null"],"description":"Optional request body template. Use \"attribute_name\" syntax to reference attributes from upstream nodes. Supports nested paths (e.g., \"location.latitude\"). Direct attribute references only; expressions not supported. Null attributes send null values.","maxLength":4000}},"required":["title","url"]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeOutputEndpoint":{"type":"object","description":"Node: output endpoint. This is the terminating node for any flow. It determines where the messages will be sent.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"output_endpoint\"."},"data":{"type":"object","oneOf":[{"$ref":"#/components/schemas/NodeOutputEndpointDataDefault"},{"$ref":"#/components/schemas/NodeOutputEndpointDataStoredEndpoint"}]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeOutputEndpointDataDefault":{"type":"object","description":"Data of default output endpoint (Navixy platform)","properties":{"title":{"type":"string"},"output_endpoint_type":{"type":"string","description":"Type of endpoint. Always 'output_default' for Navixy platform."}},"required":["title","output_endpoint_type"]},"NodeOutputEndpointDataStoredEndpoint":{"type":"object","description":"Data of MQTT output endpoint","properties":{"title":{"type":"string"},"output_endpoint_type":{"type":"string","description":"Type of endpoint. Always 'output_mqtt_client'."},"output_endpoint_id":{"type":"integer","description":"Output Endpoint identifier within the user account. It is required for only some types of node (e.g. output_mqtt_client) which has specific properties."}},"required":["title","output_endpoint_type","output_endpoint_id"]},"Edge":{"type":"object","description":"Edge between two Nodes","properties":{"from":{"type":"integer"},"to":{"type":"integer"},"type":{"description":"Edge type, optional, if not specified it is `simple_edge`","$ref":"#/components/schemas/EdgeType"}},"required":["from","to"]},"EdgeType":{"type":"string","enum":["simple_edge","then_edge","else_edge"]}},"responses":{"ResponseError":{"description":"Error response object","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always false."},"status":{"type":"object","description":"Error status. It only presence when an error occurred.","properties":{"code":{"type":"integer","description":"An error code in this API (not a HTTP code)"},"description":{"type":"string","description":"An error description"}}}}}}}}}},"paths":{"/iot/logic/flow/read":{"get":{"tags":["Flow"],"summary":"flowRead","description":"Retrieve complete flow configuration including all nodes, edges, and metadata. Returns the flow structure with node positions, connections, and enabled status. Use this endpoint to inspect flow architecture or retrieve configuration for duplication.","operationId":"flowRead","parameters":[{"name":"flow_id","in":"query","required":true,"schema":{"type":"integer","description":"Flow ID"}}],"responses":{"200":{"description":"Successful response to read a flow","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"`true` if request finished successfully.","readOnly":true},"value":{"$ref":"#/components/schemas/Flow"}}}}}},"default":{"$ref":"#/components/responses/ResponseError"}}}}}}
```

To see the details of a specific flow, copy the `id` value of the needed flow from [GET /iot/logic/flow/list](#viewing-your-flows) response. Add it in the respective field of this request:

```bash
curl -X POST "https://api.eu.navixy.com/v2/iot/logic/flow/read" \
  -H "Authorization: NVX your_session_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "flow_id": 1234
  }'
```

You will receive the complete structure of the flow in the response:

```json
{
  "success": true,
  "value": {
    "id": 1234,
    "title": "Fleet Data to External System",
    "description": null,
    "enabled": true,
    "default_flow": false,
    "nodes": [
      {
        "id": 1,
        "type": "data_source",
        "view": {
          "position": { "x": 50, "y": 50 }
        },
        "data": {
          "title": "Fleet Vehicles",
          "source_ids": [12345, 12346, 12347]
        }
      },
      {
        "id": 2,
        "type": "initiate_attributes",
        "view": {
          "position": { "x": 200, "y": 50 }
        },
        "data": {
          "title": "Calculate Business Metrics",
          "items": [
            {
              "name": "fuel_efficiency",
              "value": "value(\"distance_traveled\") / value(\"fuel_consumed\")",
              "generation_time": "genTime(\"distance_traveled\", 0, \"valid\")",
              "server_time": "now()"
            },
            {
              "name": "idle_time_percent",
              "value": "(value(\"idle_time\") / (value(\"idle_time\") + value(\"moving_time\"))) * 100",
              "generation_time": "genTime(\"idle_time\", 0, \"valid\")",
              "server_time": "now()"
            },
            {
              "name": "vehicle_status",
              "value": "value(\"speed\") gt 0 ? \"moving\" : \"stopped\"",
              "generation_time": "genTime(\"speed\", 0, \"valid\")",
              "server_time": "now()"
            }
          ]
        }
      },
      {
        "id": 3,
        "type": "output_endpoint",
        "view": {
          "position": { "x": 350, "y": 50 }
        },
        "data": {
          "title": "Send to External System",
          "output_endpoint_type": "output_mqtt_client",
          "output_endpoint_id": 45678
        }
      }
    ],
    "edges": [
      {
        "from": 1,
        "to": 2
      },
      {
        "from": 2,
        "to": 3
      }
    ]
  }
}
```

## Updating a flow

The flow update endpoint allows you to modify existing flows by changing node configurations, adding new processing rules, or adjusting connections. When updating a flow, you must provide the complete flow structure, including all nodes and edges, even if you're only modifying one element. This ensures data consistency and prevents accidental deletion of existing components. In this example, we're adding a new calculated attribute to convert engine temperature from Fahrenheit to Celsius while preserving all existing functionality.

## flowUpdate

> Update an existing flow's configuration. Requires the complete flow object including all nodes and edges. To modify individual nodes without affecting the entire flow, use the endpoint management API. Changes take effect immediately for enabled flows.

```json
{"openapi":"3.1.0","info":{"title":"Navixy IoT Logic API","version":"1.0.0"},"tags":[{"name":"Flow","description":"Operations for managing data flows"}],"servers":[{"url":"https://api.eu.navixy.com/v2","description":"Navixy production server on European platform"},{"url":"https://api.us.navixy.com/v2","description":"Navixy production server on American platform"}],"security":[{"api_key":[]}],"components":{"securitySchemes":{"api_key":{"type":"apiKey","description":"Enter an API key with the \"NVX: \" prefix, e.g. \"NVX 123456abcdefg\"","name":"Authorization","in":"header"}},"schemas":{"Flow":{"type":"object","description":"Flowchart object","allOf":[{"$ref":"#/components/schemas/FlowId"},{"$ref":"#/components/schemas/FlowDraft"}]},"FlowId":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","description":"Flow ID","readOnly":true}}},"FlowDraft":{"type":"object","description":"Flow object used with the create and update API endpoints. When calling these endpoints, this object must be nested inside a \"flow\" envelope key: {\"flow\": <FlowDraft>}. Includes runtime settings (enabled, default_flow). For a portable export/import format that omits runtime fields and is passed directly without an envelope, see FlowExport.","properties":{"title":{"type":"string","description":"Flow name"},"description":{"type":["string","null"],"description":"Flow description (optional)","readOnly":true},"enabled":{"type":"boolean","description":"Enable/disable flag"},"default_flow":{"type":"boolean","description":"Whether this is the default flow","readOnly":true},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/Node"}},"edges":{"type":"array","items":{"$ref":"#/components/schemas/Edge"}}},"required":["title"]},"Node":{"type":"object","description":"Flowchart Node","oneOf":[{"$ref":"#/components/schemas/NodeDataSource"},{"$ref":"#/components/schemas/NodeInitiateAttributes"},{"$ref":"#/components/schemas/NodeLogic"},{"$ref":"#/components/schemas/NodeAction"},{"$ref":"#/components/schemas/NodeWebhook"},{"$ref":"#/components/schemas/NodeOutputEndpoint"}]},"NodeDataSource":{"type":"object","description":"Node: Data Source","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"data_source\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"source_ids":{"type":["array","null"],"items":{"type":"integer","description":"Source ID"},"description":"Array of device/source IDs. Use null or empty array [] for all sources. Note: API normalizes null to empty array [] in responses."}}},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeID":{"type":"integer","description":"Node ID inside current flow"},"NodeView":{"type":"object","description":"Flowchart Node view properties","properties":{"position":{"type":"object","description":"Position of the left top corner","properties":{"x":{"type":"integer"},"y":{"type":"integer"}}}}},"NodeInitiateAttributes":{"type":"object","description":"Node: Initiate Attributes. Transforms device data by creating new calculated attributes based on incoming telemetry. Enables data enrichment through mathematical operations, unit conversions, bit-level manipulations, and time-based calculations using Navixy IoT Logic Expression Language (based on JEXL). Developers can consult the official JEXL specification for expression syntax and operators. Calculated attributes become available to all downstream nodes and can be displayed in Data Stream Analyzer or configured as custom sensors in Navixy tracking interface when connected to default output endpoint.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"initiate_attributes\"."},"data":{"type":"object","properties":{"title":{"type":"string","description":"Node title identifying the transformation purpose."},"items":{"type":"array","description":"List of attributes to calculate. Attributes are processed sequentially in the order defined. Each attribute can reference original device parameters and previously calculated attributes within the same node.","items":{"type":"object","properties":{"name":{"type":"string","description":"Unique attribute identifier. This name appears in Data Stream Analyzer and can be used to create custom sensors in Navixy tracking interface. If attribute name matches existing device parameter, the calculated value replaces the original in output data packets."},"value":{"type":"string","description":"JEXL-based expression to calculate attribute value. Can reference device parameters using direct syntax (e.g., 'temperature') or value() function (e.g., value('temperature', 0, 'valid')). Supports standard JEXL operators and mathematical operations, historical value access (via index parameter), and Navixy-specific bit-level operations through util: namespace functions. Consult JEXL specification for expression syntax details. Expression errors result in null values."},"generation_time":{"type":["string","null"],"description":"JEXL-based expression for device-side generation timestamp (when data was created on device). Defaults to now() if null or not specified. Use genTime() function to reference original parameter timestamps."},"server_time":{"type":["string","null"],"description":"JEXL-based expression for server-side reception timestamp (when data was received by IoT Logic). Defaults to now() if null or not specified. Use srvTime() function to reference original parameter timestamps."}},"required":["name","value"]}}}},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeLogic":{"type":"object","description":"Node: Logic. Creates conditional branching points that route data based on boolean expressions. Logic nodes evaluate incoming data against user-defined conditions and direct data flow through THEN (true) or ELSE (false) output paths. The node creates a boolean attribute that stores evaluation results and can be used in subsequent nodes or Navixy monitoring systems. Logic nodes support multiple outgoing connections on both THEN and ELSE branches. When a THEN target is a terminal node (Action, Webhook), add a second then_edge from this Logic node directly to the Output Endpoint to ensure data is still forwarded to Navixy, both edges fire in parallel.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"logic\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"name":{"type":"string","description":"Internal identifier for the logic node"},"condition":{"type":"string","description":"Boolean expression evaluated for each incoming message. Must return true or false. Expression can reference attributes from connected upstream nodes using direct attribute syntax or value() function. Supports logical operators (&&, ||, !), comparison operators (<, >, <=, >=, ==, !=), and complex conditions. If expression cannot be evaluated (null values, syntax errors, missing attributes), result is treated as false and data flows through ELSE path."}},"required":["title","name","condition"]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeAction":{"description":"Node: Device action. Executes automated device commands when triggered by incoming data. Enables direct device control through output switching and GPRS command transmission. By default, commands are sent to the device that triggered the node. Use device_mapping to redirect commands to other target devices instead. Functions as a terminal node that cannot have outgoing connections.","type":"object","required":["type","data"],"properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"action\"."},"data":{"type":"object","properties":{"title":{"type":"string"},"actions":{"type":["array","null"],"description":"List of actions to execute sequentially when node is triggered. Actions execute in order from first to last. Maximum 10 actions per node. Commands are sent to the trigger device by default, or to target devices specified in device_mapping.","items":{"oneOf":[{"$ref":"#/components/schemas/SetOutput"},{"$ref":"#/components/schemas/SendCommand"}]},"maxItems":10,"uniqueItems":true},"device_mapping":{"type":["array","null"],"description":"Optional cross-device command routing. Maps source devices to target devices that will receive the actions instead of the source device. If null or empty, actions are sent to the device that triggered the node.","uniqueItems":true,"items":{"$ref":"#/components/schemas/DeviceMapping"}}}},"view":{"$ref":"#/components/schemas/NodeView"}}},"SetOutput":{"type":"object","title":"SetOutput","description":"Switches a device output port to the specified on/off state.","required":["type","number","value"],"properties":{"type":{"type":"string","enum":["set_output"],"description":"Action type. Must be 'set_output'."},"number":{"type":"integer","minimum":1,"maximum":8,"description":"Output number as seen in UI."},"value":{"type":"boolean","description":"The state to set to."}}},"SendCommand":{"type":"object","title":"SendCommand","description":"Sends a custom GPRS command string to the device. Use for device-specific commands as documented by the device manufacturer.","required":["type","command"],"properties":{"type":{"type":"string","enum":["send_gprs_command"],"description":"Action type. Must be 'send_gprs_command'."},"command":{"type":"string","minLength":1,"maxLength":512,"description":"A custom command to send to the device. Consult its documentation for details."},"reliable":{"type":["boolean","null"],"default":true,"description":"Reliable commands will be retried in case if a tracker is not online at the moment."}}},"DeviceMapping":{"type":"object","description":"Maps a source device to one or more target devices for cross-device command routing. When a source device triggers the node, actions are sent to the specified target devices instead.","required":["source_id","target_source_ids"],"properties":{"source_id":{"type":"integer","description":"ID of the source device that triggers the routing rule."},"target_source_ids":{"type":"array","description":"IDs of the target devices that will receive the actions when the source device triggers the node.","minItems":1,"items":{"type":"integer"}}}},"NodeWebhook":{"type":"object","description":"Node: Webhook. Sends HTTP POST requests with IoT data to external endpoints, enabling real-time integration with third-party systems and APIs. Webhook nodes function as terminal nodes that cannot have outgoing connections to other nodes in the flow.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"webhook\"."},"data":{"type":"object","properties":{"title":{"type":"string","description":"Webhook node title.","maxLength":255},"url":{"type":"string","description":"Target URL for HTTP POST requests. Must use http:// or https:// protocol (HTTPS recommended). Executes fire-and-forget POST request on each incoming message without waiting for response or retrying on failure.","maxLength":255,"pattern":"^https?:\\/\\/\\S+$"},"headers":{"type":["array","null"],"description":"Optional HTTP headers for POST requests. All headers including Content-Type must be explicitly specified. Maximum 10 headers.","maxItems":10,"items":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","description":"Header name.","maxLength":255},"value":{"type":"string","description":"Header value (static only).","maxLength":255}}}},"body":{"type":["string","null"],"description":"Optional request body template. Use \"attribute_name\" syntax to reference attributes from upstream nodes. Supports nested paths (e.g., \"location.latitude\"). Direct attribute references only; expressions not supported. Null attributes send null values.","maxLength":4000}},"required":["title","url"]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeOutputEndpoint":{"type":"object","description":"Node: output endpoint. This is the terminating node for any flow. It determines where the messages will be sent.","properties":{"id":{"$ref":"#/components/schemas/NodeID"},"type":{"type":"string","description":"Node type. Always \"output_endpoint\"."},"data":{"type":"object","oneOf":[{"$ref":"#/components/schemas/NodeOutputEndpointDataDefault"},{"$ref":"#/components/schemas/NodeOutputEndpointDataStoredEndpoint"}]},"view":{"$ref":"#/components/schemas/NodeView"}},"required":["type","data"]},"NodeOutputEndpointDataDefault":{"type":"object","description":"Data of default output endpoint (Navixy platform)","properties":{"title":{"type":"string"},"output_endpoint_type":{"type":"string","description":"Type of endpoint. Always 'output_default' for Navixy platform."}},"required":["title","output_endpoint_type"]},"NodeOutputEndpointDataStoredEndpoint":{"type":"object","description":"Data of MQTT output endpoint","properties":{"title":{"type":"string"},"output_endpoint_type":{"type":"string","description":"Type of endpoint. Always 'output_mqtt_client'."},"output_endpoint_id":{"type":"integer","description":"Output Endpoint identifier within the user account. It is required for only some types of node (e.g. output_mqtt_client) which has specific properties."}},"required":["title","output_endpoint_type","output_endpoint_id"]},"Edge":{"type":"object","description":"Edge between two Nodes","properties":{"from":{"type":"integer"},"to":{"type":"integer"},"type":{"description":"Edge type, optional, if not specified it is `simple_edge`","$ref":"#/components/schemas/EdgeType"}},"required":["from","to"]},"EdgeType":{"type":"string","enum":["simple_edge","then_edge","else_edge"]}},"responses":{"OK":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"`true` if request finished successfully.","readOnly":true}}}}}},"ResponseError":{"description":"Error response object","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always false."},"status":{"type":"object","description":"Error status. It only presence when an error occurred.","properties":{"code":{"type":"integer","description":"An error code in this API (not a HTTP code)"},"description":{"type":"string","description":"An error description"}}}}}}}}}},"paths":{"/iot/logic/flow/update":{"post":{"tags":["Flow"],"summary":"flowUpdate","description":"Update an existing flow's configuration. Requires the complete flow object including all nodes and edges. To modify individual nodes without affecting the entire flow, use the endpoint management API. Changes take effect immediately for enabled flows.","operationId":"flowUpdate","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"flow":{"description":"The flow definition, wrapped in this \"flow\" key as required by the create/update endpoints. Export/import operations do not use this envelope — they accept the flow object directly.","$ref":"#/components/schemas/Flow"}},"required":["flow"]}}}},"responses":{"200":{"$ref":"#/components/responses/OK"},"default":{"$ref":"#/components/responses/ResponseError"}}}}}}
```

Copy the flow obgect structure from [POST /iot/logic/flow/read](#viewing-flow-details) response and add the new attribute to the Initiate Atribute node (`id": 2`). Then paste the resulting object in the body of this request:

```bash
curl -X POST "https://api.eu.navixy.com/v2/iot/logic/flow/update" \
  -H "Authorization: NVX your_session_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "flow": {
      "id": 1234,
      "title": "Fleet Data to External System",
      "description": null,
      "enabled": true,
      "default_flow": false,
      "nodes": [
        {
          "id": 1,
          "type": "data_source",
          "view": {
            "position": { "x": 50, "y": 50 }
          },
          "data": {
            "title": "Fleet Vehicles",
            "source_ids": [12345, 12346, 12347]
          }
        },
        {
          "id": 2,
          "type": "initiate_attributes",
          "view": {
            "position": { "x": 200, "y": 50 }
          },
          "data": {
            "title": "Calculate Business Metrics",
            "items": [
              {
                "name": "fuel_efficiency",
                "value": "value(\"distance_traveled\") / value(\"fuel_consumed\")",
                "generation_time": "genTime(\"distance_traveled\", 0, \"valid\")",
                "server_time": "now()"
              },
              {
                "name": "idle_time_percent",
                "value": "(value(\"idle_time\") / (value(\"idle_time\") + value(\"moving_time\"))) * 100",
                "generation_time": "genTime(\"idle_time\", 0, \"valid\")",
                "server_time": "now()"
              },
              {
                "name": "engine_temp_celsius",
                "value": "(value(\"engine_temp_f\") - 32) * 5/9",
                "generation_time": "genTime(\"engine_temp_f\", 0, \"valid\")",
                "server_time": "now()"
              }
            ]
          }
        },
        {
          "id": 3,
          "type": "output_endpoint",
          "view": {
            "position": { "x": 350, "y": 50 }
          },
          "data": {
            "title": "Send to External System",
            "output_endpoint_type": "output_mqtt_client",
            "output_endpoint_id": 45678
          }
        }
      ],
      "edges": [
        {
          "from": 1,
          "to": 2
        },
        {
          "from": 2,
          "to": 3
        }
      ]
    }
  }'
```

You will receive this request status in response:

```json
{
  "success": true
}
```

{% hint style="success" %}
**Congratulations!**

You've now successfully enhanced your data flow by:

* Adding an engine temperature conversion calculation (Fahrenheit to Celsius)
* Maintaining your existing business metrics calculations
* Updating your flow while preserving the connection to your fleet vehicles and MQTT endpoint
  {% endhint %}
