Skip to main content

Smart groups API

Read the smart groups the LLM Gateway uses, create virtual groups with a fixed member list, and set the rank that decides which group governs a person who is in several groups. The same groups appear in the Groups section of Govern > Policy Engine > LLM Gateway in the console.

Rank, strength and the API fields

The console Rank column is the API field priority: the number you edit, where a lower number wins. The console Strength column (#1 is the strongest) is the API field rank: a computed position you cannot set.

Groups
Synced from your directory
Virtual: fixed member list
Rank (priority)
Lower number wins
Ties: group name
Governing group
Best-ranked enabled group
One per person
Used by
Per-group app settings
Group budget sets
QuilrAI
CallWhat it doesScope
GET /smart-groups, GET /smart-groups/{group_name}List or read groups with members, priority and rank.read
POST /smart-groupsCreate a virtual group.config:write
PATCH /smart-groups/{group_name}Edit a virtual group, or override a synced group's rank (priority).config:write
POST /smart-groups/{group_name}/membersAdd or remove members of a virtual group without replacing the list.config:write
DELETE /smart-groups/{group_name}Delete a virtual group.config:write
POST /smart-groups/_priority-previewSee who would change governing group, and which budgets they would switch, before you save a priority. No writes.read

Try every operation with your own key in the Management API playground.

Rank and the governing group​

Every group has a rank number, the priority field (console Rank). A lower number is stronger. When a person is in several enabled groups, the group with the lowest priority is their governing group; equal priorities are ordered by group name. Disabled groups never govern anyone.

  • rank (console Strength) is computed from that order: the group's 1-based position among enabled groups, 1 being the strongest. It is null for a disabled group. You never send it; change priority instead.
  • Rank order decides:
    • Per-group guardrails (smart_group_policies in app settings): the person's groups are tried in rank order, and the first one that has a policy applies.
    • Group budget sets that use the strongest group's budget: the best-ranked of the person's groups in that set governs, which need not be a group with rank 1. See group budget sets.
  • Rules that check membership (for example access rules on user.smart_groups) match every group the person is in; rank does not matter there.
  • Lists are returned strongest first.

Synced and virtual groups​

Synced groupsVirtual groups
Where they come fromYour organization's Smart Groups and directory, kept up to date by a sync.Created in the console Groups tab or with POST /smart-groups.
NameThe synced name.Stored as virtual:<name>. The console shows the name without the prefix and a Virtual group label. Use the full name in policy conditions and budgets.
MembersManaged by the sync.A fixed list of emails you manage. The sync never changes or deletes a virtual group.
What you can change hereOnly the rank, as a priority override.Display name, members, enabled state and rank (priority).

Rank override. A synced group's priority is set by the sync (by default the groups are ordered by name). Send PATCH {"priority": n} to override it. The override survives every later sync. Send {"priority": null} to reset to the synced value. Reads show both: priority is the value in effect, synced_priority is the sync's value and priority_override is your override (or null).

Group fields​

FieldMeaning
group_nameFull name; virtual groups start with virtual:. Use it in the path.
nameName without the virtual: prefix.
display_name, emails, member_count, enabledWhat the group shows and who is in it.
priorityThe editable rank number (console Rank) in effect: the override when set, else the synced value. Lower wins.
synced_priority, priority_overrideThe sync's priority (a virtual group's own priority) and the admin override (null when none).
priority_override_updated_at, priority_override_updated_byWhen and by whom the override was last set or reset. A Management API write is recorded as management_key:<key_id>.
sourcesynced or virtual.
rankComputed 1-based position among enabled groups (console Strength); null when disabled. Read only.
versionSend it as If-Match on PATCH, DELETE and the members call.

Create and edit virtual groups​

export API="$MANAGEMENT_URL/llmgateway/management/v1"

curl -X POST "$API/smart-groups" \
-H "Authorization: Bearer $MANAGEMENT_KEY" \
-H "Idempotency-Key: create-sales-leads" \
-H "Content-Type: application/json" \
-d '{"name": "sales leads", "display_name": "Sales leads", "emails": ["ana@example.com", "li@example.com"], "priority": 10}'
  • Create takes name (required), display_name (default: the name), emails, enabled (default true) and priority (default 100). The name is lowercased with spaces collapsed, up to 200 characters; priority is reserved. The response (201) is {"smart_group": {...}} with group_name: "virtual:sales leads".
  • Edit with PATCH changes only the fields you send. emails replaces the whole list. Priorities are whole numbers from 0 to 1000000.
  • Change members with POST /smart-groups/{group_name}/members and {"add": [...], "remove": [...]} (at least one email; an email cannot be in both). Emails already present or already absent are ignored. The response is {smart_group, added, removed}, where added and removed count actual changes.
  • Delete answers 409 group_in_use with references (up to 50) when the active policy, budgets, exemptions, API-managed controls or app settings still name the group. Remove the references, or send ?force=true to delete anyway; the response then lists them in forced_references. Drafts are not checked.

