Skip to main content

Source Nodes

A source node brings a message into the workflow. This page lists the fields for each source type and how to set them.

Fields marked needed to start must have a usable value before the node will start. Everything else has a working default or belongs to an optional mode.


Source HTTP

Accepts inbound HTTP requests. Your script parses the request and sends the response.

FieldDefaultNotes
Route Path(empty)Needed to start. The path this node answers, for example /intake.
Worker Count1Needed to start, and must be at least 1. Concurrent requests handled.

Its Lua script is created with the node and is also needed to start.

The server is installation-wide

There is no port field on this node. Every HTTP source node answers on one embedded server, configured in Settings → Http Server: Use Server, Port, and optionally Secure with its certificate fields.

Settings → Http Server port 9001
├─ /intake → Source HTTP node "Intake" (project A)
└─ /discharge → Source HTTP node "Discharge" (project B)

Consequences worth knowing:

  • Route Path must be unique across every HTTP source node that is running, not just within one workflow. Two nodes claiming /intake cannot both answer it.
  • Changing the port affects every HTTP source node on the installation.
  • Turning Use Server off stops all of them.
  • Enabling Secure makes every route HTTPS, not just some.

Prefix routes with the interface they belong to — /adt/intake, /orders/intake — so a second project cannot accidentally claim a path a first one already uses.

Worker Count

How many requests the node handles simultaneously. Each worker is an independent script instance.

ValueBehaviour
1Strictly sequential. One request at a time, in order.
HigherConcurrent. Requests are handed to a free worker, and queue briefly if all are busy.

Raise it when concurrent inbound requests matter and your script does not depend on ordering. Leave it at 1 when you want predictable sequential handling.

Do not keep state in module-level variables when Worker Count is above 1. Each worker has its own copy, so the behaviour depends on which worker took the request.

Working with the request

main(Data) receives the complete raw HTTP request text. Parse it and respond:

local linkiir = require("linkiir")

function main(Data)
local req, err = linkiir.link.web.request{ data = Data }
if not req then
linkiir.link.web.respond{ code = 400, body = "Bad request" }
return
end

linkiir.flow.push{ data = req.body }

linkiir.link.web.respond{
code = 200,
contentType = "application/json",
body = '{"accepted":true}',
}
end

Method checks, path checks, authentication, and body size limits are yours to enforce in the script — there are no node fields for them. Reject what you do not accept with an explicit status code rather than letting it through.

:::caution There is no authentication field on this node An HTTP source node answers any request that reaches its route. If the node needs to be reachable beyond your own machine, enforce authentication in the script and restrict access at the network layer. See Security. :::

Walkthrough: Edit the Script and Start the HTTP Server.


Source LLP

Accepts HL7 v2 messages over an MLLP socket and returns an ACK.

Core fields

FieldDefaultNotes
Listen Port5349Needed to start, and must be greater than 0.
Acknowledgment ModeDefaultNeeded to start. Default or Custom.
Message EncodingWestern (ISO-8859-1)Character encoding of inbound messages.
Connection TimeoutoffTurn on to close idle connections.
Connection Timeout Minutes30Shown when Connection Timeout is on.

With Custom, an ACK script is also needed to start.

Framing

FieldDefaultNotes
LLP DelimitersNormal LLPNormal LLP or Custom.
Messages Begin After\x0BStart byte, with Custom.
Messages Continue Until\x1C\x0DEnd bytes, with Custom.

Leave LLP Delimiters on Normal LLP unless the sending system documents non-standard framing. Mismatched framing shows up as messages that never complete or connections that hang, rather than as a clear error.

TLS

FieldDefaultNotes
Use SSLoffTurn on to accept TLS connections.
Certificate File(empty)Shown with Use SSL.
Private Key File(empty)Shown with Use SSL.
Verify PeeroffRequire and verify a client certificate.
Certificate Authority File(empty)Used when verifying the peer.

Choosing an acknowledgment mode

ModeUse when
DefaultThe sender accepts a standard ACK. Fastest, no script to maintain.
CustomThe sender requires specific ACK codes, application-level validation, or non-standard fields.

With Custom, the value your script returns is sent back to the sender as the ACK.

Decide deliberately what you acknowledge. An ACK sent before the message is safely handed onward tells the sender the message is accepted when it may not be — and once a sender has an ACK, it will not resend.


Source File/FTP

