Chapter 11

Action node, targets, data, and return values

In 0.80.3, the editor displays Action, while exported flow JSON retains the persisted type api-call-service; the node version is 7. Actions cause external side effects in HA. This chapter therefore uses only disabled nodes and complete placeholders to explain the contracts for action, target, data, input overrides, queues, responses, and errors. It provides no real, directly executable targets.

Why this chapter matters

An Action is the boundary at which an event or query flow crosses into side effects. The Events: state and Current State nodes discussed in earlier chapters primarily read data; an Action can control devices, change helpers, send notifications, or invoke other HA functionality. A single incorrect target, an allowed payload override, or treating the reconnect queue as a reliable work queue can turn one test into multiple real operations.

Every call raises at least three distinct questions: action determines which HA operation to perform; target determines which entity, device, area, floor, or label it affects; and data carries arguments specific to that action. Putting an entity ID into arbitrary data, putting message text in the target, or assuming every action returns a payload all violate the contract.

Nothing in this chapter is executable: the Action node in 07-action.json contains "d": true, and its Server, action, and entity values are all PLACEHOLDER_*. Inspect it offline only. Do not Deploy it, remove its disabled flag, or connect it to a real trigger until the security review, target-owner approval, and recovery plan are complete.

Action UI, persisted type, and v7 data flow

In the pinned version, the palette label is action and the NodeType key is Action, but the type in Node-RED flow JSON remains api-call-service. “Call Service” in older flows and documentation identifies the legacy name only. Do not revert the current UI terminology or manually change the JSON type to action. The v7 migration retains compatibility fields, but new designs should use the single action field rather than separate domain and service fields supplied by a message.

After parsing the action, the controller splits it at the first period into a domain and service; if either part is missing, the action format is invalid. An action taken from configuration is rendered with Mustache and then converted to lowercase. The target combines the five v7 configuration groups with an allowed msg.payload.target; data is merged according to the JSON or JSONata, context, and payload rules. The controller then calls HA WebSocket call_service.

Layerv7 persisted fieldResponsibilitySafe default
Operation typeactionAn HA action in domain.service formPLACEHOLDER_HA_ACTION; reject input overrides
TargetentityId, deviceId, areaId, floorId, labelIdSelect the scope of the callOne minimal placeholder; prohibit broad default scopes
Argumentsdata/dataTypeAction-specific argumentsFixed schema and types; reject additional fields
Dynamic mergingmergeContext, mustacheAltTagsContext or a JSON template/JSONataLeave blank unless needed; if used, restrict keys and data owners
Execution boundaryqueue, blockInputOverridesDisconnected behavior and message overridesnone, true
OutputoutputPropertiesMap sent data, results, or other valuesOutput only required fields, never secrets or complete attributes

The example demonstrates this safe baseline exactly: v7, queue set to none, Block Input Overrides set to true, debugenabled set to false, placeholders as the only targets, and the entire Action disabled. Its data is a static illustrative string. This does not mean that the action accepts that argument, and importing the flow does not send it automatically.

Review an Action as a non-executable draft

  1. Inspect the safe example without running it.

    Open 07-action.json and verify type: "api-call-service", version: 7, and d: true. The Inject node is manual and unscheduled, but the Action must remain disabled; do not confuse “manual” with “free of side effects.”

  2. Describe a specific but non-executable scenario.

    For example: “An approved test-notification draft for one test recipient only, with the fixed content TEST_ONLY_NO_SEND.” The JSON must still contain only PLACEHOLDER_HA_ACTION and PLACEHOLDER_ENTITY_ID, not a real action, notification endpoint, or device.

  3. Separate action, target, and data.

    Put only a placeholder operation name in action; select only one type of minimal placeholder ID as the target; and list only fixed fields permitted by that action’s official schema in data. Reject unknown fields, template input, and the complete msg object.

  4. Lock down input and the queue.

    Keep Block Input Overrides=true and queue=none. Document which payload keys could affect action, target, or data if the lock were removed, but do not disable it for “convenience.” On disconnection, prefer an explicit failure to deferring a control operation until an uncertain future time.

  5. Define the output and error contracts.

    If the action has no response, retain only a sanitized correlation ID. If it does return a response, map it to a property such as msg.actionResult and validate its shape. Catch and Status handling should record only the placeholder action, error category, and time—not data content or a real target.

  6. Complete the risk and recovery review.

    The target owner must confirm the scope, whether duplicate calls are safe, the queue and reconnect policy, rate limits, manual stop procedure, and recovery plan. The review record must precede any environment change; this chapter does not instruct you to enable, deploy, or send an Action.

