InvokeExecute
→ object[]Executes a SOAP Execute call on a fully configured SOAP API object. Use with CreateObject and SetObjectProperty to perform execute-type actions such as sending triggered emails or running queries.
Syntax
Platform.Function.InvokeExecute(apiObject, status)
The official docs list an optional third options argument and type the return value as an object, but at runtime the call takes exactly two arguments and returns an array of result objects — each element carries its own StatusCode / StatusMessage / ErrorCode. status is a genuine out parameter, but the engine only writes into slots the array already has: pass [0, 0] and status[0] receives the OverallStatus string ("OK" / "Error") while status[1] receives a RequestID GUID string (not a number). An empty array ([]) is never grown — it stays at length 0 with both slots undefined, which is why the status out parameter looks inert unless it is pre-sized.
Show test script — array return value, 2-argument arity and the pre-sized status array
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Callout: differs-from-docs — the return value, the status array and the
* argument count.
*
* Proves:
* 1. DEVIATION — the call returns an ARRAY of result objects, not the
* single object the official docs promise. typeof is "object" and the
* value has a numeric length.
* 2. Each element of that array carries its own StatusCode (string),
* StatusMessage (string) and ErrorCode (number).
* 3. DEVIATION — the valid signature is exactly TWO arguments
* (apiObject, status). The third "options" argument the official docs
* describe throws, and so do arity 0 and 1. There is no reachable
* optional argument in either direction.
* 4. status IS a genuine out parameter, but the engine only writes into
* slots the array ALREADY HAS. Passed as [0, 0] it receives the
* OverallStatus string in status[0] and a RequestID GUID STRING in
* status[1] — the docs' "RequestID" slot is therefore a string here,
* not a number (unlike InvokeCreate / InvokeDelete, where status[1] is
* a numeric error code).
* 5. Passed as an empty array [] the status parameter is never grown: it
* stays at length 0 with both slots undefined. That is the behaviour
* that makes the out parameter look inert unless it is pre-sized.
* 6. DISCRIMINATING CONTROL for 4 and 5: the two calls are otherwise
* IDENTICAL — same verb, same parameters, same failure result. Only
* the initial size of the status array differs, so the difference in
* what the status array holds is attributable to that and nothing
* else.
*
* SCOPE: CloudPage only (MCDEV_Training_QA business unit). The page also
* lists automation availability; the automation context was not exercised.
*
* EXPECTED OUTPUT: every line starts with PASS. A FAIL means the runtime no
* longer matches the documented claim and the page must be revised.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
/* Build an ExecuteRequest with the given verb name and APIProperty parameters. */
function execObject(name, params) {
var o = Platform.Function.CreateObject("ExecuteRequest");
Platform.Function.SetObjectProperty(o, "Name", name);
for (var i = 0; params && i < params.length; i++) {
var p = Platform.Function.CreateObject("APIProperty");
Platform.Function.SetObjectProperty(p, "Name", params[i][0]);
Platform.Function.SetObjectProperty(p, "Value", params[i][1]);
Platform.Function.AddObjectArrayItem(o, "Parameters", p);
}
return o;
}
function unsubParams(subscriberKey) {
return [["SubscriberKey", subscriberKey], ["JobID", "0"], ["ListID", "0"], ["BatchID", "0"], ["Reason", "ssjs.guide test"]];
}
var neverCreated = "ssjsguide_id_exec_never";
/* 1 + 2 + 4. The documented 2-argument call with a PRE-SIZED status array. */
var sized = [0, 0];
var result = Platform.Function.InvokeExecute(execObject("LogUnsubEvent", unsubParams(neverCreated)), sized);
assert("DEV typeof InvokeExecute(...) is object - an ARRAY of results (docs: a single object)", String(typeof result), "object");
assert("DEV the return value is an array with one result element (docs: a single object)", result.length, 1);
assert("result[0].StatusCode is a string", String(typeof result[0].StatusCode), "string");
assert("result[0].StatusCode is 'Error' for a subscriber that was never created", String(result[0].StatusCode), "Error");
assert("result[0].StatusMessage carries the API's own message", String(result[0].StatusMessage), "The Subscriber was not found");
assert("result[0].ErrorCode is a number", String(typeof result[0].ErrorCode), "number");
assert("result[0].ErrorCode is the subscriber-not-found code 12001", result[0].ErrorCode, 12001);
assert("a PRE-SIZED status array keeps its length", sized.length, 2);
assert("status[0] receives the OverallStatus string", String(sized[0]), "Error");
assert("DEV status[1] receives a RequestID GUID STRING, not a number (InvokeCreate/InvokeDelete put a numeric code here)", String(typeof sized[1]), "string");
assert("the RequestID GUID has the canonical 36-character length", sized[1].length, 36);
/* 5 + 6. The SAME call with an EMPTY status array — never grown. */
var empty = [];
var result2 = Platform.Function.InvokeExecute(execObject("LogUnsubEvent", unsubParams(neverCreated)), empty);
assert("control: the identical call still returns one result element", result2.length, 1);
assert("control: the identical call still reports error code 12001", result2[0].ErrorCode, 12001);
assert("an EMPTY status array is never grown - it stays at length 0", empty.length, 0);
assert("status[0] of an empty status array is undefined", empty[0] === undefined ? "true" : "false", "true");
assert("status[1] of an empty status array is undefined", empty[1] === undefined ? "true" : "false", "true");
/* 3. Exactly two arguments — the docs' third argument is not reachable. */
assertThrows("arity 0 throws (the valid arity is 2)", function () {
return Platform.Function.InvokeExecute();
});
assertThrows("arity 1 throws (the valid arity is 2)", function () {
return Platform.Function.InvokeExecute(execObject("LogUnsubEvent", unsubParams(neverCreated)));
});
assertThrows("DEV arity 3 throws - the options argument the official docs describe is NOT reachable (the valid arity is 2)", function () {
var s = [0, 0];
return Platform.Function.InvokeExecute(execObject("LogUnsubEvent", unsubParams(neverCreated)), s, null);
});
</script>
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
apiObject |
object | Yes | SOAP object built with CreateObject and configured with SetObjectProperty |
status |
array | Yes | Out parameter. Pass a pre-sized array (e.g. [0, 0]): status[0] receives the OverallStatus string and status[1] a RequestID GUID string. An empty array [] is left untouched at length 0. Read the returned array for the per-item results (StatusCode / StatusMessage / ErrorCode). |
Unlike the documented signature, the third options argument is not accepted. A null
apiObject makes no SOAP call, returns null, and leaves status untouched.
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Parameters — Platform.Function.InvokeExecute(apiObject, status)
*
* Proves, one parameter at a time:
* 1. apiObject must be a SOAP API object built with CreateObject and
* populated with SetObjectProperty. Such an object is a .NET CLR host
* object (typeof "clr"), and a call built that way succeeds.
* 2. A plain JavaScript object or a string as apiObject throws — the
* parameter is not structurally typed, it must be an
* ExactTarget.Integration.WSDL type.
* 3. A null apiObject is the one non-object that does NOT throw: no SOAP
* call is made, the return value is a genuine null (not undefined, and
* not an array) and the status array is left untouched. This mirrors
* the same finding on /platform-functions/invokecreate/,
* /platform-functions/invokedelete/ and
* /platform-functions/invokeconfigure/.
* 4. status must be an array — a non-array throws.
* 5. status is an OUT parameter and must be PRE-SIZED: with [0, 0] the
* call writes the OverallStatus string into status[0] and a RequestID
* GUID string into status[1]; an empty array [] is left at length 0.
* 6. AddObjectArrayItem, used to attach the request's APIProperty
* parameters, returns a genuine null.
* 7. The member exists: a successful 2-argument invocation is the only
* reliable existence proof for a Platform.Function member (typeof
* reports "clrmethodinfo" for every name, real or not, so it proves
* nothing and is deliberately NOT asserted here).
*
* NOT ASSERTED: the values set on the apiObject cannot be read back from
* the object itself — it is a CLR host object and the engine blocks all
* introspection of it (see /platform-functions/createobject/). The values
* are proven indirectly by the API's own response.
*
* SCOPE: CloudPage only (MCDEV_Training_QA business unit).
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function assertThrows(id, fn) {
var threw = false, msg = "";
try { fn(); } catch (ex) { threw = true; msg = ex.message; }
Platform.Response.Write((threw ? "PASS " : "FAIL ") + id + " -> " + (threw ? "threw: " + msg : "did NOT throw") + "\n");
}
function assertNoThrow(id, fn) {
var ok = true, msg = "ok";
try { fn(); } catch (ex) { ok = false; msg = ex.message; }
Platform.Response.Write((ok ? "PASS " : "FAIL ") + id + " -> [" + msg + "]\n");
}
var neverCreated = "ssjsguide_id_exec_never";
/* 1 + 6. apiObject is a CreateObject SOAP object — a CLR host object. */
var apiObject = Platform.Function.CreateObject("ExecuteRequest");
assert("typeof CreateObject('ExecuteRequest') is clr", String(typeof apiObject), "clr");
assertNoThrow("SetObjectProperty(apiObject, 'Name', 'LogUnsubEvent') succeeds", function () {
Platform.Function.SetObjectProperty(apiObject, "Name", "LogUnsubEvent");
});
var prop = Platform.Function.CreateObject("APIProperty");
Platform.Function.SetObjectProperty(prop, "Name", "SubscriberKey");
Platform.Function.SetObjectProperty(prop, "Value", neverCreated);
var added = Platform.Function.AddObjectArrayItem(apiObject, "Parameters", prop);
assert("AddObjectArrayItem returns a genuine null", added === null ? "true" : "false", "true");
assert("AddObjectArrayItem does NOT return undefined", added === undefined ? "true" : "false", "false");
/* 5 + 7. The documented 2-argument call with a pre-sized status array. */
var status = [0, 0];
var result = Platform.Function.InvokeExecute(apiObject, status);
assert("InvokeExecute(apiObject, status) returns an array of results", result.length, 1);
assert("result[0].StatusCode is the API's own answer to this payload", String(result[0].StatusCode), "Error");
assert("result[0].ErrorCode is the subscriber-not-found code 12001", result[0].ErrorCode, 12001);
assert("status is an OUT parameter: status[0] was written by the call", String(status[0]), "Error");
assert("status is an OUT parameter: status[1] received a RequestID GUID string", String(typeof status[1]), "string");
assert("the pre-sized status array keeps its length", status.length, 2);
/* 5. An empty status array is left untouched. */
var emptyStatus = [];
var apiObject2 = Platform.Function.CreateObject("ExecuteRequest");
Platform.Function.SetObjectProperty(apiObject2, "Name", "LogUnsubEvent");
Platform.Function.AddObjectArrayItem(apiObject2, "Parameters", prop);
Platform.Function.InvokeExecute(apiObject2, emptyStatus);
assert("an empty status array is left at length 0 - status must be PRE-SIZED", emptyStatus.length, 0);
/* 2. apiObject must be a real SOAP object. */
assertThrows("a plain JavaScript object as apiObject throws", function () {
var s = [0, 0];
return Platform.Function.InvokeExecute({}, s);
});
assertThrows("a string as apiObject throws", function () {
var s = [0, 0];
return Platform.Function.InvokeExecute("ExecuteRequest", s);
});
/* 3. null apiObject: no SOAP call is made — genuine null back, status untouched. */
var nullStatus = [0, 0];
var nullResult = Platform.Function.InvokeExecute(null, nullStatus);
assert("a null apiObject does NOT throw", nullResult === null ? "true" : "false", "true");
assert("a null apiObject returns a genuine null, not an array of results", String(typeof nullResult), "object");
assert("a null apiObject is not undefined", nullResult === undefined ? "true" : "false", "false");
assert("a null apiObject leaves status[0] untouched (no SOAP call was made)", nullStatus[0], 0);
assert("a null apiObject leaves status[1] untouched (no SOAP call was made)", nullStatus[1], 0);
/* 4. status must be an array. */
assertThrows("a non-array status throws", function () {
var o = Platform.Function.CreateObject("ExecuteRequest");
Platform.Function.SetObjectProperty(o, "Name", "LogUnsubEvent");
return Platform.Function.InvokeExecute(o, "notanarray");
});
</script>
Examples
var execObj = Platform.Function.CreateObject("ExecuteRequest");
Platform.Function.SetObjectProperty(execObj, "Name", "LogUnsubEvent");
var param = Platform.Function.CreateObject("APIProperty");
Platform.Function.SetObjectProperty(param, "Name", "SubscriberKey");
Platform.Function.SetObjectProperty(param, "Value", "some-subscriber-key");
Platform.Function.AddObjectArrayItem(execObj, "Parameters", param);
var StatusAndRequestID = [0, 0];
var result = Platform.Function.InvokeExecute(execObj, StatusAndRequestID);
var firstResult = result[0];
// firstResult.StatusCode === "OK", firstResult.StatusMessage === "Event posted", firstResult.ErrorCode === 0
// StatusAndRequestID[0] === "OK", StatusAndRequestID[1] === a RequestID GUID string
if (firstResult.StatusCode !== "OK") {
Write("Error — " + firstResult.StatusMessage + " — code " + firstResult.ErrorCode);
}
An ExecuteRequest without Parameters is rejected by the API itself with
"No Parameters were provided" and ErrorCode 402, and an unknown verb name answers
"Unable to find a handler for the <name> method." — so the per-item StatusCode on the
returned array, not the status out parameter, is what a caller should branch on.
WSProxy is recommended over InvokeExecute for most use cases — it is simpler, uses native JS objects, and handles serialization automatically.
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Examples — the CreateObject / SetObjectProperty /
* AddObjectArrayItem / InvokeExecute build-and-execute pattern, end to end.
*
* Execute is the one SOAP verb that neither creates nor deletes a
* definition, so "it really ran" cannot be proven by re-reading an object.
* The DISCRIMINATING CONTROL is therefore a pair of otherwise identical
* LogUnsubEvent calls that differ only in the target subscriber:
* - against a subscriber this script CREATES itself the API answers
* StatusCode "OK" / "Event posted" / ErrorCode 0;
* - against a subscriber key that was NEVER created the same call answers
* "Error" / "The Subscriber was not found" / 12001.
* A call that had silently done nothing could not distinguish the two.
*
* Proves:
* 1. The example's shape works end to end and returns an array whose
* first element is result[0].
* 2. SUCCESS path: StatusCode "OK", StatusMessage "Event posted",
* ErrorCode 0, and status[0] === "OK".
* 3. FAILURE path (the control): "Error" / "The Subscriber was not
* found" / 12001 — the API rejecting a target, not the function
* failing.
* 4. The example's recommended guard branches on
* result[0].StatusCode !== "OK", which is false on the success path
* and true on the failure path.
* 5. An ExecuteRequest with NO Parameters is rejected by the API itself
* with "No Parameters were provided" and ErrorCode 402 — so the
* Parameters collection built with AddObjectArrayItem is what makes
* the documented example work.
* 6. An unknown verb name answers "Unable to find a handler for the
* <name> method." with ErrorCode 0 — the name reached the endpoint and
* is echoed back verbatim. NOTE what this does NOT show: real but
* unserved verbs (RefreshFilter, ResetPassword) answer with the same
* message shape and the same ErrorCode 0, so an unregistered name and
* a genuine verb that is not served here are indistinguishable from
* SSJS. The message separates SERVED from UNSERVED and nothing more;
* no dispatch mechanism and no cause can be read off it.
* 7. The script leaves nothing behind: the subscriber it created is
* deleted again and the business unit is left clean.
*
* SCOPE: CloudPage only (MCDEV_Training_QA business unit).
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function execObject(name, params) {
var o = Platform.Function.CreateObject("ExecuteRequest");
Platform.Function.SetObjectProperty(o, "Name", name);
for (var i = 0; params && i < params.length; i++) {
var p = Platform.Function.CreateObject("APIProperty");
Platform.Function.SetObjectProperty(p, "Name", params[i][0]);
Platform.Function.SetObjectProperty(p, "Value", params[i][1]);
Platform.Function.AddObjectArrayItem(o, "Parameters", p);
}
return o;
}
function unsubParams(subscriberKey) {
return [["SubscriberKey", subscriberKey], ["JobID", "0"], ["ListID", "0"], ["BatchID", "0"], ["Reason", "ssjs.guide test"]];
}
var subKey = "ssjsguide_id_exec_sub";
var neverCreated = "ssjsguide_id_exec_never";
/* Setup — create a real subscriber so the success path has a valid target. */
var sub = Platform.Function.CreateObject("Subscriber");
Platform.Function.SetObjectProperty(sub, "SubscriberKey", subKey);
Platform.Function.SetObjectProperty(sub, "EmailAddress", "ssjsguide.exec@ssjs.guide");
var setupStatus = [0, 0];
assert("setup: InvokeCreate of the throwaway subscriber returns 'OK'", String(Platform.Function.InvokeCreate(sub, setupStatus, null)), "OK");
/* 1 + 2 + 4. The page's example shape, against the subscriber just created. */
var execObj = execObject("LogUnsubEvent", unsubParams(subKey));
var StatusAndRequestID = [0, 0];
var result = Platform.Function.InvokeExecute(execObj, StatusAndRequestID);
var firstResult = result[0];
assert("the example returns an array with one result element", result.length, 1);
assert("firstResult.StatusCode is 'OK' on the success path", String(firstResult.StatusCode), "OK");
assert("firstResult.StatusMessage is the API's success message", String(firstResult.StatusMessage), "Event posted");
assert("firstResult.ErrorCode is 0 on the success path", firstResult.ErrorCode, 0);
assert("StatusAndRequestID[0] receives the OverallStatus string 'OK'", String(StatusAndRequestID[0]), "OK");
assert("StatusAndRequestID[1] receives a RequestID GUID string", String(typeof StatusAndRequestID[1]), "string");
assert("the example's guard does NOT fire on the success path", firstResult.StatusCode !== "OK" ? "true" : "false", "false");
/* 3 + 4. CONTROL — the identical call against a key that was never created. */
var controlStatus = [0, 0];
var controlResult = Platform.Function.InvokeExecute(execObject("LogUnsubEvent", unsubParams(neverCreated)), controlStatus);
assert("control: the identical call against a never-created key returns 'Error'", String(controlResult[0].StatusCode), "Error");
assert("control: the API's own not-found message", String(controlResult[0].StatusMessage), "The Subscriber was not found");
assert("control: the subscriber-not-found SOAP error code is 12001", controlResult[0].ErrorCode, 12001);
assert("control: status[0] receives the OverallStatus string 'Error'", String(controlStatus[0]), "Error");
assert("the example's guard DOES fire on the failure path", controlResult[0].StatusCode !== "OK" ? "true" : "false", "true");
/* 5. A request without Parameters is rejected by the API. */
var noParamStatus = [0, 0];
var noParamResult = Platform.Function.InvokeExecute(execObject("LogUnsubEvent", null), noParamStatus);
assert("an ExecuteRequest without Parameters returns 'Error'", String(noParamResult[0].StatusCode), "Error");
assert("the API reports that no parameters were provided", String(noParamResult[0].StatusMessage), "No Parameters were provided");
assert("the no-parameters SOAP error code is 402", noParamResult[0].ErrorCode, 402);
/* 6. An unknown verb name is echoed back in the rejection message. A real
* but unserved verb answers identically apart from the echoed name, so
* this separates served from unserved verbs and nothing further. */
var badVerbStatus = [0, 0];
var badVerbResult = Platform.Function.InvokeExecute(execObject("NotARealExecuteVerb", null), badVerbStatus);
assert("an unknown verb name returns 'Error'", String(badVerbResult[0].StatusCode), "Error");
assert("the API reports that it has no handler for the verb", String(badVerbResult[0].StatusMessage), "Unable to find a handler for the NotARealExecuteVerb method.");
assert("the unknown-verb answer carries ErrorCode 0", badVerbResult[0].ErrorCode, 0);
/* 7. Cleanup — the business unit is left clean. */
var delSub = Platform.Function.CreateObject("Subscriber");
Platform.Function.SetObjectProperty(delSub, "SubscriberKey", subKey);
var cleanupStatus = [0, 0];
assert("cleanup: the throwaway subscriber is deleted again", String(Platform.Function.InvokeDelete(delSub, cleanupStatus, null)), "OK");
assert("cleanup: the delete reports success code 0", cleanupStatus[1], 0);
</script>