Skip to content

MngUpdateCustomersAssignedManagerByFilter

Sets assigned_manager_id, the CRM owner, for every customer matching the supplied filter. The filter accepts the same parameter set as MngGetCustomersByFilter, so a selection previewed in the customer list can be reused here unchanged.

The confirm flag decides what happens. With confirm: false the command runs every validation and access check but writes nothing, returning the counters that describe the outcome. With confirm: true the same run also persists the change. The response shape is identical in both modes, so a client can render one screen for the preview and the result.

Use this method for portfolio handover, team rebalancing, and campaign reassignment. To move a single customer, use MngUpdateCustomer. To move customers between desks rather than managers, use MngUpdateCustomersDeskByFilter, which follows the same contract.

SEO

Page summary: Bulk-reassign CRM customers to a manager through the ScaleTrade manager TCP API, with a dry-run preview.

Keywords: ScaleTrade customer API, MngUpdateCustomersAssignedManagerByFilter, bulk reassign customers, mass manager assignment, CRM owner reassignment, manager TCP API, dry run bulk update, customer portfolio handover.

Access Control

Allowed sessions:

  • SESSION_MANAGER
  • SESSION_ADMIN
  • SESSION_DEALER
  • SESSION_CRM_MANAGER
  • SESSION_CRM_ADMIN

The caller must have CRM access and set_customers. Session type is checked as explicit set membership, not as a privilege ladder: a type outside the list is rejected regardless of its numeric value.

Scope is enforced twice. The requested deskFilter is first narrowed to the desks the caller may see, and then every selected customer is checked individually against the caller's brand and desk scope. Customers outside that scope are reported as failures and are never written. Admin scope widens the brand filter; super admin bypasses the scope and permission checks, but never the per-customer scope check.

Behavior

  • confirm is mandatory. There is no default, so an incomplete request can never write anything.
  • limit and offset are required by the schema but have no effect. Every customer matching the filter is processed, not just one page.
  • orderBy is accepted for schema compatibility with MngGetCustomersByFilter but has no observable effect, because the response carries counters rather than rows.
  • The target manager is validated once, before the loop. A manager that does not exist, is disabled, lacks CRM access, or is the hidden recovery manager id=1 rejects the whole request with 400 INVALID_MANAGER, rather than producing one identical failure per customer.
  • Brand match is checked per customer. The target manager must belong to the same brand as the customer; this is the only target check that depends on the individual record.
  • assigned_manager_id: 0 is valid and clears the assignment for every matching customer. Both the target validation and the brand check are skipped in that case, but scope checks still apply.
  • Customers already assigned to the target manager are counted in skipped and left untouched, so updated_time is not disturbed and the audit trail stays clean.
  • Application is partial. A failure on one customer does not stop the run; it is recorded in failures and processing continues.
  • Both modes perform identical checks. The dry run differs only in that it does not write, so the preview reports the real outcome.
  • Every call is written to the audit log with the caller id, mode, target manager id, and all four counters.

Order Of Operations, Per Customer

  1. Brand and desk scope check. A failure yields PERMISSION_DENIED.
  2. Already assigned to the target manager: counted in skipped, no further work.
  3. Target manager brand compared with the customer brand. A mismatch yields INVALID_MANAGER.
  4. With confirm: false, processing stops here.
  5. Assignment written through the standard customer update path. Storage errors are recorded as failures.

Request

Dry run, report what would change:

{
  "command": "MngUpdateCustomersAssignedManagerByFilter",
  "extID": "1",
  "data": {
    "assigned_manager_id": 10,
    "confirm": false,
    "filter": {
      "deskFilter": "*",
      "limit": 100,
      "offset": 0,
      "where": [
        ["lifecycle_stage", "=", 0],
        ["brand", "=", "default"]
      ]
    }
  }
}

Apply, the same request with the flag flipped:

{
  "command": "MngUpdateCustomersAssignedManagerByFilter",
  "extID": "2",
  "data": {
    "assigned_manager_id": 10,
    "confirm": true,
    "filter": {
      "deskFilter": "*",
      "limit": 100,
      "offset": 0,
      "where": [
        ["lifecycle_stage", "=", 0],
        ["brand", "=", "default"]
      ]
    }
  }
}

Clear the assignment for every matching customer:

{
  "command": "MngUpdateCustomersAssignedManagerByFilter",
  "extID": "3",
  "data": {
    "assigned_manager_id": 0,
    "confirm": true,
    "filter": {
      "deskFilter": "DESK_EU*",
      "limit": 100,
      "offset": 0
    }
  }
}

