Skip to main content
Data Operations · NGSI-LD and Stellio

Post to Stellio

The node sends an array of NGSI-LD entities via HTTP POST to the batch upsert endpoint of the Stellio context broker. New entities are created, existing ones updated. Status code, response headers and response body are then available in the message.

  • Publish
  • Batch upsert
  • NGSI-LD
Node type
post-to-stellio
Package
@htag/node-red-contrib-hypertegrity-ngsi-ld
Inputs / outputs
1 / 1
Target
Stellio context broker (NGSI-LD)

When to use this node​

Post to Stellio is the last step of the typical data flow: after the NGSI-LD Builder has produced normalised entities from the connector data, this node writes them into the context broker. It uses the endpoint entityOperations/upsert with the option update, so existing entities are updated attribute by attribute and new ones are created without you having to check beforehand whether an entity exists.

Typical use cases are:

  • Regular measurements (weather, air quality, water levels) continuously updated in the same entities.
  • Master data such as parking sites, stops or points of interest loaded once or after changes.
  • Several data spaces (tenants) served from one flow by setting the tenant per message via msg.tenant.

How the node works​

1

Receive message

msg.payload holds the entity array, for example straight from the NGSI-LD Builder.

2

Determine target

API URL and tenant are taken from msg, the node configuration or the environment variable STELLIO_API_URL.

3

Send POST

The payload is sent as application/ld+json to /ngsi-ld/v1/entityOperations/upsert?options=update.

4

Pass on response

Status code, headers and response body are written into the message and emitted.

Result: The entities are stored in the broker; the message carries the broker response for error handling and logging.

The node is message-driven and sends every incoming message immediately as its own HTTP request. For large data volumes, place a Split node with small batches and a Delay node for rate limiting in front of it, as shown in the example flow.

Configuration​

FieldTypeDefaultMeaning
NameTextemptyDisplay name of the node in the flow.
TenantText (required)emptyValue of the NGSILD-Tenant header, i.e. the data space in the broker, for example ds_opendata.
Stellio API URLText${STELLIO_API_URL}Base URL of the broker without the path /ngsi-ld/v1. Node-RED replaces the placeholder with the environment variable of the same name. If the field is empty, the node uses STELLIO_API_URL from the environment.

The API URL is optional because the environment variable STELLIO_API_URL serves as fallback. Without a valid URL the node aborts with an error.

Input​

PropertyTypeMeaning
msg.payloadarray of entitiesSent unchanged as JSON. The batch upsert endpoint expects an array; the NGSI-LD Builder always delivers an array. Every entity must contain id, type and @context, because the node sets no Link header. If the payload is missing, an empty object is sent.
msg.tenantstringOverrides the configured tenant for this message.
msg.stellioApiUrlstringOverrides the configured API URL for this message.

Output​

The incoming message is extended with the broker response. For a batch upsert in which one entity was created and one updated, the output looks like this:

{
"statusCode": 201,
"headers": {
"content-type": "application/json",
"date": "Thu, 01 Oct 2026 06:00:02 GMT"
},
"payload": [
"urn:ngsi-ld:WeatherObserved:exampletown:station-042"
]
}
FieldMeaning
msg.statusCodeHTTP status code of the response. 201 reports newly created entities (their ids are in the payload), 204 a pure update without content, 207 a partial result with successes and errors.
msg.headersAll response headers of the broker.
msg.payloadResponse body as parsed JSON. If the response is not JSON, the raw text is kept; for an empty response the value is null. The original entity array is replaced.
Check the status code

The node forwards the message even for error statuses such as 400 or 500. Check msg.statusCode in a Switch node if you want to handle failed transfers separately.

Example flow​

The package ships with a shared example flow for several Stellio nodes. Import it in Node-RED via Menu → Import → Examples → @htag/node-red-contrib-hypertegrity-ngsi-ld → stellio-helper-nodes. Alternatively download stellio-helper-nodes.json and import it via Menu → Import.

Step 1

Produce data

Inject, Function, Split and Delay deliver air quality records in small, throttled batches.

Step 2

NGSI Builder

The builder converts each batch into AirQualityObserved entities.

Step 3

Post to Stellio

The node writes the entity array via upsert into the tenant of the broker.

