MngGetCustomersByFilter¶
Returns a paginated customer list.
email and phone are masked by default. A caller holding see_customer_contacts can request open values with contacts: "full". Email domain remains visible while masked, and filtering always works against full stored values in both modes.
Access Control¶
Requires CRM access and see_customers. The requested deskFilter is intersected with the manager desk scope unless the manager has see_all_customers or admin scope. Customer brand must match manager brand when brand scope is set.
contacts: "full" additionally requires see_customer_contacts, the same permission that governs MngGetCustomerContacts and full-contact export. It is checked once, before any customer is selected, so an unauthorised request returns immediately. Row-level visibility is unaffected by the flag: customers outside the caller's brand or desk scope are filtered out in both modes.
Request Parameters¶
| Name | Type | Required | Description |
|---|---|---|---|
limit |
int | Yes | Maximum rows, from 1 to 50000 |
offset |
int | Yes | Pagination offset |
deskFilter |
string | Yes | Desk wildcard mask, for example *, DESK_*, DESK_EU*,!DESK_EU_TEST |
contacts |
string | No | masked or full, default masked. full returns email and phone unmasked and requires see_customer_contacts |
where |
array | No | [[field, operator, value], ...] |
orWhere |
array | No | OR comparison group in [[field, operator, value], ...] format; 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"]] |
Request¶
{
"command": "MngGetCustomersByFilter",
"extID": "1",
"data": {
"limit": 50,
"offset": 0,
"deskFilter": "DESK_*",
"where": [
["email", "like", "example.com"]
],
"orderBy": [
["created_time", "desc"]
]
}
}
Asking for open contacts:
{
"command": "MngGetCustomersByFilter",
"extID": "2",
"data": {
"limit": 100,
"offset": 0,
"deskFilter": "*",
"contacts": "full",
"where": [
["lifecycle_stage", "=", 2]
]
}
}
Response Data¶
{
"structure": [
"customer_id",
"external_id",
"type",
"status",
"lifecycle_stage",
"enable",
"enable_otp",
"deposit_allowed",
"withdrawal_allowed",
"first_name",
"last_name",
"middle_name",
"full_name",
"birth_date",
"citizenship",
"country_of_residence",
"email",
"phone",
"preferred_language",
"timezone",
"brand",
"desk",
"manager_id",
"lead_source",
"campaign",
"affiliate_id",
"introducer_id",
"source_type",
"landing_url",
"referrer_url",
"utm_source",
"utm_medium",
"utm_campaign",
"utm_content",
"utm_term",
"import_batch_id",
"old_id",
"assigned_manager_id",
"crm_stage",
"segment",
"tags_json",
"email_verified",
"phone_verified",
"marketing_allowed",
"tax_id",
"national_id",
"pep_status",
"sanctions_status",
"risk_level",
"aml_status",
"kyc_status",
"sales_status",
"risk_status",
"finance_status",
"kyc_updated_time",
"aml_updated_time",
"last_contact_time",
"first_contact_time",
"next_contact_time",
"conversion_time",
"last_login_time",
"archive_time",
"created_time",
"updated_time",
"created_by",
"updated_by",
"meta_json"
],
"rows": [
[
1,
"",
0,
0,
0,
1,
0,
1,
1,
"John",
"Smith",
"",
"John Smith",
0,
"",
"",
0,
"",
"",
"",
"",
"",
"",
"",
"",
"",
"cl***@example.com",
"+35***000",
"",
"",
"default",
0,
10,
"",
"",
"",
"",
10,
"qualified",
"",
"",
0,
0,
0,
0,
"",
"",
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1777700000,
1777700000,
10,
10,
""
]
],
"count": 1
}
The example above is a masked response. With contacts: "full" the same row
returns [email protected] and +35700000000 in those two positions, and
nothing else in the response differs.
Contact Fields¶
The flag changes two values, never the shape of the response. structure keeps
the same columns, with the same names in the same order, in both modes, and
count, paging, filtering, and ordering are untouched. Omitting contacts is
identical to sending masked.
| Column | masked |
full |
|---|---|---|
email |
iv***@example.com |
[email protected] |
phone |
+79***567 |
+79161234567 |
Masking keeps the first two characters of the email local part and the first and last three digits of the phone. Empty values stay empty in both modes.
Any value other than masked and full is rejected by schema validation with
400. MngExportCustomersByFilter additionally
accepts the integer alias mask_contacts; that alias is not available here, the
list accepts contacts only.
Who Can Request Open Contacts¶
A caller qualifies when either of these holds:
- they are a super administrator, or
- they are an enabled manager session with the
access_crmscope andsee_customer_contacts = 1.
The predicate short-circuits on super administrator status, so such a caller may
request full even when see_customer_contacts is 0 in their record. Anything
reproducing this check client-side must reproduce the whole predicate rather than
read the raw permission field, or the option disappears for administrators who
are in fact entitled to it.
Client Integration¶
Because an unauthorised full is a hard 403 rather than a downgrade to masked
values, the client must know the caller's permission before it sends the request.
A stale permission cache produces an empty screen, not a degraded one.
Sending full is best wired to a deliberate user action, a "show contacts"
toggle, rather than sent automatically whenever the permission exists. It keeps
personal data off screens that do not need it, and it makes the audit record
correspond to something a person actually did.
Note that MngGetCustomer unmasks automatically for anyone
holding the permission, with no parameter at all, while this command requires the
parameter. Until a client starts sending contacts: "full", a manager with the
permission sees an open contact on the customer card and a masked one in the
list. That is expected, not a defect.
Audit¶
Every request that actually reveals contacts is written to the audit log with the
caller id, the number of rows returned, and the desk filter used. Requests
without contacts: "full" are not logged: this is the most frequently called
command in the CRM, and auditing every call would flood the log. The audit record
therefore marks a disclosure, not a query.
How Contacts Open Across Commands¶
| Command | Scale | How contacts open | Permission |
|---|---|---|---|
| MngGetCustomer | One customer | Automatically, no parameter | see_customer_contacts |
| MngGetCustomerContacts | One customer | Always, that is its purpose | see_customer_contacts |
| MngExportCustomersByFilter | Bulk, to a file | contacts: "full" |
export_customers plus see_customer_contacts |
MngGetCustomersByFilter |
Bulk, on screen | contacts: "full" |
see_customers plus see_customer_contacts |
Errors¶
| Error | Status | Condition |
|---|---|---|
INVALID_DATA |
400 |
contacts holds a value other than masked or full |
RET_NOT_ENOUGH_RIGHTS |
403 |
full requested without see_customer_contacts |
An unauthorised full fails the whole request: no structure, no rows, and no
count. The list does not degrade to masked values. This mirrors
MngExportCustomersByFilter, where the same
request is refused outright.