{
  "status": "DISABLED_NON_EXECUTED_DRAFT",
  "action": "PLACEHOLDER_HA_ACTION",
  "target": { "entity_id": ["PLACEHOLDER_ENTITY_ID"] },
  "data": { "message": "TEST_ONLY_NO_SEND" },
  "blockInputOverrides": true,
  "queue": "none"
}

The block above is review documentation, not an importable flow or an executable HA request. Do not replace action and target with real values and then use it directly; whether data is valid depends entirely on the schema of the action that may later be approved.

Input overrides, data merging, and the side-effect threshold

v7 InputService can read msg.payload.action, msg.payload.target, and msg.payload.data from a message; legacy compatibility also recognizes payload domain and service fields. When Block Input Overrides=true, InputService disables these message overrides: action comes from configuration, target comes from the five configured selectors, and payload data does not participate in data merging. Every Action should retain this safe default.

If block=false, a payload action can replace the configured action, payload target is deep-merged with the configured target, and payload data has the highest precedence in data merging. Even if an upstream node intends to change only one text field, an attacker or faulty node could change the action and its target. For any HTTP, MQTT, webhook, Dashboard, Assist, or cross-flow input, type checking alone is insufficient. Establish an action allowlist, a target allowlist, and a data schema, then construct a new, clean msg object.

Data can use JSONata or JSON. JSON mode performs Mustache rendering before parsing; optional alternate tags change only the template delimiters for the data field. JSONata runs through the Node-RED evaluator. Neither one is HA Jinja or JavaScript. Never treat untrusted strings as templates, and never place tokens, headers, or credentials in data or context.

mergeContext names one context key. The node reads the global object first, overlays the flow object, and—when input overrides are allowed—finally overlays payload data; configured data has the lowest precedence. block=true removes only the payload layer, so context can still override configuration. Before enabling mergeContext, restrict who can write that flow/global key, define its object shape and retention period, and establish a clearing procedure.

Blocking overrides is not a complete policy: it blocks message overrides, but it does not detect a real target selected incorrectly in the editor, prevent contamination through mergeContext, impose rate limits, or require a second confirmation. High-risk targets also require human approval, a narrow allowlist, a cooldown, and an observable stop path.

Entity, device, area, floor, and label targets

The v7 editor’s Target selector supports five ID types. Configuration fields become HA target keys: floor_id, area_id, device_id, entity_id, and label_id. An empty configuration array omits that key; at runtime, a single entry may become a string while multiple entries remain a collection. Values can render environment variables or Mustache, so environment and context values also belong within the review boundary.

Target typeNon-executable placeholderScope riskReview question
entityPLACEHOLDER_ENTITY_IDMost precise, but renaming or replacing the ID can break itIs this a dedicated test entity, and does it permit this action?
devicePLACEHOLDER_DEVICE_IDOne device can contain multiple entities and capabilitiesIs the action’s actual scope on the device clear?
areaPLACEHOLDER_AREA_IDMembership changes as entity and device assignments changeCould new members be included without review?
floorPLACEHOLDER_FLOOR_IDBroader than an area and may span multiple spacesIs an entire floor truly necessary? Deny it by default.
labelPLACEHOLDER_LABEL_IDLabel membership can expand dynamicallyWho can change the label, and are changes monitored?

Being selectable in the UI does not mean that every action accepts every target type. The editor filters or hides the target selector according to HA service metadata, and an unknown action may lack reliable metadata. Check the action documentation and services metadata for the target HA version. Place an entity ID exactly where the action schema specifies; do not invent fields from screenshots or rely on compatibility relocation.

