<WSProxyInstance>.updateItem
→ objectUpdate a single existing SFMC object via the SOAP API. Accepts an optional UpdateOptions argument (e.g. SaveOptions for upsert behavior).
Runtime verified
Test scripts included
Syntax
<WSProxyInstance>.updateItem(objectType, properties[, updateOptions])
2–3 arguments
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
objectType |
string | Yes | SOAP API object type |
properties |
object | Yes | Single object to update (must include identifier) |
updateOptions |
object | No | SOAP UpdateOptions object (e.g. { SaveOptions: [...] }) |
Show test script
<script runat="server">
/*
* Chapter: Parameters
*
* Proves:
* 1. updateItem is a CLR method on every WSProxy instance.
* 2. objectType (string) + properties (object) are BOTH required: the
* 2-argument form is the documented minimum and succeeds
* (min_args = 2).
* 3. properties is ONE object describing ONE item - a single call
* produces exactly one Results entry.
* 4. updateOptions is OPTIONAL and, when supplied as a third argument
* in the documented { SaveOptions: [ ... ] } shape, is accepted
* (max_args = 3) and the call still succeeds.
* 5. NEGATIVE - calling with fewer than 2 arguments is rejected: both
* the 1-argument and the 0-argument form throw.
* 6. NEGATIVE - objectType must name a real SOAP object type; an
* unknown type does not silently succeed.
* 7. properties must include the identifier the page requires: an
* update whose properties object carries no identifier does not
* succeed.
*
* NOT PROBED: Date / number / boolean type-acceptance counterparts. None
* of the three parameters is in scope for the matrix - objectType is a
* SOAP type NAME (free-text string), properties is an object, and
* updateOptions is a SOAP UpdateOptions object. No parameter is
* documented as a date, a 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");
}
var proxy = new Script.Util.WSProxy();
var tag = "uiP" + (new Date()).getTime();
/* 1. The method exists on the instance. */
assert("typeof proxy.updateItem is clrmethodinfo", typeof proxy.updateItem, "clrmethodinfo");
/* Fixture - a subscriber to update. */
var made = proxy.createItem("Subscriber", {
EmailAddress: tag + "a@joernberkefeld.com",
SubscriberKey: tag + "-a",
Status: "Active"
});
assert("fixture subscriber created", "" + made.Status, "OK");
/* 2. Documented minimum: objectType + properties (min_args = 2). */
var two = proxy.updateItem("Subscriber", {
SubscriberKey: tag + "-a",
Status: "Unsubscribed"
});
assert("2-argument form (objectType, properties) succeeds", "" + two.Status, "OK");
/* 3. One properties object updates exactly one item. */
assert("one properties object produces exactly one Results entry", "" + two.Results.length, "1");
/* 4. updateOptions is optional and accepted as a third argument. */
var three = proxy.updateItem("Subscriber", {
SubscriberKey: tag + "-a",
Status: "Active"
}, { SaveOptions: [{ PropertyName: "*", SaveAction: "UpdateAdd" }] });
assert("3-argument form with updateOptions succeeds (max_args = 3)", "" + three.Status, "OK");
assert("3-argument form still returns one result", "" + three.Results.length, "1");
assert("3-argument form result is OK", "" + three.Results[0].StatusCode, "OK");
/* 5. NEGATIVE - fewer than 2 arguments is rejected. */
assertThrows("updateItem(objectType) with no properties throws (min_args = 2)", function () { return proxy.updateItem("Subscriber"); });
assertThrows("updateItem() with no arguments throws (min_args = 2)", function () { return proxy.updateItem(); });
/* 6. NEGATIVE - objectType must name a real SOAP object type. */
var unknownOk = false;
try {
var bogus = proxy.updateItem("ThisTypeDoesNotExist" + tag, { Name: tag });
unknownOk = ("" + bogus.Status === "OK");
} catch (exType) {
unknownOk = false;
}
assert("an unknown objectType does not succeed", unknownOk ? "true" : "false", "false");
/* 7. NEGATIVE - properties must include the identifier. */
var noIdOk = false;
try {
var noId = proxy.updateItem("Subscriber", { Status: "Unsubscribed" });
noIdOk = ("" + noId.Status === "OK");
} catch (exNoId) {
noIdOk = false;
}
assert("properties without an identifier does not succeed", noIdOk ? "true" : "false", "false");
/* Cleanup. */
var c1 = proxy.deleteItem("Subscriber", { SubscriberKey: tag + "-a" });
assert("cleanup: fixture subscriber deleted", "" + c1.Status, "OK");
</script>
Return Value
{
Status: "OK",
RequestID: "...",
Results: [
{
StatusCode: "OK",
StatusMessage: "Updated DataExtensionObject",
OrdinalID: 0,
ErrorCode: 0,
Object: { /* the updated object */ }
}
]
}
updateItem updates a single object, so Results always contains exactly one entry. There is no top-level StatusMessage — the per-item status text lives on the Results entry.
Show test script
<script runat="server">
/*
* Chapter: Return Value
*
* Proves the documented return shape, field by field:
* 1. updateItem returns an OBJECT.
* 2. Status is "OK" when the item was updated.
* 3. RequestID is a non-empty string.
* 4. Results is an array and - because updateItem updates a SINGLE
* object - it ALWAYS contains exactly one entry.
* 5. The Results entry carries StatusCode ("OK" on success),
* StatusMessage ("Updated DataExtensionObject" for a DE row),
* OrdinalID (0 for the single item) and ErrorCode (0 on success).
* 6. The Results entry carries an Object field.
* 7. There is NO top-level StatusMessage - the per-item status text
* lives on the Results entry, not on the response root.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
var proxy = new Script.Util.WSProxy();
var tag = "uiR" + (new Date()).getTime();
/* Fixture - a data extension with one row to update. */
var de = proxy.createItem("DataExtension", {
Name: tag + "_de",
CustomerKey: tag + "_de",
Fields: [
{ Name: "SubscriberKey", FieldType: "Text", IsPrimaryKey: true, IsRequired: true, MaxLength: 254 },
{ Name: "Score", FieldType: "Number" }
]
});
assert("fixture data extension created", "" + de.Status, "OK");
var seed = proxy.createItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Properties: [
{ Name: "SubscriberKey", Value: tag + "-r1" },
{ Name: "Score", Value: "10" }
]
});
assert("fixture row created", "" + seed.Status, "OK");
/* 1.-7. The documented success shape. */
var result = proxy.updateItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Keys: [{ Name: "SubscriberKey", Value: tag + "-r1" }],
Properties: [{ Name: "Score", Value: "95" }]
});
assert("typeof result is object", typeof result, "object");
assert("result.Status is OK", "" + result.Status, "OK");
assert("typeof result.RequestID is string", typeof result.RequestID, "string");
assert("result.RequestID is not empty", (("" + result.RequestID).length > 0) ? "true" : "false", "true");
assert("typeof result.Results is object", typeof result.Results, "object");
assert("Results always contains exactly one entry", "" + result.Results.length, "1");
assert("Results[0].StatusCode is OK", "" + result.Results[0].StatusCode, "OK");
assert("Results[0].StatusMessage names the updated object type", "" + result.Results[0].StatusMessage, "Updated DataExtensionObject");
assert("Results[0].OrdinalID is 0 for the single item", "" + result.Results[0].OrdinalID, "0");
assert("Results[0].ErrorCode is 0 on success", "" + result.Results[0].ErrorCode, "0");
assert("typeof Results[0].Object is object", typeof result.Results[0].Object, "object");
assert("there is NO top-level StatusMessage", typeof result.StatusMessage, "undefined");
/* The update really took effect. */
var rows = Platform.Function.LookupRows(tag + "_de", "SubscriberKey", tag + "-r1");
assert("the update took effect", "" + rows[0]["Score"], "95");
/* Cleanup. */
var deCleanup = proxy.deleteItem("DataExtension", { CustomerKey: tag + "_de" });
assert("cleanup: data extension deleted", "" + deCleanup.Status, "OK");
</script>
Examples
Update subscriber status
var proxy = new Script.Util.WSProxy();
var result = proxy.updateItem("Subscriber", {
SubscriberKey: "sub_jane",
Status: "Unsubscribed"
});
Update DE row
var proxy = new Script.Util.WSProxy();
var result = proxy.updateItem(
"DataExtensionObject",
{
CustomerKey: "MyDE_Key",
Keys: [
{ Name: "SubscriberKey", Value: "sub_jane" }
],
Properties: [
{ Name: "Score", Value: "95" },
{ Name: "UpdatedAt", Value: Platform.Function.Now() }
]
}
);
Upsert with SaveOptions
var proxy = new Script.Util.WSProxy();
var result = proxy.updateItem(
"DataExtensionObject",
{
CustomerKey: "MyDE_Key",
Keys: [{ Name: "SubscriberKey", Value: "sub_jane" }],
Properties: [{ Name: "Score", Value: "95" }]
},
{ SaveOptions: [{ PropertyName: "*", SaveAction: "UpdateAdd" }] }
);
Show test script
<script runat="server">
/*
* Chapter: Examples
*
* Runs all three documented examples:
* 1. EXAMPLE 1 - "Update subscriber status": objectType "Subscriber"
* with SubscriberKey as the identifier and Status as the updated
* property; Status comes back "OK" and the subscriber really is
* Unsubscribed afterwards.
* 2. EXAMPLE 2 - "Update DE row": objectType "DataExtensionObject",
* the data extension named through the CustomerKey property, a FLAT
* Keys array of { Name, Value } identifiers and a FLAT Properties
* array of { Name, Value } pairs - including a date value produced
* by Platform.Function.Now(); the stored row carries the new values.
* 3. EXAMPLE 3 - "Upsert with SaveOptions": the same call plus the
* third argument { SaveOptions: [{ PropertyName: "*",
* SaveAction: "UpdateAdd" }] } upserts - a key that does not exist
* yet is ADDED rather than rejected.
* 4. CONTROL for 3 - without the SaveOptions argument the same
* not-yet-existing key is NOT added (the call returns Status
* "Error"), which is what makes the documented upsert option
* meaningful.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function countRows(deKey, field, value) {
try {
var found = Platform.Function.LookupRows(deKey, field, value);
return found ? found.length : 0;
} catch (exLookup) {
return 0;
}
}
var proxy = new Script.Util.WSProxy();
var tag = "uiE" + (new Date()).getTime();
/* 1. EXAMPLE 1 - update subscriber status. */
var madeSub = proxy.createItem("Subscriber", {
EmailAddress: tag + "@joernberkefeld.com",
SubscriberKey: tag + "-sub",
Status: "Active"
});
assert("example 1: fixture subscriber created as Active", "" + madeSub.Status, "OK");
var subResult = proxy.updateItem("Subscriber", {
SubscriberKey: tag + "-sub",
Status: "Unsubscribed"
});
assert("example 1: the subscriber update succeeds", "" + subResult.Status, "OK");
assert("example 1: the single item reports StatusCode OK", "" + subResult.Results[0].StatusCode, "OK");
var subCheck = proxy.retrieve("Subscriber", ["SubscriberKey", "Status"], {
Property: "SubscriberKey", SimpleOperator: "equals", Value: tag + "-sub"
});
assert("example 1: the subscriber is Unsubscribed afterwards", "" + subCheck.Results[0].Status, "Unsubscribed");
/* 2. EXAMPLE 2 - update a DE row through flat Keys + Properties. */
var de = proxy.createItem("DataExtension", {
Name: tag + "_de",
CustomerKey: tag + "_de",
Fields: [
{ Name: "SubscriberKey", FieldType: "Text", IsPrimaryKey: true, IsRequired: true, MaxLength: 254 },
{ Name: "Score", FieldType: "Number" },
{ Name: "UpdatedAt", FieldType: "Date" }
]
});
assert("example 2: fixture data extension created", "" + de.Status, "OK");
var seed = proxy.createItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Properties: [
{ Name: "SubscriberKey", Value: tag + "-r1" },
{ Name: "Score", Value: "10" }
]
});
assert("example 2: fixture row created", "" + seed.Status, "OK");
var rowResult = proxy.updateItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Keys: [
{ Name: "SubscriberKey", Value: tag + "-r1" }
],
Properties: [
{ Name: "Score", Value: "95" },
{ Name: "UpdatedAt", Value: Platform.Function.Now() }
]
});
assert("example 2: the flat Keys + Properties row update succeeds", "" + rowResult.Status, "OK");
assert("example 2: the single row reports StatusCode OK", "" + rowResult.Results[0].StatusCode, "OK");
var rows = Platform.Function.LookupRows(tag + "_de", "SubscriberKey", tag + "-r1");
assert("example 2: still exactly one row", "" + rows.length, "1");
assert("example 2: the Number value was updated", "" + rows[0]["Score"], "95");
assert("example 2: the Now() date value was stored", (("" + rows[0]["UpdatedAt"]).length > 0) ? "true" : "false", "true");
/* 4. CONTROL - without SaveOptions an unknown key is not added. */
var noUpsert = proxy.updateItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Keys: [{ Name: "SubscriberKey", Value: tag + "-r2" }],
Properties: [{ Name: "Score", Value: "50" }]
});
assert("control: without SaveOptions the missing key is not added", "" + countRows(tag + "_de", "SubscriberKey", tag + "-r2"), "0");
assert("control: without SaveOptions the update of a missing key returns Status Error", "" + noUpsert.Status, "Error");
/* 3. EXAMPLE 3 - upsert with SaveOptions. */
var upsert = proxy.updateItem("DataExtensionObject", {
CustomerKey: tag + "_de",
Keys: [{ Name: "SubscriberKey", Value: tag + "-r3" }],
Properties: [{ Name: "Score", Value: "95" }]
}, { SaveOptions: [{ PropertyName: "*", SaveAction: "UpdateAdd" }] });
assert("example 3: the upsert call succeeds", "" + upsert.Status, "OK");
assert("example 3: the single item reports StatusCode OK", "" + upsert.Results[0].StatusCode, "OK");
var upsertRows = Platform.Function.LookupRows(tag + "_de", "SubscriberKey", tag + "-r3");
assert("example 3: SaveAction UpdateAdd added the missing key", "" + upsertRows.length, "1");
assert("example 3: the upserted row carries the submitted value", "" + upsertRows[0]["Score"], "95");
/* Cleanup. */
var subCleanup = proxy.deleteItem("Subscriber", { SubscriberKey: tag + "-sub" });
assert("cleanup: subscriber deleted", "" + subCleanup.Status, "OK");
var deCleanup = proxy.deleteItem("DataExtension", { CustomerKey: tag + "_de" });
assert("cleanup: data extension deleted", "" + deCleanup.Status, "OK");
</script>