Request Data

Top level:

Field Type Required Description
assigned_manager_id int Yes Target CRM manager id, minimum 0. 0 clears the assignment
confirm bool Yes false reports what would change without writing. true applies the change
filter object Yes Customer selection, same parameter set as MngGetCustomersByFilter

filter object:

Field Type Required Description
deskFilter string Yes Desk wildcard mask, for example *, DESK_*, DESK_EU*,!DESK_EU_TEST. Narrowed to the desks visible to the caller
limit int Yes From 1 to 50000. Required by the schema, does not limit the update
offset int Yes Minimum 0. Required by the schema, does not limit the update
where array No [[field, operator, value], ...], all conditions must match
orWhere array No OR comparison group; at least one condition must match. Other filters stay mandatory
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"]]. Accepted for compatibility, has no observable effect

Supported filter fields are the customer identity, contact, CRM, acquisition, compliance, and lifecycle fields, the same set as MngGetCustomersByFilter. String comparisons support =, !=, and like, where like is a case-insensitive substring match. Common filter semantics, including grouped orWhere, are described in Table filter syntax; desk masks are described in Desks TCP API.

Response Data

Counters only, with no per-customer rows, so the payload stays the same size whether four customers are affected or forty thousand. The key set is identical in both modes.

Dry run:

{
  "confirm": false,
  "assigned_manager_id": 10,
  "matched": 1240,
  "updated": 0,
  "skipped": 338,
  "failed": 2,
  "failures": [
    {"customer_id": 1099, "error": "PERMISSION_DENIED"},
    {
      "customer_id": 1101,
      "error": "INVALID_MANAGER",
      "message": "Manager belongs to another brand"
    }
  ]
}

Applied:

{
  "confirm": true,
  "assigned_manager_id": 10,
  "matched": 1240,
  "updated": 900,
  "skipped": 338,
  "failed": 2,
  "failures": [
    {"customer_id": 1099, "error": "PERMISSION_DENIED"},
    {
      "customer_id": 1101,
      "error": "INVALID_MANAGER",
      "message": "Manager belongs to another brand"
    }
  ]
}
Field Type Description
confirm bool Echo of the request flag, so the client can tell a preview from an applied run
assigned_manager_id int Target manager id, echoed back. 0 means the assignment was cleared
matched int Customers selected by the filter, brand scope, and desk mask
updated int Customers actually reassigned. Always 0 when confirm is false
skipped int Customers already assigned to the target manager. Reported in both modes
failed int Customers that did not pass the per-customer checks. Reported in both modes
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 customers that would be reassigned is matched - skipped - failed.

Response Statuses

Status Condition
200 Dry run. Always, since nothing was meant to change
200 Applied, at least one customer updated, no failures
207 Applied, at least one customer updated, some failed
400 Schema validation failed, or the target manager is unusable
409 Applied, no customer updated

Repeating A Completed Run Returns 409

Once every customer is assigned to the target manager, running the same request again yields updated: 0 with skipped equal to matched and an empty failure list, and therefore 409. This is an idempotent no-op, not a fault. Clients must distinguish the two cases by the counters: skipped == matched with no failures means the work was already done, while a non-zero failed means nothing could be written.

Errors

Request-level:

Error Status Description
INVALID_DATA 400 Schema validation failed. The message field names the offending parameter
INVALID_MANAGER 400 The target manager does not exist, is disabled, has no CRM access, or is the hidden recovery manager. Message: Manager does not exist, is disabled, or has no CRM access
PERMISSION_DENIED_ACCESS 401 Session type is not in the allowed list
403 Caller context could not be resolved: not found, disabled, missing CRM scope, or missing set_customers

Per-customer, reported inside failures:

Error Description
PERMISSION_DENIED The customer is outside the caller's brand or desk scope
INVALID_MANAGER The target manager belongs to another brand than this customer
RET_ERROR Storage or internal error while writing the customer
RET_ERR_NOTFOUND The customer disappeared between selection and write

INVALID_MANAGER Appears At Two Levels And Means Different Things

At request level with status 400 the manager itself is unusable, and nothing was processed. Inside failures the manager is fine but belongs to a different brand than that particular customer. A selection spanning several brands will therefore succeed for some customers and fail for others with the same target. Narrow the filter by brand, or run the command once per brand.

See also MngUpdateCustomersDeskByFilter for the same contract applied to desks, MngGetCustomersByFilter for the selection, filtering, and scope rules, and MngDeleteAccountsList for the same bulk result shape.