Emails match case-insensitively and are stored lowercase.

Preview a rank change​

Before saving a priority, send the changes to POST /smart-groups/_priority-preview. Nothing is saved.

{"changes": [{"group_name": "executives", "priority": 1}, {"group_name": "virtual:sales leads", "priority": 20}]}
Response fieldMeaning
affected_users, affected_count, truncatedPeople whose governing group would change (email, from_group, to_group), the first 500, and the total.
tiesTies the change creates: a priority that a moved group would share with another enabled group that has members in common (shared_members). Existing ties the change does not touch are not listed. Tied groups are ordered by name; give them distinct priorities to be explicit.
budget_moves, budget_moves_count, budget_moves_truncatedPeople whose governing budget would change in a group budget set that uses the strongest group's budget: set_id, set_label, from_group, to_group, the budget ids and, when known, metric, window, from_limit and to_limit. apps lists the apps where the move happens ("*" means every other app) and is null when it happens everywhere. In sets with app-scoped budgets the governing group can depend on the request: conditional is then true and from_groups / to_groups list the possible groups.
budget_moves_unavailableSet when budgets could not be read; budget_moves is then empty.

A person who moves counts against the new group's budget from then on; their earlier usage stays on the old group's budget and is not carried over (a per-person budget they never used starts at zero; a shared group budget keeps its running total). Send null as the priority to preview a reset to the synced value (synced groups only). Up to 1,000 changes per preview.

Writes and errors​

  • POST /smart-groups and the members call need an Idempotency-Key; a retry with the same key replays the first result.
  • PATCH and DELETE need If-Match with the group's version (428 without it, 412 version_conflict when stale). If-Match is optional on the members call.
StatusCodeWhen
400invalid_requestA field has the wrong shape, a priority is out of range, or null was sent for a virtual group.
404not_foundThe group does not exist (also when it was deleted at the source).
409smart_group_existsA group with this name already exists.
409synced_group_read_onlyA field other than priority was sent for a synced group, or a synced group was deleted or given members.
409group_in_useThe group is still referenced; see references.
409idempotency_outcome_unknownThe group changed after a failed attempt with this key. Read it and retry with a new key.
503smart_group_storage_unavailable, reference_check_unavailableStorage or the reference check is unavailable. Retry.

Endpoints​

GET/smart-groups

List smart groups

Smart groups that app access rules, budgets and group policies can reference, in effective priority order. Synced groups come from the directory sync; virtual groups are created here or in the console.

REQUIRESread
Path, query & header parameters 2
limit (query)integeroptional

Page size.

min: 1max: 200default: 50
cursor (query)stringoptional

Opaque cursor from the previous page's next_cursor.

No request body.

curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups?limit=50' \
--header 'Authorization: Bearer <management-key>'

Authentication, errors & retry rules Try it in the playground

POST/smart-groups

Create a virtual smart group

Create an admin-managed group with a static member list. It is stored as virtual:<name>, is never changed by the directory sync and can be referenced like any other group. Enabled groups are ranked by priority number, lowest first (ties: group name). Per-group guardrail policies apply from the person's first ranked group that has one; strongest group budget sets charge the person's best-ranked group in the set; membership rules match every group. Requires an Idempotency-Key; 409 smart_group_exists when the name is taken.

REQUIRESconfig:write
Path, query & header parameters 1
Idempotency-Key (header)stringrequired

Unique per logical write. A retry with the same key and body replays the original result; the same key with a different body is a 409.

min length: 1max length: 200
Full request body specification application/json

display_namestringoptional

Shown in the console. Default: name.

min length: 1max length: 200
emailsarray<string>optional

Member email addresses (case-insensitive; stored lowercase, duplicates removed).

max items: 50000
Array item specification
string
enabledbooleanoptional
default: true
namestringrequired

Name without the virtual: prefix (lowercased, spaces collapsed). The group is stored as virtual:<name>. The name priority is reserved.

min length: 1max length: 200
priorityintegeroptional

Lower number wins when a person is in several groups.

min: 0max: 1000000default: 100

Unknown fields are rejected in this object.

curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups' \
--header 'Authorization: Bearer <management-key>' \
--header 'Idempotency-Key: create-contractors-001' \
--header 'Content-Type: application/json' \
--data '{
"display_name": "Contractors",
"emails": [
"dana@example.com"
],
"name": "contractors",
"priority": 5
}'

Authentication, errors & retry rules Try it in the playground

POST/smart-groups/_priority-preview

Preview priority changes

