How to Reach a Manufacturing MES with No Native Connector via the HTTP Connector
Pull completed production runs from your manufacturing execution system (MES) on a schedule, sign the request the way the vendor's API expects, map work-order numbers to NetSuite assembly builds, and record finished-goods receipts, all without a native MES tile.
What This Integration Does
Most MES platforms on a factory floor have no dedicated tile in Spojit, but they almost always expose a REST API. This tutorial reaches that API directly through the http connector, so your shop-floor completions flow into NetSuite as assembly-build updates without anyone re-keying work-order numbers or finished-goods quantities. The result is a clean, auditable bridge between production and your ERP that runs on its own every shift.
The workflow runs on a Schedule trigger, for example every 30 minutes during production hours. On each run it asks the MES for production runs completed since the last poll, signs that request with an HMAC signature using the code connector, reshapes the response with a Transform node so each work-order number lines up with the matching NetSuite assembly build, and calls update-record on the netsuite connector to post finished-goods receipt quantities. Because the call is keyed to a "completed since" timestamp and NetSuite updates are idempotent by record id, re-running the workflow does not double-count: a run already posted is simply written with the same values again.
Prerequisites
- A netsuite connection in Spojit (Connections - Add connection - NetSuite) with permission to read and update assembly-build records. Verify it first with the
verify-connectiontool. - Your MES vendor's REST API base URL, an API key or shared secret, and the documented request-signing scheme (most use an HMAC SHA-256 signature over a canonical string). Keep the signing secret handy for the code step.
- A mapping between MES work-order numbers and NetSuite assembly-build internal ids. A small lookup table (for example a JSON object) is enough to start.
- The NetSuite record type name for your finished-goods build (commonly
assemblyBuild) and the field your account uses for received quantity.
Step 1: Add a Schedule trigger
Add a Trigger node and set its type to Schedule. Enter a 5-field Unix cron expression and an IANA timezone so polling lines up with your shifts, for example */30 6-22 * * 1-6 in Australia/Sydney to poll every 30 minutes between 6am and 10pm, Monday to Saturday. The trigger output is { scheduledAt }, which you can use as the upper bound of your query window. A single trigger can hold multiple schedules if you run more than one shift pattern.
Step 2: Build and sign the MES request with the code connector
Add a Connector node on the code connector in Direct mode and pick execute-python. Compute the lookback window and the HMAC signature your MES expects, then return both the canonical query parameters and the signature so the next step can send them. A typical script:
import hmac, hashlib, datetime
secret = "YOUR_MES_SIGNING_SECRET"
# poll the last 35 minutes so a 30-minute schedule never leaves a gap
now = datetime.datetime.utcnow()
since = (now - datetime.timedelta(minutes=35)).strftime("%Y-%m-%dT%H:%M:%SZ")
# canonical string the vendor documents, e.g. METHOD + path + completedSince
canonical = "GET\n/v1/production-runs\ncompletedSince=" + since
signature = hmac.new(secret.encode(), canonical.encode(), hashlib.sha256).hexdigest()
return {"completedSince": since, "signature": signature}
Keep the secret out of the URL: it only ever lives inside the signing step. The output is available downstream as {{ sign.completedSince }} and {{ sign.signature }} (name the node sign in the properties panel).
Step 3: Pull completed production runs with http http-get
Add a Connector node on the http connector in Direct mode and choose http-get. Point it at your MES REST endpoint and pass the signed parameters from Step 2:
URL: https://mes.yourvendor.com/v1/production-runs?completedSince={{ sign.completedSince }}
Headers: {
"Authorization": "ApiKey YOUR_MES_API_KEY",
"X-Signature": "{{ sign.signature }}",
"Accept": "application/json"
}
The response body is the list of runs the MES finished in the window. If your vendor requires the signature on the request body instead of the query string, use http-post and move the parameters into the body the same way. If the MES paginates, capture the next-page cursor it returns and wrap Steps 2 and 3 in a Loop node so you drain every page before moving on.
Step 4: Map work-order numbers to NetSuite builds with a Transform
Add a Transform node to reshape the raw MES payload into exactly the fields NetSuite needs. For each completed run, look up the matching assembly-build internal id from your mapping table and produce a flat object per build:
// input: {{ runs }} (the array returned by http-get)
const buildMap = {
"WO-10231": "8842", // MES work order -> NetSuite assemblyBuild internal id
"WO-10244": "8857"
};
return {{ runs }}.map(run => ({
recordType: "assemblyBuild",
id: buildMap[run.workOrderNumber],
body: {
quantity: run.completedQuantity,
memo: "MES completion " + run.completedAt
}
}));
Drop any run whose work-order number is missing from the map so an unmapped order never reaches the ERP. The Transform output is a tidy array, one entry per finished-goods receipt to post.
Step 5: Record finished-goods receipts with netsuite update-record
Add a Loop node in ForEach mode over the array from Step 4. Inside the loop, add a Connector node on the netsuite connector in Direct mode and select update-record. Map the loop item straight into the tool's fields:
recordType: {{ item.recordType }}
id: {{ item.id }}
body: {{ item.body }}
Each iteration patches one NetSuite assembly build with the received quantity from the floor. Because update-record targets a specific record id, posting the same completion twice writes the same values rather than creating duplicates, which is what keeps the schedule safe to re-run.
Step 6: Notify the team and handle gaps
Add a Send Email node after the loop to send a short shift summary (count of runs posted, any work orders skipped for missing mapping) to the production planner. Recipients and subject are templated, so you can include {{ runs.length }} in the body. If you would rather flag failures only, wrap the NetSuite call so that on error the workflow continues and collects the failed work-order numbers into the email instead of halting the whole shift. For a richer alert you can swap or add a slack connector node with send-message to your operations channel.
Tips
- Make the lookback window slightly longer than the schedule interval (35 minutes for a 30-minute cron) so a delayed run is never missed at the boundary.
- Keep the HMAC secret only inside the code step, never in the URL or a header you log. Sign the exact canonical string your vendor documents, including the order and casing of parameters.
- Use
verify-connectionon the netsuite connector once after setup to confirm scope before you let the schedule run unattended. - Ask Miraxa, the intelligent layer across your automation, to scaffold this for you: "Build a scheduled workflow that calls https://mes.yourvendor.com with http-get, signs it with execute-python, and updates NetSuite assembly builds with update-record." Then fine-tune each node in the properties panel.
Common Pitfalls
- Signature mismatches are the most common failure: the canonical string must match the vendor's spec byte-for-byte, including the timestamp format and trailing newlines.
- Timezone drift: the MES
completedSincefilter and your cron timezone must agree. Send the timestamp in UTC (theZsuffix) to avoid off-by-one-hour gaps around daylight-saving changes. - Unmapped work orders silently disappear if you drop them without logging. Surface skipped orders in the Step 6 email so a missing mapping gets fixed.
- Pagination: if the MES caps results per page and you do not loop the cursor, busy shifts will only post the first page of completions.
Testing
Before enabling the schedule, point the completedSince value at a known window with one or two finished work orders and run the workflow with the Run button on a Manual trigger copy. Confirm the http-get step returns the expected runs, the Transform produces one entry per mapped build, and the update-record step patches the correct NetSuite assembly build with the right quantity. Check the execution log for each step, verify the values in NetSuite, then re-run the same window to confirm it is idempotent (no duplicates). Only after that switch the trigger back to Schedule and let it run hands-off.