Appearance
Outbound REST Calls
Last updated
License feature: REST API OutboundAn outbound API configuration sends an HTTP request from the appliance to another system — on a timer, when a tag changes, or when you trigger it — with a JSON body filled in from live tag values. Use it to push a counter to an ERP endpoint, post a machine state to a cloud service, or call a webhook.
For a one-off call inside logic, the workflow Call URL node or a script's http.post is often simpler — see Communication Nodes.
Where and who
Visualize → Data Infrastructure, tab Outbound API. Needs the rest_api_outbound licensed feature. Viewing needs any role; creating, editing and testing need editor; deleting needs admin.
Tokens, passwords and API keys entered here — bearer tokens, basic-auth credentials, API keys, and any header value that looks like one — are encrypted on the appliance. The API and the page show them back as ••••••••, for every role including viewers; a saved call keeps working, and editing something else on the same configuration does not require re-entering the credential.
Any of them — and the URL, which may carry a ?token= of its own — can instead be a reference to the Secrets store, written ${secret:API_TOKEN}. A reference is a name rather than a credential, so it is shown as you typed it instead of masked, and the value is looked up for each call: rotate the endpoint's token in Secrets and every call that references it uses the new one. A name that matches no secret fails the call with Secret "API_TOKEN" is not in the Secrets store as its last status, and nothing is sent to the endpoint.
Create a call
- Open Data Infrastructure → Outbound API and click New Outbound API.
- Enter Name and URL, for example
https://erp.plant.local/api/production. - Choose HTTP Method (usually POST).
- Choose a Trigger and its settings.
- Choose Auth Type and fill in the credentials.
- Write the Body Template.
- Click Create, then the Test / Manual Trigger icon. The result shows Success (HTTP 200) or Failed: ….
Fields
| Field | What it does | Default | Notes |
|---|---|---|---|
| Name | Label | — | Required |
| URL | Target address | — | Required; http:// or https://. A password in the URL itself (https://user:pass@host/…) is encrypted and masked the same as the auth fields |
| HTTP Method | POST, PUT, PATCH or GET | POST | GET sends no body |
| Trigger | Manual, Timer or Tag Change | Manual | |
| Interval (seconds) | Timer period | 60 | 0 or blank means 60 |
| Trigger Tag | Device and tag to watch (Tag Change) | — | Fires on every change |
| Auth Type | None, Bearer Token, Basic Auth, API Key | None | |
| Token | Sent as Authorization: Bearer <token> | — | Bearer only |
| Username / Password | Sent as Authorization: Basic … | — | Basic only |
| Header Name / API Key | Sent as <Header Name>: <key> | X-API-Key | API Key only |
| Custom Headers (JSON) | Extra headers as a JSON object of text values | {} | Invalid JSON shows an error and can't be saved |
| Body Template | Request body with tag placeholders | empty (sends {}) | See below |
Body template
Write the JSON you want to send and put {{deviceId:tagPath}} where a live value should go:
json
{
"machine": "Press 4",
"partCount": {{3:Counter/PartCount}},
"dieTemp": {{3:HR100}},
"job": "{{1:CurrentJob}}"
}- Each placeholder is replaced with the tag's current cached value, written as valid JSON for where it sits.
- Inside quotes (
"{{1:CurrentJob}}") the value is escaped as text, so quotes, backslashes and line breaks in it don't break the body. A tag with no value gives an empty string. - Without quotes (
{{3:HR100}}) a number stays a number,true/falsestay booleans, anything else becomes quoted text, and a tag with no value becomesnull. - The header
Content-Type: application/jsonis sent unless Custom Headers override it. With a non-JSON content type, values are inserted exactly as they are, with no escaping.
Behavior to know
- Timeout 15 seconds. No retries and no store & forward — a call that fails while the network is down is simply missed.
- Tag Change sends one request per change. A fast-changing tag can send several requests a second; use a timer for those.
- The list shows each call's method, URL, trigger and last status (
successorerror:<HTTP status or message>) with its time. The response body is not kept. - A failure sends one Outbound API Failed notification, and Outbound API Recovered when calls succeed again.
- Calls cannot be paused from the tab; delete them or set the trigger to Manual.
- Test / Manual Trigger sends a real request with real values — point it at a test endpoint first.
API
| Method | Path | Role | Purpose |
|---|---|---|---|
| GET | /api/data-infra/outbound-api | viewer | List configurations |
| GET | /api/data-infra/outbound-api/:id | viewer | One configuration |
| POST | /api/data-infra/outbound-api | editor | Create |
| PUT | /api/data-infra/outbound-api/:id | editor | Update |
| DELETE | /api/data-infra/outbound-api/:id | admin | Delete |
| POST | /api/data-infra/outbound-api/:id/test | editor | Send now |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
error:400 | The target rejected the body — for example the template itself isn't valid JSON | Check the template outside the placeholders |
error:401 / error:403 | Wrong or missing credentials | Check Auth Type and credentials |
error:fetch failed or a DNS/connection message | Appliance cannot reach the URL (no route, DNS, firewall, TLS) | Test from the appliance network; use an IP if DNS is not available |
error:The operation was aborted due to timeout | No answer within 15 s | Check the target service |
Custom headers must be a JSON object | Invalid JSON in Custom Headers | Fix the JSON, for example {"X-Site": "PlantA"} |
| Nothing sent on Tag Change | Trigger tag not set, or the tag does not change | Pick the device and tag; check the tag is live |
Name and URL are required | Missing field | Fill both |