Who would change active group if these priorities were applied, plus the priority ties the change creates (a changed group lands on another enabled group's priority and they share members; existing ties are not listed), and budget_moves: people whose governing budget in a strongest group budget set would move to another group's budget (its own counter; usage is not carried over). Nothing is saved. Lists at most 500 people per list (truncated / budget_moves_truncated).

REQUIRESread
Full request body specification application/json

changesarray<object>required
min items: 1max items: 1000
Array item specification
group_namestringrequired

Full group name.

priorityinteger | nullrequired

Proposed priority; null: reset a synced group's override.

min: 0max: 1000000

Unknown fields are rejected in this object.

Unknown fields are rejected in this object.

curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups/_priority-preview' \
--header 'Authorization: Bearer <management-key>' \
--header 'Content-Type: application/json' \
--data '{
"changes": [
{
"group_name": "virtual:contractors",
"priority": 1
}
]
}'

Authentication, errors & retry rules Try it in the playground

DELETE/smart-groups/{group_name}

Delete a virtual smart group

Virtual groups only (synced: 409 synced_group_read_only). When the active policy, budgets, exemptions, managed controls or app settings name the group the response is 409 group_in_use with references; pass force=true to delete anyway. Requires the group's version in If-Match.

REQUIRESconfig:write
Path, query & header parameters 3
group_name (path)stringrequired
If-Match (header)stringrequired

Quoted version from the latest read of the group; 412 when it changed.

force (query)booleanoptional

Delete even when the group is referenced.

default: false
Full request body specification application/json

Unknown fields are rejected in this object.

curl --request DELETE \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups/engineering' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "9b2e4f0c7a1d"'

Authentication, errors & retry rules Try it in the playground

GET/smart-groups/{group_name}

Read a smart group

One smart group (name matched case-insensitively).

REQUIRESread
Path, query & header parameters 1
group_name (path)stringrequired

No request body.

curl --request GET \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups/engineering' \
--header 'Authorization: Bearer <management-key>'

Authentication, errors & retry rules Try it in the playground

PATCH/smart-groups/{group_name}

Update a smart group or its priority

Virtual group: change display_name, emails, enabled or priority. Synced group: only priority, which sets an override the directory sync never replaces; null resets it to the synced priority (other fields: 409 synced_group_read_only). Enabled groups are ranked by priority number, lowest first (ties: group name). Per-group guardrail policies apply from the person's first ranked group that has one; strongest group budget sets charge the person's best-ranked group in the set; membership rules match every group. Requires the group's version in If-Match.

REQUIRESconfig:write
Path, query & header parameters 2
group_name (path)stringrequired
If-Match (header)stringrequired

Quoted version from the latest read of the group; 412 when it changed.

Full request body specification application/json

At least one field. Synced groups accept only priority.

display_namestringoptional
min length: 1max length: 200
emailsarray<string>optional

Replaces the member list (virtual groups only).

max items: 50000
Array item specification
string
enabledbooleanoptional
priorityinteger | nulloptional

Virtual group: its priority (not null). Synced group: the priority override; null resets to the synced priority.

min: 0max: 1000000

Unknown fields are rejected in this object.

curl --request PATCH \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups/engineering' \
--header 'Authorization: Bearer <management-key>' \
--header 'If-Match: "9b2e4f0c7a1d"' \
--header 'Content-Type: application/json' \
--data '{
"priority": 1
}'

Authentication, errors & retry rules Try it in the playground

POST/smart-groups/{group_name}/members

Add or remove smart group members

Virtual groups only (synced: 409 synced_group_read_only). Adds and removes members without replacing the list; already-present adds and absent removes are ignored (added/removed count actual changes). Requires an Idempotency-Key; If-Match (group version) is optional.

REQUIRESconfig:write
Path, query & header parameters 3
group_name (path)stringrequired
Idempotency-Key (header)stringrequired

Unique per logical write. A retry with the same key and body replays the original result; the same key with a different body is a 409.

min length: 1max length: 200
If-Match (header)stringoptional

Quoted version from the latest read of the group; 412 when it changed.

Full request body specification application/json

At least one email in add or remove; virtual groups only.

addarray<string>optional

Emails to add (already-present ones are ignored).

max items: 50000
Array item specification
string
removearray<string>optional

Emails to remove (absent ones are ignored).

max items: 50000
Array item specification
string

Unknown fields are rejected in this object.

curl --request POST \
'https://guardrails-usa-1.quilr.ai/llmgateway/management/v1/smart-groups/engineering/members' \
--header 'Authorization: Bearer <management-key>' \
--header 'Idempotency-Key: create-contractors-001' \
--header 'If-Match: "9b2e4f0c7a1d"' \
--header 'Content-Type: application/json' \
--data '{
"add": [
"lee@example.com"
]
}'

Authentication, errors & retry rules Try it in the playground