Skip to content

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_MANAGER
  • SESSION_ADMIN
  • SESSION_DEALER
  • SESSION_CRM_MANAGER
  • SESSION_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.