The Gateway Script Handler
The Gateway Script Handler
The script handler runs one of your scripts with a delivered file in its input context. It is the general-purpose handler: anything the built-in ones do not cover.
Configure it on a route by choosing the Script handler and naming the script.
What the script receives
function main(context) {
context.file_name // "purchase_order.edi" — the name the partner used
context.file_path // "/inbound/edi/purchase_order.edi"
context.file_size // bytes
context.file_sha256 // content hash
context.file_content // the file as TEXT — see the warning below
context.file_base64 // the file as BASE64 — the intact bytes
context.file_id // the transfer id, as a string
context.s3_key // where it was stored
context.principal_id // which login delivered it, as a string
context.protocol // "sftp" or "ftps"
context.company_id
context.user_id
}
The run is recorded in the script's own execution history with
triggered_by = "file_gateway", so its output and console logs are where you would expect.
Use file_base64 for anything that is not plain text
file_content destroys binary files. It is
a text view of the bytes. Encoding it as JSON replaces every byte sequence that is not valid
UTF-8 with the Unicode replacement character — and those bytes do not come back. A scanned PDF or an
image handed to a script this way is corrupted before the script sees it, which rules out exactly the
document work these scripts exist to do.This is measurable rather than theoretical. Uploading a 256-byte file containing every possible byte value and reporting what the script could see:
{
"bytes_received_by_gateway": 256,
"chars_visible_to_script": 256,
"replacement_chars": 128, <-- half the file, gone
"file_base64_present": true,
"verdict": "base64 available — binary is recoverable"
}
128 of 256 bytes were replaced in file_content. The same file read
from file_base64 is byte-for-byte intact.
| File type | Use |
|---|---|
| EDI, CSV, JSON, XML, plain text | file_content — convenient and correct |
| PDF, TIFF, PNG, JPEG, Excel, ZIP, anything compressed or signed | file_base64 — always |
file_base64 is also what the OCR API wants, so it passes straight through:
const result = ocr.extractProfile({
profileId: "1195805445820416012",
base64: context.file_base64,
mediaType: "application/pdf"
});
content_base64, connector_name
and file_extension. None of those exist on a gateway run. Reading them
gives undefined, and it looks like a routing problem.The script's return value decides the transfer
The gateway marks a transfer processed once it has started the right script with the right bytes — that is all it can know at that moment. When the script finishes, its verdict is carried back to the transfer.
| The script… | Transfer becomes | Reason shown |
|---|---|---|
| Throws an error | failed | The error message |
Returns { success: false, script_message: "…" } | failed | Your message |
Returns { success: false } with no message | failed | "the script reported the file could not be accepted" |
Returns { success: true } | unchanged (processed) | — |
Returns anything with no success key, or nothing | unchanged (processed) | — |
success: false matters. A script that
runs cleanly and returns success: false has made a judgement — this invoice has
no PO number, this order references a part we do not make. The runtime calls that run a success,
because "success" there only means nothing threw. Reading the returned value is what lets a script
reject the document that arrived instead of merely logging that it disagreed with it —
and it is what makes "show me today's failures" return the failed invoice instead of a clean sheet.If script_message is absent, message and then error are used.
A rejecting script
function main(context) {
const text = context.file_content;
const po = (text.match(/PO[- ]?(\d{4,})/) || [])[1];
if (!po) {
return { success: false,
script_message: "no PO number in " + context.file_name };
}
const rows = odbc.executeQuery("open_purchase_orders");
if (!rows.some(r => r.po_number === po)) {
return { success: false,
script_message: "PO " + po + " is not open" };
}
return { success: true, script_message: "matched PO " + po };
}
Both rejections turn the transfer red in the transfers console with the reason on the row.
There is no gateway.* script API
A run already receives everything about its own transfer. Reading other transfers is reporting work, and it belongs in the console rather than in a sandbox.