Polls a directory, or an FTP/FTPS/SFTP server, and creates one message per file.

Core fields

FieldDefaultNotes
Interval10000Needed to start, and must be greater than 0. Poll interval in milliseconds.
Input Directory(empty)Needed to start. Directory to poll.
File Extension(empty)Needed to start. Which files to pick up.
Minimum File Age0Seconds a file must be untouched before it is read.
Input File Type(empty)Arbitrary text, HL7, or X12.
Input File EncodingWestern (ISO-8859-1)Character encoding of file contents.
Hex EOF Character(empty)End-of-file marker, when the sender writes one.
Ignored Segments List(empty)Segments to skip, for HL7 and X12 input.

:::caution Set Minimum File Age when a sender writes in place A poller can read a file the sender is still writing, producing a truncated message. Set Minimum File Age to a few seconds, or ask the sender to write to a temporary name and rename on completion. A rename is atomic and needs no age delay. :::

After a local file is processed

FieldOptions
Processed FilesDelete processed files or Move processed files
Processed File PathWhere successful files go, with Move processed files
Error File PathWhere failed files go

Prefer Move processed files over deleting. A directory of processed files is the fastest way to answer "did we receive it?", and it lets you re-drop a file to reprocess it.

FTP, FTPS, and SFTP

Turn on Use FTP to poll a remote server instead of a local directory.

FieldDefaultNotes
FTP ProtocolFTPFTP, FTPS (FTP over SSL), or SFTP (Secure Shell FTP).
AuthenticationUsername/PasswordUsername/Password or Private/Public Key. Shown for SFTP.
FTP Server(empty)Needed to start when Use FTP is on.
FTP Port21
FTP Username(empty)Needed to start when Use FTP is on.
FTP Password(empty)For password authentication.
FTP Path(empty)Remote directory to poll.
Certificate File, FTPS Private Key File(empty)For FTPS.
SFTP Private Key File, Public Key File(empty)For key-based SFTP.
Verify PeeroffLeave on outside a trusted network.
Verify Host FingerprintoffLeave on outside a trusted network.
Attempt to ReconnectNoNo, Yes (unlimited), or Yes, with limit.
Reconnect Limit Times60With Yes, with limit.
Reconnection Interval10000Milliseconds between attempts.

After a remote file is downloaded, a second Processed Files field controls the remote side, with its own options: Delete remote files after downloading or Move remote files after downloading to another remote directory. With the move option, set FTP Path for Downloaded Files.

:::note Two fields named Processed Files With Use FTP on, the form shows two fields with this label — one for the remote server and one for the local directory. Tell them apart by their options: the remote one names remote files. :::

Choose SFTP or FTPS over plain FTP. Plain FTP sends credentials and file contents unencrypted.

Put the password in the project's Credentials tab flagged Secret, and reference it, rather than typing it into the node. See Project Settings.


Source Custom

Runs your script on a timer. Use it when you fetch data yourself — from an API, a database, or a computation — rather than receiving it.

FieldDefaultNotes
Interval10000Needed to start, and must be greater than 0. Milliseconds between runs.

Its Lua script is also needed to start.

main is called with no argument on this node type — there is no inbound message. Fetch or build your data and push each message:

local linkiir = require("linkiir")

function main()
local resp, err = linkiir.link.web.get{
url = "https://api.example.com/pending",
timeout = 15,
}
if not resp then
error("fetch failed: " .. err.message)
end
if resp.code >= 400 then
error("source returned " .. resp.code)
end

linkiir.flow.push{ data = resp.body }
end

Declaring main(Data) here is harmless, but Data will be nil. Write main() so the signature matches what actually happens.

Interval guidance

IntervalSuits
10005000Near-real-time polling of a fast, cheap source
1000060000Normal polling of an API or directory
MinutesBatch pulls, scheduled extracts

Keep the run shorter than the interval. A run that regularly takes longer than its interval means the node is always busy and the schedule stops being meaningful.

There is no cron-style schedule. For "once a day at 02:00", poll at a sensible interval and have the script decide whether it is time to act.


Handling script errors

Custom nodes run your code, so a script error is a case you need to decide about. Whether an error stops the node or is skipped is behaviour of the node's error handling — see Error Handling and Retry for how to choose, and for keeping payload content out of error text.

For clinical interfaces, prefer stopping. A node that quietly skips messages can discard a day of data before anyone notices, and the durable queue means stopping loses nothing.


Next