<WSProxyInstance>.retrieve
→ objectRetrieve SFMC objects of a given type using an optional filter. Returns up to ~2500 rows per call; use getNextBatch for pagination.
Syntax
<WSProxyInstance>.retrieve(objectType, columns[, filter[, retrieveOptions[, requestProps]]])
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
objectType |
string | Yes | SOAP API object type (e.g., "DataExtension", "Subscriber", "DataExtensionObject[CustomerKey]") |
columns |
string[] | Yes | Array of property names to return |
filter |
object | No | SimpleFilterPart or ComplexFilterPart |
retrieveOptions |
object | No | Properties to set on the SOAP RetrieveOptions object. Set { BatchSize: n } (1–2500) to force paged results; values above 2500 are ignored |
requestProps |
object | No | Additional request-level properties such as { QueryAllAccounts: true }. Set ContinueRequest to a prior page’s RequestID to fetch the next page via retrieve (an alternative to getNextBatch) |
Runtime verified. On a published CloudPage, retrieve(obj, cols, null, { BatchSize: 2 }, { QueryAllAccounts: false }) against a 6-row Data Extension returned a first page with Status: "MoreDataAvailable", HasMoreRows: true, a RequestID, and exactly 2 rows — the retrieveOptions.BatchSize argument pages cleanly without throwing. Setting props.ContinueRequest to that RequestID and calling retrieve again returned each next page (3 pages of 2 rows, 6 total), the RequestID held constant, and HasMoreRows flipped to false (Status: "OK") on the last page. BatchSize caps at 2,500.
Show test script
<script runat="server">
/*
* Chapter: Parameters
*
* Proves:
* 1. retrieve is a CLR method on every WSProxy instance.
* 2. objectType (string) + columns (string[]) are the two REQUIRED
* arguments — the 2-argument form succeeds (min_args = 2).
* 3. NEGATIVE — fewer than 2 arguments is rejected: the 1-argument and
* the 0-argument forms throw.
* 4. objectType accepts the documented forms: "DataExtension",
* "Subscriber" and "DataExtensionObject[CustomerKey]".
* 5. columns is an array of property NAMES — every requested column is
* returned on the result rows.
* 6. filter is OPTIONAL (3rd argument) — omitting it returns every row.
* 7. retrieveOptions is OPTIONAL (4th argument) and { BatchSize: n }
* forces paged results.
* 8. requestProps is OPTIONAL (5th argument) — the full 5-argument form
* (max_args = 5) succeeds with { QueryAllAccounts: false }.
* 9. The page's runtime-verified callout, end to end, against a 6-row
* Data Extension:
* retrieve(obj, cols, null, { BatchSize: 2 }, { QueryAllAccounts: false })
* returns a first page with Status "MoreDataAvailable",
* HasMoreRows true, a RequestID and exactly 2 rows; setting
* props.ContinueRequest to that RequestID and calling retrieve again
* returns each next page (3 pages of 2 rows, 6 rows total); the
* RequestID stays constant; the last page reports Status "OK" and
* HasMoreRows false.
*
* NOT PROBED: Date / number / boolean type-acceptance counterparts.
* No parameter is in scope for the matrix — objectType is a SOAP type
* NAME (free-text string), columns is a string array, and filter /
* retrieveOptions / requestProps are typed `object`. None is documented
* as a date, a bare count/limit, or a 0/1 flag.
*
* 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");
}
Platform.Load("core", "1.1.5");
var proxy = new Script.Util.WSProxy();
var tag = "wsrP" + (new Date()).getTime();
var deKey = tag + "_de";
var objectType = "DataExtensionObject[" + deKey + "]";
/* 1. The method exists on the instance. */
assert("typeof proxy.retrieve is clrmethodinfo", typeof proxy.retrieve, "clrmethodinfo");
/* Fixture: a 6-row Data Extension, matching the page callout. */
assert("fixture data extension created", "" + proxy.createItem("DataExtension", {
Name: deKey,
CustomerKey: deKey,
Fields: [
{ Name: "Pk", FieldType: "Text", MaxLength: 50, IsPrimaryKey: true, IsRequired: true },
{ Name: "Val", FieldType: "Number" }
]
}).Status, "OK");
var de = DataExtension.Init(deKey);
for (var i = 1; i <= 6; i++) { de.Rows.Add({ Pk: "r" + i, Val: i * 10 }); }
assert("six fixture rows exist", "" + de.Rows.Retrieve().length, "6");
/* 2. + 4. + 5. + 6. The 2-argument form: objectType + columns only. */
var two = proxy.retrieve(objectType, ["Pk", "Val"]);
assert("the 2-argument form (objectType, columns) succeeds", "" + two.Status, "OK");
assert("omitting the optional filter returns every row", "" + two.Results.length, "6");
assert("the first requested column is returned", "" + two.Results[0].Properties[0].Name, "Pk");
assert("the second requested column is returned", "" + two.Results[0].Properties[1].Name, "Val");
/* 4. objectType accepts "DataExtension". */
var deList = proxy.retrieve("DataExtension", ["Name", "CustomerKey"], {
Property: "CustomerKey", SimpleOperator: "equals", Value: deKey
});
assert("objectType DataExtension is accepted", "" + deList.Status, "OK");
assert("the fixture DE is found by CustomerKey", "" + deList.Results.length, "1");
/* 4. objectType accepts "Subscriber". */
var subs = proxy.retrieve("Subscriber", ["EmailAddress", "SubscriberKey", "Status"], {
Property: "SubscriberKey", SimpleOperator: "equals", Value: tag + "_nobody"
});
assert("objectType Subscriber is accepted", "" + subs.Status, "OK");
/* 3. NEGATIVE — fewer than 2 arguments is rejected. */
assertThrows("retrieve(objectType) with no columns throws (min_args = 2)", function () { return proxy.retrieve(objectType); });
assertThrows("retrieve() with no arguments throws (min_args = 2)", function () { return proxy.retrieve(); });
/* 7. + 8. + 9. The full 5-argument form and the callout's paging loop. */
var opts = { BatchSize: 2 };
var props = { QueryAllAccounts: false };
var page = proxy.retrieve(objectType, ["Pk", "Val"], null, opts, props);
assert("the 5-argument form (max_args = 5) succeeds", typeof page, "object");
assert("callout: first page Status is MoreDataAvailable", "" + page.Status, "MoreDataAvailable");
assert("callout: first page HasMoreRows is true", page.HasMoreRows ? "true" : "false", "true");
assert("callout: first page carries a non-empty RequestID", (("" + page.RequestID).length > 0) ? "true" : "false", "true");
assert("callout: retrieveOptions.BatchSize caps the first page at 2 rows", "" + page.Results.length, "2");
var firstId = "" + page.RequestID;
var pages = 1;
var rowsSeen = page.Results.length;
var idHeldConstant = true;
while (page.HasMoreRows) {
props.ContinueRequest = page.RequestID;
page = proxy.retrieve(objectType, ["Pk", "Val"], null, opts, props);
pages = pages + 1;
rowsSeen = rowsSeen + page.Results.length;
if (("" + page.RequestID) !== firstId) { idHeldConstant = false; }
}
assert("callout: props.ContinueRequest paged through 3 pages of 2 rows", "" + pages, "3");
assert("callout: 6 rows in total across the pages", "" + rowsSeen, "6");
assert("callout: the RequestID stayed constant across the pages", idHeldConstant ? "true" : "false", "true");
assert("callout: the last page reports Status OK", "" + page.Status, "OK");
assert("callout: the last page reports HasMoreRows false", page.HasMoreRows ? "true" : "false", "false");
/* Cleanup. */
assert("cleanup: fixture data extension deleted", "" + proxy.deleteBatch("DataExtension", [{ CustomerKey: deKey }]).Status, "OK");
</script>
Filter Types
SimpleFilterPart
var filter = {
Property: "Status",
SimpleOperator: "equals", // equals, notEquals, greaterThan, lessThan, isNull, isNotNull, like, between, IN
Value: "Active"
};
ComplexFilterPart (AND / OR)
var filter = {
LeftOperand: {
Property: "Status",
SimpleOperator: "equals",
Value: "active"
},
LogicalOperator: "AND", // or "OR"
RightOperand: {
Property: "Score",
SimpleOperator: "greaterThan",
Value: "50"
}
};
Show test script
<script runat="server">
/*
* Chapter: Filter Types
*
* Proves every filter shape and every operator the chapter documents,
* against a 6-row fixture Data Extension (Pk = r1..r6, Val = 10..60,
* Opt set on r1 only):
* 1. SimpleFilterPart is { Property, SimpleOperator, Value }.
* 2. Every documented SimpleOperator works:
* equals, notEquals, greaterThan, lessThan,
* isNull, isNotNull, like, between, IN
* 3. ComplexFilterPart is
* { LeftOperand, LogicalOperator, RightOperand }
* and both documented LogicalOperator values work: "AND" and "OR".
*
* The `like` wildcard character is built with String.fromCharCode(37) so
* no literal percent sequence reaches the CloudPage AMPscript
* preprocessor.
*
* NOTE on isNull / isNotNull: the SimpleFilterPart shape the chapter
* documents has three members, and Value must be present even for these
* two operators. Omitting Value (or passing null) makes the SOAP call
* fail with "Error executing retrieve call." — an empty string satisfies
* it. The last two assertions prove that, so the shape stays exactly the
* one the chapter documents.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
Platform.Load("core", "1.1.5");
var proxy = new Script.Util.WSProxy();
var tag = "wsrF" + (new Date()).getTime();
var deKey = tag + "_de";
var objectType = "DataExtensionObject[" + deKey + "]";
var cols = ["Pk", "Val", "Opt"];
assert("fixture data extension created", "" + proxy.createItem("DataExtension", {
Name: deKey,
CustomerKey: deKey,
Fields: [
{ Name: "Pk", FieldType: "Text", MaxLength: 50, IsPrimaryKey: true, IsRequired: true },
{ Name: "Val", FieldType: "Number" },
{ Name: "Opt", FieldType: "Text", MaxLength: 50 }
]
}).Status, "OK");
var de = DataExtension.Init(deKey);
for (var i = 1; i <= 6; i++) {
if (i === 1) { de.Rows.Add({ Pk: "r1", Val: 10, Opt: "set" }); }
else { de.Rows.Add({ Pk: "r" + i, Val: i * 10 }); }
}
assert("six fixture rows exist", "" + de.Rows.Retrieve().length, "6");
function count(filter) {
var out = "";
try { out = "" + proxy.retrieve(objectType, cols, filter).Results.length; }
catch (ex) { out = "THREW: " + ex.message; }
return out;
}
/* 1. + 2. SimpleFilterPart — every documented operator. */
assert("SimpleOperator equals matches one row", count({ Property: "Pk", SimpleOperator: "equals", Value: "r3" }), "1");
assert("SimpleOperator notEquals matches the other five rows", count({ Property: "Pk", SimpleOperator: "notEquals", Value: "r3" }), "5");
assert("SimpleOperator greaterThan matches the rows above the value", count({ Property: "Val", SimpleOperator: "greaterThan", Value: "30" }), "3");
assert("SimpleOperator lessThan matches the rows below the value", count({ Property: "Val", SimpleOperator: "lessThan", Value: "30" }), "2");
assert("SimpleOperator isNull matches the rows without a value", count({ Property: "Opt", SimpleOperator: "isNull", Value: "" }), "5");
assert("SimpleOperator isNotNull matches the row with a value", count({ Property: "Opt", SimpleOperator: "isNotNull", Value: "" }), "1");
assert("SimpleOperator like matches on a wildcard", count({ Property: "Pk", SimpleOperator: "like", Value: "r" + String.fromCharCode(37) }), "6");
assert("SimpleOperator between matches the inclusive range", count({ Property: "Val", SimpleOperator: "between", Value: ["20", "40"] }), "3");
assert("SimpleOperator IN matches every listed value", count({ Property: "Pk", SimpleOperator: "IN", Value: ["r1", "r2"] }), "2");
/* 3. ComplexFilterPart — AND and OR. */
assert("ComplexFilterPart with LogicalOperator AND narrows the result", count({
LeftOperand: { Property: "Val", SimpleOperator: "greaterThan", Value: "20" },
LogicalOperator: "AND",
RightOperand: { Property: "Val", SimpleOperator: "lessThan", Value: "50" }
}), "2");
assert("ComplexFilterPart with LogicalOperator OR widens the result", count({
LeftOperand: { Property: "Pk", SimpleOperator: "equals", Value: "r1" },
LogicalOperator: "OR",
RightOperand: { Property: "Pk", SimpleOperator: "equals", Value: "r6" }
}), "2");
/* The documented three-member SimpleFilterPart shape applies to isNull /
isNotNull too — Value must be present, an empty string is enough. */
assert("isNull without a Value member is rejected", count({ Property: "Opt", SimpleOperator: "isNull" }), "THREW: Error executing retrieve call.");
assert("isNotNull without a Value member is rejected", count({ Property: "Opt", SimpleOperator: "isNotNull" }), "THREW: Error executing retrieve call.");
/* Cleanup. */
assert("cleanup: fixture data extension deleted", "" + proxy.deleteBatch("DataExtension", [{ CustomerKey: deKey }]).Status, "OK");
</script>
Return Value
{
Status: "OK", // "MoreDataAvailable" while a paged result set still has more pages; "OK" on the final page
RequestID: "...", // carry into getNextBatch, or into props.ContinueRequest, to fetch the next page
Results: [...], // array of result objects
HasMoreRows: false // true when more rows exist (use getNextBatch or props.ContinueRequest)
}
Show test script
<script runat="server">
/*
* Chapter: Return Value
*
* Proves the documented return shape, field by field:
* 1. retrieve returns an OBJECT.
* 2. Status is a STRING and is "OK" on an unpaged / final result, and
* "MoreDataAvailable" while a paged result set still has more pages.
* 3. RequestID is a STRING and carries into getNextBatch AND into
* props.ContinueRequest — both fetch the next page.
* 4. Results is an ARRAY of result objects.
* 5. HasMoreRows is a BOOLEAN — false when no more rows exist and true
* when more rows exist.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
Platform.Load("core", "1.1.5");
var proxy = new Script.Util.WSProxy();
var tag = "wsrR" + (new Date()).getTime();
var deKey = tag + "_de";
var objectType = "DataExtensionObject[" + deKey + "]";
assert("fixture data extension created", "" + proxy.createItem("DataExtension", {
Name: deKey,
CustomerKey: deKey,
Fields: [{ Name: "Pk", FieldType: "Text", MaxLength: 50, IsPrimaryKey: true, IsRequired: true }]
}).Status, "OK");
var de = DataExtension.Init(deKey);
for (var i = 1; i <= 6; i++) { de.Rows.Add({ Pk: "r" + i }); }
assert("six fixture rows exist", "" + de.Rows.Retrieve().length, "6");
/* 1., 2., 4., 5. — the unpaged result. */
var all = proxy.retrieve(objectType, ["Pk"]);
assert("typeof the retrieve result is object", typeof all, "object");
assert("typeof Status is string", typeof all.Status, "string");
assert("Status is OK when the whole result set fits in one page", "" + all.Status, "OK");
assert("typeof Results is object", typeof all.Results, "object");
assert("Results is an array of result objects", "" + all.Results.length, "6");
assert("typeof a Results entry is object", typeof all.Results[0], "object");
assert("typeof HasMoreRows is boolean", typeof all.HasMoreRows, "boolean");
assert("HasMoreRows is false when no more rows exist", all.HasMoreRows ? "true" : "false", "false");
/* 2., 3., 5. — the paged result. */
var p1 = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 2 }, { QueryAllAccounts: false });
assert("Status is MoreDataAvailable while more pages remain", "" + p1.Status, "MoreDataAvailable");
assert("HasMoreRows is true when more rows exist", p1.HasMoreRows ? "true" : "false", "true");
assert("typeof RequestID is string", typeof p1.RequestID, "string");
assert("RequestID is not empty", (("" + p1.RequestID).length > 0) ? "true" : "false", "true");
/* 3. RequestID carries into getNextBatch. */
var viaBatch = proxy.getNextBatch(objectType, p1.RequestID);
assert("the RequestID carried into getNextBatch returns the next page", (viaBatch.Results.length > 0) ? "true" : "false", "true");
/* 3. RequestID carries into props.ContinueRequest. */
var p2 = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 2 }, { QueryAllAccounts: false });
var viaContinue = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 2 }, { QueryAllAccounts: false, ContinueRequest: p2.RequestID });
assert("the RequestID carried into props.ContinueRequest returns the next page", "" + viaContinue.Results.length, "2");
/* Cleanup. */
assert("cleanup: fixture data extension deleted", "" + proxy.deleteBatch("DataExtension", [{ CustomerKey: deKey }]).Status, "OK");
</script>
Examples
Retrieve all Data Extensions
var proxy = new Script.Util.WSProxy();
var result = proxy.retrieve("DataExtension", ["Name", "CustomerKey", "Description"]);
var des = result.Results;
for (var i = 0; i < des.length; i++) {
Write(des[i].Name + " (" + des[i].CustomerKey + ")<br>");
}
Retrieve with filter
var proxy = new Script.Util.WSProxy();
var filter = {
Property: "TriggeredSendStatus",
SimpleOperator: "equals",
Value: "Active"
};
var result = proxy.retrieve("TriggeredSendDefinition",
["Name", "CustomerKey", "TriggeredSendStatus"],
filter
);
Retrieve DE rows
var proxy = new Script.Util.WSProxy();
var result = proxy.retrieve(
"DataExtensionObject[MyDE_CustomerKey]",
["Email", "FirstName", "Score"],
{
Property: "Score",
SimpleOperator: "greaterThan",
Value: "80"
}
);
var rows = result.Results;
Retrieve a subscriber
var proxy = new Script.Util.WSProxy();
var result = proxy.retrieve(
"Subscriber",
["EmailAddress", "SubscriberKey", "Status"],
{
Property: "SubscriberKey",
SimpleOperator: "equals",
Value: "sub_12345"
}
);
var sub = result.Results[0];
Retrieve across all business units
var proxy = new Script.Util.WSProxy();
var result = proxy.retrieve(
"DataExtension",
["Name", "CustomerKey"],
null,
null,
{ QueryAllAccounts: true }
);
Pass null — not an empty object {} — when you want no filter. An empty filter object makes the SOAP call fail with Error executing retrieve call.
Manual pagination with getNextBatch
var proxy = new Script.Util.WSProxy();
var result = proxy.retrieve("DataExtension", ["Name", "CustomerKey"]);
while (result.HasMoreRows) {
// process result.Results ...
result = proxy.getNextBatch("DataExtension", result.RequestID);
}
Pagination with BatchSize and ContinueRequest
Force a smaller page with retrieveOptions.BatchSize, then continue via props.ContinueRequest — a fully retrieve-based alternative to getNextBatch. Runtime-verified to work on a published CloudPage.
var proxy = new Script.Util.WSProxy();
var obj = "DataExtensionObject[MyDE_CustomerKey]";
var cols = ["Pk", "Val"];
var opts = { BatchSize: 500 }; // 1..2500; larger is ignored
var props = { QueryAllAccounts: false };
// First page
var data = proxy.retrieve(obj, cols, null, opts, props);
// data.Status === "MoreDataAvailable" and data.HasMoreRows === true while paged
// Subsequent pages
while (data.HasMoreRows) {
// process data.Results ...
props.ContinueRequest = data.RequestID; // carry the RequestID forward
data = proxy.retrieve(obj, cols, null, opts, props);
}
// last page: data.Status === "OK", data.HasMoreRows === false
Show test script
<script runat="server">
/*
* Chapter: Examples
*
* Runs every example on the page, verbatim in structure, and proves the
* claim each one makes:
* 1. "Retrieve all Data Extensions" — retrieve("DataExtension",
* ["Name", "CustomerKey", "Description"]) returns rows whose Name and
* CustomerKey are read directly off the result object.
* 2. "Retrieve with filter" — a SimpleFilterPart on
* TriggeredSendDefinition TriggeredSendStatus equals "Active" is
* accepted. NOTE: "Status" is NOT a retrievable/filterable property
* of TriggeredSendDefinition — the SOAP name is
* TriggeredSendStatus. The last two assertions prove that.
* 3. "Retrieve DE rows" — "DataExtensionObject[MyDE_CustomerKey]" with a
* greaterThan filter on a numeric column returns the matching rows.
* 4. "Retrieve a subscriber" — Subscriber with a SubscriberKey equals
* filter is accepted, and result.Results[0] is the matched
* subscriber. The key comes from an unfiltered single-row retrieve
* rather than a created fixture: the example only reads, and this
* BU's Subscriber list is not writable from a CloudPage.
* 5. "Retrieve across all business units" — the 5-argument form with a
* null filter, a null retrieveOptions and { QueryAllAccounts: true }
* is accepted and returns rows. The page's warning callout is proven
* too: an EMPTY filter object {} is rejected with "Error executing
* retrieve call." — pass null, not {}.
* 6. "Manual pagination with getNextBatch" — the while (result.HasMoreRows)
* loop carrying result.RequestID into proxy.getNextBatch terminates
* and visits every row.
* 7. "Pagination with BatchSize and ContinueRequest" — the loop that
* carries props.ContinueRequest = data.RequestID reaches a last page
* with Status "OK" and HasMoreRows false, and BatchSize 500 (within
* 1..2500) is accepted.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function guard(fn) {
try { return "" + fn(); } catch (ex) { return "THREW: " + ex.message; }
}
Platform.Load("core", "1.1.5");
var proxy = new Script.Util.WSProxy();
var tag = "wsrX" + (new Date()).getTime();
var deKey = tag + "_de";
assert("fixture data extension created", "" + proxy.createItem("DataExtension", {
Name: deKey,
CustomerKey: deKey,
Fields: [
{ Name: "Pk", FieldType: "Text", MaxLength: 50, IsPrimaryKey: true, IsRequired: true },
{ Name: "Score", FieldType: "Number" }
]
}).Status, "OK");
var de = DataExtension.Init(deKey);
for (var i = 1; i <= 6; i++) { de.Rows.Add({ Pk: "r" + i, Score: i * 20 }); }
assert("six fixture rows exist", "" + de.Rows.Retrieve().length, "6");
/* 1. Retrieve all Data Extensions. */
var deResult = proxy.retrieve("DataExtension", ["Name", "CustomerKey", "Description"], {
Property: "CustomerKey", SimpleOperator: "equals", Value: deKey
});
assert("example 1: retrieving DataExtension succeeds", "" + deResult.Status, "OK");
assert("example 1: Name is read directly off the result object", "" + deResult.Results[0].Name, deKey);
assert("example 1: CustomerKey is read directly off the result object", "" + deResult.Results[0].CustomerKey, deKey);
/* 2. Retrieve with filter. */
var tsd = proxy.retrieve("TriggeredSendDefinition", ["Name", "CustomerKey", "TriggeredSendStatus"], {
Property: "TriggeredSendStatus", SimpleOperator: "equals", Value: "Active"
});
assert("example 2: a filtered TriggeredSendDefinition retrieve succeeds", "" + tsd.Status, "OK");
assert("example 2: TriggeredSendDefinition has no retrievable Status property", guard(function () {
return proxy.retrieve("TriggeredSendDefinition", ["Name", "CustomerKey", "Status"]).Status;
}), "Error: The Request Property(s) Status do not match with the fields of TriggeredSendDefinition retrieve");
assert("example 2: filtering TriggeredSendDefinition on Status is rejected", guard(function () {
return proxy.retrieve("TriggeredSendDefinition", ["Name", "CustomerKey"], { Property: "Status", SimpleOperator: "equals", Value: "Active" }).Status;
}), "Error: The Filter Property 'Status' is not a retrievable property.");
/* 3. Retrieve DE rows with a greaterThan filter. */
var rows = proxy.retrieve("DataExtensionObject[" + deKey + "]", ["Pk", "Score"], {
Property: "Score", SimpleOperator: "greaterThan", Value: "80"
});
assert("example 3: the DataExtensionObject greaterThan filter succeeds", "" + rows.Status, "OK");
assert("example 3: only the rows above the threshold are returned", "" + rows.Results.length, "2");
/* 4. Retrieve a subscriber. Read an existing subscriber rather than
creating a fixture — this BU's Subscriber list is not writable from a
CloudPage, and the example only reads. */
var anySub = proxy.retrieve("Subscriber", ["EmailAddress", "SubscriberKey", "Status"], null, { BatchSize: 1 }, { QueryAllAccounts: false });
assert("example 4: a Subscriber retrieve returns a row", (anySub.Results.length > 0) ? "true" : "false", "true");
var subKey = "" + anySub.Results[0].SubscriberKey;
var subResult = proxy.retrieve("Subscriber", ["EmailAddress", "SubscriberKey", "Status"], {
Property: "SubscriberKey", SimpleOperator: "equals", Value: subKey
});
assert("example 4: the filtered Subscriber retrieve succeeds", "" + subResult.Status, "OK");
assert("example 4: Results[0] is the matched subscriber", "" + subResult.Results[0].SubscriberKey, subKey);
/* 5. Retrieve across all business units. */
var allBu = proxy.retrieve("DataExtension", ["Name", "CustomerKey"], null, null, { QueryAllAccounts: true });
assert("example 5: a null filter with QueryAllAccounts true is accepted", "" + allBu.Status, "OK");
assert("example 5: the cross-business-unit retrieve returns rows", (allBu.Results.length > 0) ? "true" : "false", "true");
assert("example 5: an EMPTY filter object is rejected - pass null instead", guard(function () {
return proxy.retrieve("DataExtension", ["Name", "CustomerKey"], {}, null, { QueryAllAccounts: true }).Status;
}), "THREW: Error executing retrieve call.");
/* 6. Manual pagination with getNextBatch. */
var objectType = "DataExtensionObject[" + deKey + "]";
var result = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 2 }, { QueryAllAccounts: false });
var seen = result.Results.length;
while (result.HasMoreRows) {
result = proxy.getNextBatch(objectType, result.RequestID);
seen = seen + result.Results.length;
}
assert("example 6: the getNextBatch loop terminated", result.HasMoreRows ? "true" : "false", "false");
assert("example 6: the getNextBatch loop visited every row", "" + seen, "6");
/* 7. Pagination with BatchSize and ContinueRequest. */
var opts = { BatchSize: 500 };
var props = { QueryAllAccounts: false };
var data = proxy.retrieve(objectType, ["Pk"], null, opts, props);
assert("example 7: BatchSize 500 is within the accepted 1..2500 range", "" + data.Status, "OK");
opts = { BatchSize: 2 };
props = { QueryAllAccounts: false };
data = proxy.retrieve(objectType, ["Pk"], null, opts, props);
assert("example 7: a paged first page reports MoreDataAvailable", "" + data.Status, "MoreDataAvailable");
assert("example 7: a paged first page reports HasMoreRows true", data.HasMoreRows ? "true" : "false", "true");
var total = data.Results.length;
while (data.HasMoreRows) {
props.ContinueRequest = data.RequestID;
data = proxy.retrieve(objectType, ["Pk"], null, opts, props);
total = total + data.Results.length;
}
assert("example 7: the last page reports Status OK", "" + data.Status, "OK");
assert("example 7: the last page reports HasMoreRows false", data.HasMoreRows ? "true" : "false", "false");
assert("example 7: the ContinueRequest loop visited every row", "" + total, "6");
/* Cleanup. */
assert("cleanup: fixture data extension deleted", "" + proxy.deleteBatch("DataExtension", [{ CustomerKey: deKey }]).Status, "OK");
</script>
Notes
- Returns up to ~2,500 rows per call by default. When
HasMoreRowsistrue, either callgetNextBatchwith theRequestID, or setprops.ContinueRequestto theRequestIDand callretrieveagain — both fetch subsequent pages. - Pass
{ BatchSize: n }as the 4th (retrieveOptions) argument to force a smaller page size (1–2,500; larger values are ignored). TheretrieveOptions.BatchSizeargument is runtime-verified to page cleanly on a published CloudPage. - A paged
retrievereturnsStatus: "MoreDataAvailable"until the final page, which returnsStatus: "OK". - The
DataExtensionObject[CustomerKey]syntax is used for retrieving rows from a specific DE. ReplaceCustomerKeywith the DE’s external key.
Show test script
<script runat="server">
/*
* Chapter: Notes
*
* Proves every claim in the Notes list:
* 1. When HasMoreRows is true, BOTH continuation routes fetch subsequent
* pages: getNextBatch with the RequestID, and props.ContinueRequest
* set to the RequestID followed by another retrieve.
* 2. { BatchSize: n } passed as the 4th (retrieveOptions) argument forces
* a smaller page size — BatchSize 2 returns exactly 2 rows on the
* first page of a 6-row result set.
* 3. Values LARGER than 2,500 are ignored — BatchSize 5000 returns the
* whole 6-row result set in one unpaged page (Status "OK",
* HasMoreRows false), exactly like an unpaged retrieve.
* 4. A paged retrieve returns Status "MoreDataAvailable" until the final
* page, which returns Status "OK".
* 5. The DataExtensionObject[CustomerKey] syntax retrieves rows from that
* specific Data Extension — the CustomerKey is the DE's external key,
* and a bare "DataExtensionObject" without the bracketed key is NOT
* the same call.
*
* NOT ASSERTABLE HERE: the "returns up to ~2,500 rows per call by default"
* default page size. Proving it requires a fixture larger than 2,500 rows,
* which is far beyond what a page test script can seed and delete inside a
* single CloudPage request. The claim is already recorded from a 2,600-row
* fixture in the getNextBatch verification.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
Platform.Load("core", "1.1.5");
var proxy = new Script.Util.WSProxy();
var tag = "wsrN" + (new Date()).getTime();
var deKey = tag + "_de";
var objectType = "DataExtensionObject[" + deKey + "]";
assert("fixture data extension created", "" + proxy.createItem("DataExtension", {
Name: deKey,
CustomerKey: deKey,
Fields: [{ Name: "Pk", FieldType: "Text", MaxLength: 50, IsPrimaryKey: true, IsRequired: true }]
}).Status, "OK");
var de = DataExtension.Init(deKey);
for (var i = 1; i <= 6; i++) { de.Rows.Add({ Pk: "r" + i }); }
assert("six fixture rows exist", "" + de.Rows.Retrieve().length, "6");
/* 2. + 4. BatchSize forces a smaller page. */
var p1 = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 2 }, { QueryAllAccounts: false });
assert("BatchSize 2 forces a first page of exactly 2 rows", "" + p1.Results.length, "2");
assert("a paged retrieve reports MoreDataAvailable before the final page", "" + p1.Status, "MoreDataAvailable");
assert("a paged retrieve reports HasMoreRows true before the final page", p1.HasMoreRows ? "true" : "false", "true");
/* 1. Continuation route A — getNextBatch with the RequestID. */
var viaBatch = proxy.getNextBatch(objectType, p1.RequestID);
assert("continuation route A: getNextBatch with the RequestID returns the next page", (viaBatch.Results.length > 0) ? "true" : "false", "true");
/* 1. + 4. Continuation route B — props.ContinueRequest, looped to the end. */
var opts = { BatchSize: 2 };
var props = { QueryAllAccounts: false };
var data = proxy.retrieve(objectType, ["Pk"], null, opts, props);
var total = data.Results.length;
while (data.HasMoreRows) {
props.ContinueRequest = data.RequestID;
data = proxy.retrieve(objectType, ["Pk"], null, opts, props);
total = total + data.Results.length;
}
assert("continuation route B: props.ContinueRequest returns every remaining row", "" + total, "6");
assert("the final page of a paged retrieve reports Status OK", "" + data.Status, "OK");
assert("the final page of a paged retrieve reports HasMoreRows false", data.HasMoreRows ? "true" : "false", "false");
/* 3. Values larger than 2,500 are ignored. */
var big = proxy.retrieve(objectType, ["Pk"], null, { BatchSize: 5000 }, { QueryAllAccounts: false });
assert("BatchSize above 2500 is ignored - the whole result set is returned", "" + big.Results.length, "6");
assert("BatchSize above 2500 is ignored - Status is OK", "" + big.Status, "OK");
assert("BatchSize above 2500 is ignored - HasMoreRows is false", big.HasMoreRows ? "true" : "false", "false");
/* 5. The DataExtensionObject[CustomerKey] syntax targets that DE. */
var scoped = proxy.retrieve(objectType, ["Pk"]);
assert("DataExtensionObject[CustomerKey] returns the rows of that data extension", "" + scoped.Results.length, "6");
assert("DataExtensionObject[CustomerKey] returns rows, not data extensions", "" + scoped.Results[0].Properties[0].Name, "Pk");
/* Cleanup. */
assert("cleanup: fixture data extension deleted", "" + proxy.deleteBatch("DataExtension", [{ CustomerKey: deKey }]).Status, "OK");
</script>