0.80.3 version detail: some legacy actions define entity_id in data fields rather than in target. The controller checks service metadata. If it finds fields.entity_id, data does not already contain entity_id, and the merged target.entity_id is a single string, it warns and temporarily moves that value into data. This compatibility path does not move an array target. The behavior is documented for removal in 1.0; do not depend on it, and correct affected flows before upgrading.

Several target types can be merged at once, potentially producing a union of scopes rather than narrowing the selection by intersection. A safe draft uses only one, most precise target type at a time. Treat areas, floors, and labels as dynamic groups and recheck their members before every call. Documentation, Debug output, and issues must show placeholders only, never real IDs.

Action-dependent data, queues, and concrete safe scenarios

The selected HA action defines the data schema; there is no guarantee of a universal message, brightness, or temperature field. The editor can display descriptions and example data from HA services metadata, but that metadata belongs to the connected environment and should not be fabricated in a UI or screenshot. Even loaded example data is only a draft: remove unnecessary fields and verify every type, range, and unit.

Keep all three concrete safety scenarios non-executable:

  • Test-notification draft: action=PLACEHOLDER_HA_ACTION, target=PLACEHOLDER_ENTITY_ID, with only the fixed value TEST_ONLY_NO_SEND in data. Verify that the recipient scope is minimal, the content contains no state attributes, and duplicate delivery has a defined policy; keep the example node disabled.
  • Test device-state-change draft: use only PLACEHOLDER_DEVICE_ID as the target and name no operable domain or entity. First prove that a duplicate call can be reversed, someone will monitor the physical site, and an independent stop path exists; do not connect a real event.
  • Area-maintenance draft: use only the corresponding placeholder for an area, floor, or label, and first export its membership for human review. Reject any membership beyond one test scope, and do not use a queue to deliver missed operations.

Queue settings affect messages only while HA is disconnected: none immediately raises NoConnectionError; first retains only the first message; last replaces the retained message with the latest one; and all appends every message to an in-memory array. Once the connection is ready, the controller retrieves entries with pop(), so an accumulated set is processed from the end of the array; do not assume FIFO order. The queue is not durable, has no hard limit verifiable in this chapter, and does not provide exactly-once delivery.

QueueWhile disconnectedRiskRecommendation
noneRaise an error immediatelyRequires explicit failure handlingSafe default; do not defer control
firstRetain the first message only while the queue is emptyLater intent is lost, and the retained intent may be stale at reconnectionDo not use without strict proof of timeliness
lastReplace the retained message with the latest oneIntermediate events are lost, and the latest intent may still become staleRequires a version or timestamp gate before evaluation
allRetain every message in memoryUnbounded growth, a reconnection burst, and non-FIFO processingProhibit for control Actions

If the business truly requires a reliable work queue, use a dedicated architecture with persistence, ordering, deduplication, deadlines, cancellation, and a dead-letter contract. The Action node’s four queue options are not a substitute. After recovering from a disconnection, query Current State again instead of blindly replaying stale control operations.

Output properties, return_response, and errors

Response support and response shape depend on the selected action. Do not assume every action returns data or that results are always written to msg.payload. A destination property is written only when Output Properties explicitly maps a value to it.

0.80.3 version detail: the HA WebSocket wrapper checks the HA version and services metadata before making a call. On HA 2023.12 or later, if the specified action’s metadata contains response, the outgoing call_service sets return_response to true; without response metadata, it sets the flag to false. On older HA versions, it does not set the value. This chapter’s baseline still follows the package README prerequisite of HA 2024.3+; this conditional only explains the runtime boundary.

When the call promise resolves, the controller exposes response?.response as the Output Properties source results. It also combines the domain, service, data, and target actually sent into the sentData source.

Output value typeContentsPossible conditionRecommended mapping
sentDatadomain, service, data, and targetMay contain environment IDs or sensitive argumentsDo not output the complete object; extract only a sanitized correlation field
resultsThe response portion of the HA call responseAction-dependent and possibly undefinedWrite to msg.actionResult, then validate its shape
msgThe input message is available for mappingMay contain external dataPreserve only necessary allowlisted fields
No output propertiesSend the original message after successThe payload does not automatically become the resultDownstream nodes must not assume the payload is a response

