https://api.[tenant].getomneo.com/api/v3.
How membership is decided
A Profile is a member of a dynamic group when all three of these hold:- It is returned by the group’s candidate query.
- It matches at least one active inclusion rule.
- It matches no active exclusion rule.
- Inclusion rules combine with OR. A Profile passes the inclusion gate when it matches any one of them.
- Exclusion rules are evaluated in order, and the first match wins. As soon as an exclusion rule matches, the Profile is out and no further rules are checked.
- Compose AND and NOT inside a single rule. Put more complex logic in one rule’s JSON Logic expression rather than spreading it across several rules, because separate rules only ever OR (inclusion) or short-circuit (exclusion).
Define the candidate query
Every dynamic group has a candidate query, set through thequery, query_type, and arguments fields on the definition. The query is the first gate: a Profile the query does not return is never evaluated against the rules, so it can never be a member.
The candidate query is the same mechanism automations use, configured the same way and drawn from the same set. For the full list of queries and their arguments, see Automation Queries.
A dynamic group must have a candidate query. You can change the query later, but you cannot remove it.
The query must return profiles, since membership is a set of profiles. Most queries do; ones that return other objects (
achievementProgress, expiredReservations, lastStockChangeList, pointBalance, tierAchieved, unpurchasedListItems) are valid in an automation but rejected here.
Create reusable Rule Definitions
Rules on a group do not carry their own logic. Each rule points at a Group Rule Definition, a reusable template that holds the JSON Logic expression. Create a template once and reference it from as many groups as you like.
Because the logic lives on the template, a group that references it adjusts behaviour only through
arguments, which override the template’s default_arguments by key. This keeps a single expression, such as “has a given status”, consistent everywhere it is used.
Fields available to a rule
A rule’s JSON Logic is evaluated against this context. Reference the fields withvar, as in the examples on this page.
The Rule Definition object
Reading a template withGET /groups/rule-definitions/{id} returns the shared logic and its metadata.
Update or delete a Rule Definition
Templates are shared, so a change ripples to every group that references them.PUT /groups/rule-definitions/{id}updates the template and returns200. Every dynamic group that references it becomes stale: itsrefresh_statusmoves tostaleand it is re-evaluated on the next run.DELETE /groups/rule-definitions/{id}returns204. Referencing groups become stale and their rules are left without logic, so re-point those rules at another template or delete them.- Setting
is_active: falsekeeps existing rules working but blocks new rules from referencing the template.
Attach rules to a group
A Rule is an instance of a template on a specific group. Add one withPOST /groups/definitions/{group}/rules.
A rule references a template and cannot carry its own logic. To change what a rule tests, point it at a different template or adjust its
arguments.
A rule read returns the template reference, this rule’s overrides, and an effective object:
effective object is the resolved view: the template’s logic merged with this rule’s argument overrides. Use it to confirm exactly what the rule evaluates without cross-referencing the template.
Edit or remove a rule
Update a rule withPUT /groups/definitions/{group}/rules/{rule} to re-point its group_rule_definition_id, or change its arguments, sort_order, or is_active. Remove it with DELETE /groups/definitions/{group}/rules/{rule}, which returns 204. Both mark the group stale so it is re-evaluated on the next run.
Create a dynamic group in one call
You do not have to create the definition and its rules separately. Passtype: "dynamic", the query fields, and a nested rules array where each rule references a group_rule_definition_id.
201 with the definition and its rules. In this example a Profile is a member when the candidate query returns it (profiles lapsed for 90 days), it has the vip status (inclusion), and it does not have the staff status (exclusion).
The definition comes back with the query fields, the refresh schedule, and each rule resolved into effective form:
current_member_count stays 0 on a dynamic definition even after it has members; size the group from its latest snapshot. For the full field reference, see Working with Groups.
The
query and query_type values above are illustrative. The candidate queries available to you are configured per tenant, so use a query that exists in your tenant rather than copying these names.arguments appears at two levels with different shapes. On the definition it configures the candidate query and is an array of { "name", "value" } objects. On a rule, and in a template’s default_arguments, it is a flat { "name": value } map, referenced in JSON Logic as args.<name>.Refresh and read snapshots
Omneo re-evaluates a dynamic group on the schedule set byrefresh_period and refresh_period_type (the same period enum as membership expiry: days, weeks, months, years, and the absolute_* variants). Each evaluation produces a snapshot that records the per-Profile result.
Start a run on demand:
202: the run has been accepted and will complete shortly. It does not return the new membership inline.
Read the runs, newest first, and drill into a single run’s per-Profile detail:
status completed; a run that could not finish has status failed with an error.
A
POST to /snapshots returns 202 with this same record before it finishes, so completed_at and total_profiles are not yet populated. Poll the snapshot until status is completed.filter[result_status] and filter[processing_status].
The second row shows the model in action: the Profile matched an inclusion rule (
100) but an exclusion rule (101) removed it, so it is not a member.
The current membership of a dynamic group is its most recent completed snapshot. Reading members through GET /groups/definitions/{group}/profiles (covered in Working with Groups) returns exactly that set.
The refresh_status field tells you where the group is in this cycle.
Editing the query or the rules marks the group
stale and schedules it for the next run. Start a snapshot run yourself if you need membership updated before the schedule fires.
Debug membership with explain
To understand why a single Profile is or is not a member without reading a whole snapshot, call the explain endpoint.200 and reports the outcome of the three gates for that Profile: whether the candidate query returned it, which inclusion rules matched, and whether an exclusion rule removed it.
For a Profile removed by an exclusion rule,
exclusion.matched is true and excluded_by names the rule:
reason tells you which gate to look at, and the per-rule detail shows which inclusion or exclusion rule was responsible.
Worked example: lapsed VIPs, excluding staff
This builds the group used throughout this guide from scratch.1
Create the reusable template
POST /groups/rule-definitions with a jsonlogic rule that checks a status. The response is 201 with the template id, for example 12. Reuse it for both the inclusion and exclusion rule by passing different arguments.2
Create the group and rules in one call
POST /groups/definitions with type: "dynamic", the candidate query, refresh_period, and a rules array referencing template 12 (inclusion, status: "vip") and template 20 (exclusion, status: "staff"). The response is 201 with the definition and its rules.3
Run the first snapshot
POST /groups/definitions/42/snapshots returns 202. It requires at least one active inclusion rule, so it would return 422 on a group with none.4
Read the result
GET /groups/definitions/42/snapshots lists runs newest first. When status is completed, total_profiles is the member count. GET /groups/definitions/42/profiles returns the members as group_snapshot_profile rows.5
Debug a missing Profile
If a customer you expected is absent,
GET /groups/definitions/42/profiles/{profile}/explain returns the reason: not_in_query means the candidate query did not return them, no_inclusion_match means no inclusion rule matched, and excluded_by_rule names the exclusion rule that removed them.Errors
Edge cases and gotchas
- The candidate query is the first gate. A Profile the query does not return can never be a member, whatever the rules say. Check
query.matchedin explain before the rules. - Inclusion is OR, exclusion is first-match. Separate rules only ever OR (inclusion) or short-circuit (exclusion). Put AND and NOT logic inside a single rule’s JSON Logic.
- Changes go stale, not live. Editing the query, a rule, or a referenced template marks the group
stale. Membership updates on the next scheduled run, or immediately if you start a snapshot. - A snapshot needs an inclusion rule. Starting a run on a group with no active inclusion rule returns
422. - Dynamic groups reject manual and expiry fields. Manual add or remove, and membership-expiry fields such as
periodandabsolute_expiry, return422on a dynamic group. current_member_countstays0. Size a dynamic group fromtotal_profileson its latest completed snapshot.- Deleting a template breaks its rules. A deleted Rule Definition leaves referencing rules without logic. Re-point them at another template or delete them.
Related
- Groups concept
- Working with Groups
- Favourite groups
- Group Rule API
- Add Group Rule API
- Edit Group Rule API
- Delete Group Rule API
- Browse Group Rule Definitions API
- Add Group Rule Definition API
- Update Group Rule Definition API
- Delete Group Rule Definition API
- Start a manual snapshot run API
- List snapshots API
- Explain group membership API