Show example flow as JSON (Post to Stellio excerpt)
[
{"id": "tab1", "type": "tab", "label": "Stellio Helper Nodes", "disabled": false, "info": ""},
{"id": "inject1", "type": "inject", "z": "tab1", "name": "", "props": [{"p": "payload"}], "repeat": "", "once": false, "payload": "", "payloadType": "date", "x": 160, "y": 580, "wires": [["func1"]]},
{"id": "func1", "type": "function", "z": "tab1", "name": "Air quality", "func": "msg.payload = [\n {\"id\": \"urn:ngsi-ld:AirQualityObserved:exampledistrict:2026-09-30\", \"type\": \"AirQualityObserved\", \"dateObserved\": \"2026-09-30T00:00:00Z\", \"location\": {\"type\": \"Point\", \"coordinates\": [7.3322, 50.3315]}, \"areaServed\": \"Example District\", \"temperature\": 9.8, \"o3\": 0.1239}\n];\nreturn msg;", "outputs": 1, "x": 350, "y": 580, "wires": [["split1"]]},
{"id": "split1", "type": "split", "z": "tab1", "name": "", "splt": "\\n", "spltType": "str", "arraySplt": "5", "arraySpltType": "len", "stream": false, "property": "payload", "x": 570, "y": 580, "wires": [["delay1"]]},
{"id": "delay1", "type": "delay", "z": "tab1", "name": "", "pauseType": "rate", "timeout": "5", "timeoutUnits": "seconds", "rate": "1", "nbRateUnits": "2", "rateUnits": "second", "drop": false, "x": 140, "y": 700, "wires": [["builder1"]]},
{"id": "builder1", "type": "ngsi-builder", "z": "tab1", "name": "", "contextUrl": "https://context.${DOMAIN}/main-context", "entityType": "AirQualityObserved", "mode": "smart", "entityId": "", "addObservedAt": true,
"mappings": [
{"target": "id", "source": "id", "addObservedAt": true, "required": true},
{"target": "type", "source": "type", "addObservedAt": true, "required": true},
{"target": "dateObserved", "source": "dateObserved", "addObservedAt": true, "required": true},
{"target": "location", "source": "location.coordinates", "addObservedAt": true, "required": true},
{"target": "areaServed", "source": "areaServed", "addObservedAt": true, "required": false},
{"target": "temperature", "source": "temperature", "addObservedAt": true, "required": false},
{"target": "o3", "source": "o3", "addObservedAt": true, "required": false}
],
"customFields": [], "customMappings": [], "overwrites": [], "debugMode": false, "useTransformation": false, "transformationScript": "", "topicFilter": "", "useObservedAtOverwrite": false, "observedAtField": "", "ignoreRequired": false, "enableValidation": true, "invalidExtraFields": false, "invalidMissingOptional": false, "invalidValue": false, "invalidOptionalAction": "skip",
"locationConfig": {"enabled": true, "type": "Point", "posType": "array", "latField": "", "lonField": "", "arrayField": "location.coordinates", "polyField": "", "order": "lonlat"},
"x": 380, "y": 700, "wires": [["post1"]]},
{"id": "post1", "type": "post-to-stellio", "z": "tab1", "name": "", "stellioApiUrl": "${STELLIO_API_URL}", "tenant": "ds_opendata", "x": 590, "y": 700, "wires": [[]]}
]

Status and errors​

The node shows no status below the node icon. Errors are reported via node.error and can be handled with a Catch node.

IndicatorMeaning
Error "Stellio API URL is required"Neither msg.stellioApiUrl, the Stellio API URL field nor the environment variable STELLIO_API_URL is set. The message is not sent.
Error with network message (for example "ECONNREFUSED", "ENOTFOUND")The broker is unreachable or the hostname cannot be resolved. The message is not forwarded.
msg.statusCode 201 / 204 / 207Successful upsert: created, updated or partially successful.
msg.statusCode 400The broker rejects the payload, for example because of a missing @context, an invalid URN or malformed JSON-LD. Details are in msg.payload.
msg.statusCode 401 / 403Access denied. Check the protection provided by the network or an upstream gateway.
msg.statusCode 404The path /ngsi-ld/v1/entityOperations/upsert was not found; check the base URL.

Notes​

  • No Link header: The node sends Content-Type: application/ld+json. The @context must therefore be included in every entity, as the NGSI-LD Builder ensures.
  • Authentication: The node sends no authentication headers; access to the broker is protected by the network or an upstream gateway.
  • Rate limiting: Every message is one request. Combine Split and Delay nodes to avoid overloading the broker during bulk imports.
  • Payload is replaced: After sending, msg.payload holds the broker response, no longer the entities. Store the entities in another property beforehand if you need them later.
  • Personal data: The node transfers all content unchanged into the broker. Check beforehand whether the entities contain personal data and whether the target tenant is approved for it.

References​