MngUpdateLeadsByFilter¶
Writes an arbitrary combination of editable fields to every lead matching the
supplied filter. Only the fields present in the fields object are written.
The confirm flag decides whether anything is written. With confirm: false the
command runs every check and returns the counters describing what would happen,
without touching a record. With confirm: true the same run also persists the
change. The response shape is identical in both modes.
The command is available through the manager command API only; there is no REST
path for it. The kind is fixed by the command name, so customer_kind is not
accepted on input. See
Clients and Leads Commands.
It replaces the deprecated MngUpdateCustomersByFilter.
Access Control¶
Allowed sessions:
SESSION_MANAGERSESSION_ADMINSESSION_DEALERSESSION_CRM_MANAGERSESSION_CRM_ADMIN
The caller must have CRM access and set_leads. The requested deskFilter is first
narrowed to the desks the caller may see, and then every selected record is
checked individually against the caller's brand and desk scope. Records outside
that scope are reported as failures and are never written.
Every call is written to the journal, successful ones included.
Request¶
{
"command": "MngUpdateLeadsByFilter",
"extID": "1",
"data": {
"fields": {
"desk": "DESK_EU",
"segment": "vip"
},
"confirm": false,
"filter": {
"deskFilter": "*",
"limit": 100,
"offset": 0
}
}
}
Request Data¶
Top level:
| Field | Type | Required | Description |
|---|---|---|---|
fields |
object | Yes | Fields to write. At least one, all keys from the whitelist below |
confirm |
bool | Yes | false reports what would change without writing. true applies the change |
filter |
object | Yes | Record selection |
filter object:
| Field | Type | Required | Description |
|---|---|---|---|
deskFilter |
string | Yes | Desk wildcard mask, for example *, DESK_*, DESK_EU*,!DESK_EU_TEST. Must not be empty |
limit |
int | Yes | From 1 to 50000. Validated, but it does not limit how much is processed |
offset |
int | Yes | Minimum 0. Validated, but it does not limit how much is processed |
where |
array | No | [[field, operator, value], ...], all conditions must match |
orWhere |
array | No | OR comparison group; at least one condition must match |
whereNot |
array | No | [[field, value], ...] |
whereIn |
array | No | [[field, [values...]], ...] |
whereNotIn |
array | No | [[field, [values...]], ...] |
whereBetween |
array | No | [[field, [from, to]], ...] |
whereNotBetween |
array | No | [[field, [from, to]], ...] |
orderBy |
array | No | Example: [["created_time", "desc"]] |
Filter fields and operators are the same as for the customer table, including the
lifecycle_flags operators has_all, has_any, and has_none. Common filter
semantics are described in Table filter syntax; desk masks in
Desks TCP API.
Editable Fields¶
The fields object accepts these keys, and nothing else:
desk, manager_id, assigned_manager_id, enable, status, type,
source_type, lifecycle_flags_add, lifecycle_flags_remove,
deposit_allowed, withdrawal_allowed, pep_status, sanctions_status,
risk_level, aml_status, sales_status, risk_status, finance_status,
crm_stage, segment, lead_source, campaign, affiliate_id,
introducer_id, country_of_residence, citizenship, preferred_language,
timezone, email_verified, phone_verified, marketing_allowed,
first_contact_time, last_contact_time, next_contact_time.
customer_kind is not accepted. Neither is the whole lifecycle_flags mask: a
filtered selection is heterogeneous, so only the increments
lifecycle_flags_add and lifecycle_flags_remove are available, each bounded to
0..63. If the two overlap, the whole call is rejected with 400 INVALID_DATA
and the message lifecycle_flags_add and lifecycle_flags_remove overlap, and no
record is changed.
A record whose value the write does not alter counts as unchanged: it lands in
skipped, not in updated.
Response Data¶
Counters only, with no per-record rows, so the payload is the same size for four records or forty thousand.
{
"confirm": true,
"fields": {
"desk": "DESK_EU",
"segment": "vip"
},
"matched": 1240,
"updated": 900,
"skipped": 338,
"failed": 2,
"failures": [
{"customer_id": 1099, "error": "PERMISSION_DENIED"}
]
}
| Field | Type | Description |
|---|---|---|
confirm |
bool | Echo of the request flag |
matched |
int | Records selected by the filter, kind, brand scope, and desk mask |
updated |
int | Records actually written. Always 0 when confirm is false |
skipped |
int | Records that already held the requested value |
failed |
int | Records that did not pass the per-record checks |
failures |
array | One entry per failure with customer_id, error, and an optional message. Present only when non-empty |
Reading the Counters¶
After an applied run the identity matched = updated + skipped + failed holds.
On a dry run updated is 0 by definition, and the number of records that would
be written is matched - skipped - failed.
Response Statuses¶
| Status | Condition |
|---|---|
200 |
Dry run. Always, since nothing was meant to change |
200 |
Applied, at least one record written, no failures |
207 |
Applied, at least one record written, some failed |
409 |
Applied, nothing was written |
Once every record already holds the requested value, running the same request
again yields updated: 0 with skipped equal to matched and therefore 409.
That is an idempotent no-op, not a fault: tell the two apart by the counters.
Errors¶
| HTTP | Error | Description |
|---|---|---|
400 |
INVALID_DATA |
Request validation failed |
403 |
RET_NOT_ENOUGH_RIGHTS |
Missing permission, missing scope, or the record is outside the caller's visibility |
404 |
RET_NOT_FOUND |
No customer with that identifier exists |
Every error carries a message field with free-form text. Its contents are not
part of the contract; branch on error.