REST Endpoints
A pipeline can publish an HTTP endpoint. An ERP posts an order, an MES asks for line status, a label printer requests the next job — each arrives as a message that runs your graph and returns whatever you build.
Published routes are served by the RestGateway on port 8090.
Building one
REST API (ingress) → Python (validate) → MongoDB (insert) → HTTP Response
- REST API node in
ingressmode defines the method and URL pattern. - Middle nodes do the work.
- HTTP Response sends the reply. Every ingress path must reach one, or the caller waits for the timeout.
Route configuration
| Setting | Default | Purpose |
|---|---|---|
| Method | GET | GET, POST, PUT, DELETE, PATCH, or * for any. |
| URL pattern | /api/v1/example | Supports parameters: /api/v1/orders/:id. |
| Timeout | 30 s | How long the caller waits before the gateway gives up. |
| Auth type | api_key | api_key or none. |
| Required scopes | (none) | Capability scopes the caller's key must hold, e.g. tag:write,db:read. |
| Allowed IPs | (any) | Comma-separated CIDR allow-list. |
| Rate limit | 0 (off) | Requests per second. |
| Burst limit | 0 | Burst size above the sustained rate. |
| Max payload size | 1 MB | Request body cap. |
| CORS enabled | false | Allow browser cross-origin calls. |
| Allowed origins | * | Origins permitted when CORS is on. |
| Header whitelist | (none) | Request headers passed through to the pipeline. |
Fail-closed by default
A route persisted without an explicit auth type requires an API key. A route is public only when
its author deliberately sets auth to none.
This is the correct default for an industrial system: a route that silently defaulted to public would be a data leak created by omission.
API keys
Keys are project-scoped credentials created in settings.
Keys are managed in Settings → API keys, which requires Access settings.
- The key value is shown once, at creation. Only a hash is stored.
- Revocation is immediate.
- Give each consumer its own key, so one can be revoked without disrupting the others.
→ API keys
Scopes
A key carries capability scopes; a route can require some. A key without a required scope is rejected even though it is otherwise valid.
Key "mes-integration" scopes: db:read, tag:read
Route POST /api/v1/setpoint requires: tag:write → rejected
Route GET /api/v1/status requires: tag:read → allowed
Scopes let one key serve several routes at a bounded level of privilege.
Defence in depth
Layer the controls; each is cheap and independent.
| Control | Stops |
|---|---|
| API key | Unauthenticated callers |
| Scopes | An authenticated caller doing more than it should |
| IP allow-list | Calls from outside the expected network |
| Rate limit + burst | Runaway clients and brute-force attempts |
| Max payload size | Memory-exhaustion attempts |
| CORS off | Browser-based cross-origin abuse |
An integration endpoint for a known MES should have: an API key, the narrowest scopes, the MES's CIDR, a rate limit slightly above its real traffic, and CORS off.
Calling an endpoint
curl -X POST https://qubiq.example.com:8090/api/v1/orders \
-H "X-API-Key: <key>" \
-H "Content-Type: application/json" \
-d '{"orderId":"SO-1042","line":"L1","qty":500}'
Reading request data
The request arrives as the message payload — body, path parameters, query string and whitelisted headers.
def transform(payload, message):
order = payload.get("body", {})
if not order.get("orderId"):
return {"status": 400, "body": {"error": "orderId is required"}}
system.db.runNamedQuery("insert_order", {
"id": order["orderId"],
"line": order.get("line"),
"qty": order.get("qty", 0),
})
return {"status": 201, "body": {"accepted": order["orderId"]}}
Only whitelisted headers are passed through — an explicit choice, so that authorization headers and cookies are not handed to pipeline code by accident.
Outbound calls (egress)
The same node in egress mode calls out: post an alarm to a webhook, fetch a work order, push
a report to an external API.
| Setting | Purpose |
|---|---|
| URL, method | The target |
| Static headers | Added to every request (e.g. an authorization header) |
| Timeout | Give up after this long |
Egress calls made from a pipeline are covered by store-and-forward, so a webhook that is briefly down does not lose the event.
Operational notes
- Port 8090 must be reachable by the caller; it is separate from the UI port.
- The pipeline must be running. A stopped pipeline's routes return an error.
- Version your URLs (
/api/v1/...). Changing a pipeline's response shape breaks callers exactly as changing any API does. - Return meaningful status codes from the HTTP Response node. A 200 carrying an error message is hostile to whoever integrates with you at 03:00.
Troubleshooting
| Symptom | Check |
|---|---|
| 404 | Pipeline stopped, or the URL pattern does not match (leading slash, trailing slash, method). |
| 401 / 403 | Missing or revoked API key; missing required scope; source IP outside the allow-list. |
| 413 | Body exceeds max payload size. |
| 429 | Rate limit hit — raise it or fix the client. |
| Timeout | No HTTP Response node was reached on that path. |
| CORS error in a browser | CORS disabled, or the origin is not in the allowed list. |
Next
→ Designer