return_response is a WebSocket call flag chosen by the wrapper from action metadata, not a general-purpose argument to put in data. The HA action defines whether it supports or requires a response and what that response contains. Verify rolling behavior against the official documentation and services metadata for the target HA version.

Common errors include being disconnected with queue=none, an invalid action format, unparseable JSON, a schema-invalid input, a rejected HA call, or a connection failure during the call. None of these produces a successful output mapping. Use Catch to capture errors and Status to observe state, terminating the error branch in a bounded Debug or alerting design. Never change the target automatically and retry, or write complete data, responses, tokens, or real IDs to logs.

A retry policy must account for whether the action is idempotent. A network timeout can occur after HA has executed the action but before Node-RED receives the response, so an immediate retry may duplicate the side effect. A safe design requires a request or correlation ID, action-specific verification, a retry limit, backoff, and manual recovery—not merely checking whether output arrived.

Troubleshooting

  • The palette shows Action, but the export says api-call-service: this is the expected persisted type in 0.80.3. Do not change it manually to action or rebuild the node simply because of its legacy name.
  • The action format is invalid: keep the node disabled and confirm that the draft uses the complete PLACEHOLDER_HA_ACTION; any subsequently approved value must use domain.service form. Do not guess with a real action merely to test it.
  • The target is broader than expected: check whether entity, device, area, floor, and label targets coexist; whether payload.target is merged when block=false; and whether area, floor, or label membership changed. Abort the change and return to one placeholder allowlist entry.
  • Configured data was replaced by another value: check mergeContext. Even with Block Input Overrides=true, flow or global context can override configured data. Clear the contaminated key, inventory its writers, and enforce a fixed schema.
  • msg.payload has no response after success: this can be normal. Confirm that the action metadata declares a response, then explicitly map results to the chosen property in Output Properties. Do not fabricate a result for an action with no response.
  • Stale operations appear after reconnection: stop the side-effect branch immediately and check whether queue is anything other than none. first, last, and all can all retain stale intent, and all is processed with pop. Restore queue=none for control operations.
  • Only a timeout is visible, so HA execution is uncertain: do not retry immediately. Verify the outcome with an action-specific read-only query, retain a sanitized correlation value, and follow the idempotency and manual recovery policy.
  • Debug output or logs contain a real target or data: disable the full Debug output immediately and sanitize the sidebar, logs, exports, and issue reports. If credentials may have been exposed, follow the incident rotation procedure without reposting the value.

Pinned sources

The only related download is 07-action.json. It is for offline review only: the Action node is disabled, and every environment-specific field uses a placeholder. This site provides no real action, entity, device, area, floor, label, or executable screenshot.

FAQ

Why does the UI say Action when the JSON type is not action?
Version 0.80.3 retains the persisted type api-call-service for compatibility with existing flows. The palette label and persisted registration can differ; do not edit the JSON type manually.
Does Block Input Overrides=true prevent all dynamic data from affecting the node?
No. It blocks input overrides such as payload action, target, and data, but global and flow objects selected by mergeContext can still override configured data, and the editor configuration itself can select the wrong target. You still need allowlists, an inventory of context writers, and human review.
Can a target use entity, area, and label at the same time?
The runtime can combine several target keys, but this may expand the scope rather than narrow it by intersection. A safe draft selects only one, most precise placeholder type at a time; recheck area, floor, and label membership before calling.
Is Queue all a reliable offline FIFO?
No. It exists only in memory, has no hard upper limit verifiable in this chapter, and is processed with array pop() after the connection becomes ready. It offers no exactly-once, deadline, or durability guarantee. Use queue=none for control Actions.
Does every Action write its return value to msg.payload?
No. A response depends on action metadata; the controller only exposes response?.response as the results source, which still requires explicit mapping through Output Properties. Allow for undefined when there is no response.
Can I retry an Action immediately after a timeout?
No. HA may have executed it even though the response was lost. First verify the outcome with an action-specific read-only query, then follow the idempotency, retry-limit, and manual recovery policy.