Customer Groups

Create manual or rule-based customer groups and manage their memberships through the Store API.

Customer Groups require customer scopes: reads use read_customers and writes use write_customers. Manual groups have members you add or remove. Automatic groups select members from their saved rules. A group's type cannot change after creation.

Spending and order-count thresholds#

For lifetime_spend and orders_count, use gte or lte with a non-negative decimal string in value and omit value_id. Read GET /customer-groups/limits before constructing inputs: each numeric operator includes decimal_places and max_value. Spending operators also include currency with the store base currency code, symbol, and display precision. Use decimal_places for accepted amount precision; currency display precision can differ.

Field

Accepted value

Meaning

lifetime_spend

Use the store base currency, no grouping or symbol, at most 12 integral digits, and the currency's amount precision. For example, INR accepts 100.01 but rejects 100.001; JPY accepts 100; KWD accepts 100.001. Extra trailing zeroes that do not change the amount are accepted. Do not send scientific notation.

The customer's total recorded paid value less refunds, in the store base currency.

orders_count

A whole-number string from 0 through 2147483647, with no decimal point.

Orders recorded as paid. Refunding an order does not remove it from this count. For retained purchases that exclude fully refunded orders, use the purchase rules below.

Create, rule updates, and preview use the same validation. Invalid spending precision or bounds return HTTP 400 GROUP_RULE_MONEY_INVALID; invalid order counts return GROUP_RULE_ORDER_COUNT_INVALID. Malformed numeric values can return GROUP_RULE_NUMBER_INVALID, and unrelated references return GROUP_RULE_VALUE_SHAPE_INVALID. Saved rule values remain decimal strings; General display preferences do not change their meaning. Existing saved thresholds are not rounded automatically. Correct an invalid older threshold before resubmitting its rules.

Use purchase rules#

Automatic Customer Groups can use last_purchase_at and purchased_product rules. Before authoring or previewing one, call GET /customer-groups/purchase-rule-readiness. This read endpoint requires read_customers; the credential determines the store.

GET /customer-groups/purchase-rule-readiness json
{
  "success": true,
  "data": {
    "available": true,
    "status": "ready"
  }
}

While purchase history is being prepared, the endpoint returns available: false, status: refreshing, and reason: CUSTOMER_PURCHASE_FACTS_REFRESHING. Requests that create, change, preview, or evaluate purchase rules then return HTTP 409 with the same error code. Metadata-only updates, such as changing a group name without submitting rules, remain available. Retry after readiness becomes ready; do not interpret refreshing as no matching customers.

Field

Operators

Value and behavior

last_purchase_at

within_last, before, after, is_null, is_not_null

For within_last, use 1d through 365d, without signs or leading zeroes; each day is a rolling 24-hour period. For before and after, use a valid YYYY-MM-DD date in years 0001–9999. Dates use UTC calendar boundaries and exclude the selected day; after starts at the next UTC midnight. Omit value_id for every purchase-date rule. Null operators also require value to be omitted or null.

purchased_product

includes, excludes

Put the positive parent product ID in value as a canonical decimal string from 1 through 9223372036854775807, without whitespace, signs, or leading zeroes, and omit value_id. A parent product matches retained eligible quantity from any variant. Do not send a variant, category, or collection ID.

Purchase conditions count paid and cash-on-delivery orders with item quantity remaining after refunds. Cancelled, test, unpaid non-COD, and fully refunded orders do not count. A full monetary refund excludes the order even when no individual item quantities were marked as refunded. A fully refunded line no longer matches purchased_product; a partially refunded line still matches while eligible quantity remains. last_purchase_at is the latest order creation time among qualifying purchases, so an order can continue to set the date when another eligible item remains after refunds. Once readiness is complete, an eligible customer with no retained purchase matches last_purchase_at is_null and purchased_product excludes.

An invalid, deleted, or other-store parent product returns HTTP 400 with GROUP_RULE_PRODUCT_INVALID. Invalid dates or day ranges return GROUP_RULE_DATE_INVALID or GROUP_RULE_DURATION_INVALID; missing required values return GROUP_RULE_VALUE_REQUIRED. Extra values on an empty check or a value_id on a purchase-date rule return GROUP_RULE_VALUE_SHAPE_INVALID. Purchase-rule readiness only states whether these rules can be evaluated; it does not grant marketing consent.

Synchronize group membership#

Use the membership snapshot and change feed together when your integration needs a durable local copy of a Customer Group's membership. Both endpoints require read_customers. The credential determines the store, and each item contains only a customer UUID. The feed does not include customer profiles, contact details, or marketing-consent state; treat customer UUIDs as customer data and protect them accordingly.

Task

Endpoint

First-page query

Read a complete starting membership

GET /customer-groups/{id}/membership-snapshot

Optional limit from 1 to 250; default 100.

Replay later membership changes

GET /customer-groups/{id}/membership-changes

Optional non-negative after_revision and optional limit from 1 to 250; defaults are 0 and 100.

Take the initial snapshot#

GET /customer-groups/58ee109f-64f7-4a51-8d48-b0ca62c4236a/membership-snapshot?limit=1 json
{
  "success": true,
  "data": {
    "group_id": "58ee109f-64f7-4a51-8d48-b0ca62c4236a",
    "revision": 42,
    "ready": true,
    "last_evaluated_at": "2026-09-12T10:00:00Z",
    "customer_ids": ["87964951-2890-4b72-bd8f-78625a76c737"],
    "has_more": true,
    "next_cursor": "opaque"
  }
}

Always take this initial snapshot, even if you plan to request changes from after_revision=0: revision 0 can already have members but has no change item for each preexisting membership. Keep the returned revision. If has_more is true, request the next page with cursor as the only query parameter. The cursor pins every snapshot page to the same revision and page limit. If membership changes while you paginate, the API returns CUSTOMER_GROUP_MEMBERSHIP_RESTART_REQUIRED; discard the partial snapshot and restart without a cursor. An automatic group that is still refreshing returns CUSTOMER_GROUP_MEMBERSHIP_REFRESHING and no customer IDs or cursor.

Replay changes after the snapshot#

GET /customer-groups/58ee109f-64f7-4a51-8d48-b0ca62c4236a/membership-changes?after_revision=42&limit=100 json
{
  "success": true,
  "data": {
    "group_id": "58ee109f-64f7-4a51-8d48-b0ca62c4236a",
    "current_revision": 44,
    "history_floor_revision": 12,
    "through_revision": 44,
    "group_deleted": false,
    "changes": [
      {"revision": 43, "operation": "added", "customer_id": "28f97875-549a-4ec3-a074-51b159411f99"},
      {"revision": 44, "operation": "removed", "customer_id": "87964951-2890-4b72-bd8f-78625a76c737"}
    ],
    "revisions": [
      {"revision": 43, "change_kind": "members_changed", "added_count": 1, "removed_count": 0, "recorded_at": "2026-09-12T10:05:00Z"},
      {"revision": 44, "change_kind": "members_changed", "added_count": 0, "removed_count": 1, "recorded_at": "2026-09-12T10:06:00Z"}
    ],
    "has_more": false
  }
}

Apply changes in the returned order: revision ascending, then operation in the fixed order added, removed, group_deleted, then customer UUID. A page contains at most limit change items, including a group_deleted marker. revisions supplies counts and timestamps for exactly the revisions touched by that page; counts can cover items split across more than one page. Persist each operation idempotently. For a page with has_more, checkpoint next_cursor only after the complete page is durable. For the final page, checkpoint through_revision only after the complete traversal is durable. Pagination is pinned to through_revision, so changes committed later do not enter the traversal. Begin the next traversal with after_revision equal to that checkpointed through_revision.

A removed operation means that the customer left this group. It does not mean that the customer withdrew marketing consent, and an added operation does not grant consent. Read and process marketing consent through the customer contract separately.

Promotional campaign control groups are configured by staff in Store Admin or the mobile app and are not Store API resources. An integration can synchronize a Customer Group with these endpoints and run its own authorized experiment, but it must enforce destination consent, suppression, assignment and deletion rules itself. The membership feed cannot launch a Tringify campaign or place a customer into a Tringify campaign's message or control arm.

Cursors, retention, and deletion#

Cursors are opaque, bound to the credential's store, group, endpoint, page limit, and captured revision, and expire no later than 24 hours after the first page was issued. Continuation requests accept only cursor; changing limit or after_revision requires a new first page. Store cursors exactly as returned and never inspect or modify them.

Change history is retained for at least 30 days. history_floor_revision is the highest revision already removed; complete replay is available only when after_revision is at or above that floor. CUSTOMER_GROUP_MEMBERSHIP_CURSOR_EXPIRED means the cursor's 24-hour lifetime ended or required change history was removed; take a new snapshot instead of treating the result as no changes. The change feed remains readable after group deletion and ends with a group_deleted operation without a customer_id. After that marker is durable, discard the obsolete local membership mirror. Snapshot requests for a deleted group return CUSTOMER_GROUP_MEMBERSHIP_DELETED.

HTTP

Error code

Recovery

400

CUSTOMER_GROUP_MEMBERSHIP_CURSOR_INVALID

Start a new request with valid first-page parameters; do not reuse the cursor for another store, group, or endpoint.

404

CUSTOMER_GROUP_NOT_FOUND

Verify the group belongs to the credential's store.

409

CUSTOMER_GROUP_MEMBERSHIP_REFRESHING

Retry the first snapshot after automatic evaluation completes.

409

CUSTOMER_GROUP_MEMBERSHIP_RESTART_REQUIRED

Discard all partial snapshot pages and begin the snapshot again.

410

CUSTOMER_GROUP_MEMBERSHIP_CURSOR_EXPIRED

Take a new snapshot, then resume replay from that snapshot revision.

410

CUSTOMER_GROUP_MEMBERSHIP_DELETED

Stop snapshot synchronization; use the change feed to observe deletion when retained history permits.

Receive membership webhooks#

A merchant can connect a saved Customer Group to a webhook endpoint. The endpoint receives customer_group_membership.snapshot while a complete membership is synchronized, then customer_group_membership.changes for later revisions. These deliveries use the standard webhook JSON envelope and request signature described in Webhook events. Verify the signature against the raw request body, deduplicate by envelope event_id, and return a successful response only after durably accepting the batch.

Process batches by subscription_id, generation_number, and batch_sequence. generation is the opaque UUID for one synchronization epoch. generation_number increases when a fresh synchronization starts, and batch_sequence increases within that generation. HTTP requests can complete out of order. Stage a later sequence until earlier sequences in that generation are durable. When a larger generation number appears, discard partial work from older generations and build the replacement membership from the new snapshot.

customer_group_membership.snapshot data json
{
  "subscription_id": "6cb6ffb3-2d41-49cb-bac6-e3229c499cd3",
  "group_id": "bd74fa4d-13c3-4ae8-90ef-c4bed6bc6518",
  "generation": "c010b2a7-dd8b-4b24-8a03-9201becafbdd",
  "generation_number": 2,
  "batch_sequence": 1,
  "final": true,
  "revision": 18,
  "customer_ids": [
    "014f36c2-2469-4cc5-a105-e785d7605416",
    "bf655bea-c683-43e2-8792-16e4411d593d"
  ]
}

Collect every snapshot batch for one generation and promote it as the current membership only after all sequences through the batch marked final: true are durable. An empty final snapshot is a valid empty group. final closes that snapshot or change-page sequence; it does not close the connection.

customer_group_membership.changes data json
{
  "subscription_id": "6cb6ffb3-2d41-49cb-bac6-e3229c499cd3",
  "group_id": "bd74fa4d-13c3-4ae8-90ef-c4bed6bc6518",
  "generation": "c010b2a7-dd8b-4b24-8a03-9201becafbdd",
  "generation_number": 2,
  "batch_sequence": 2,
  "final": true,
  "from_revision": 18,
  "through_revision": 20,
  "changes": [
    {"revision": 19, "operation": "added", "customer_id": "8a4d941f-5541-4f54-9a71-29c4dc063987"},
    {"revision": 20, "operation": "removed", "customer_id": "014f36c2-2469-4cc5-a105-e785d7605416"}
  ],
  "revisions": [
    {"revision": 19, "change_kind": "members_changed", "added_count": 1, "removed_count": 0, "recorded_at": "2026-09-12T09:30:00Z"},
    {"revision": 20, "change_kind": "members_changed", "added_count": 0, "removed_count": 1, "recorded_at": "2026-09-12T09:31:00Z"}
  ],
  "group_deleted": false
}

Apply changes in their supplied order and make each revision idempotent. added inserts a customer UUID and removed removes it. revisions describes the source revisions represented by the batch and can include a revision with no item changes. Use through_revision as the durable source checkpoint only after the complete batch is accepted. A checkpoint shown by Tringify means the batch was queued; it does not prove that your endpoint received it.

When group_deleted is true, the changes include a terminal group_deleted operation without customer_id. Apply all earlier operations in the batch before removing the local group. Delivery is at least once, so retries can repeat the same event_id. Pausing and reconnecting begins a new generation with sequence 1 and a fresh snapshot. Removing the connection deletes its queued and historical deliveries, although a request already in flight can complete.

Endpoints#

Customer Group limits

GET read_customers

Get Customer Group limits.

Returns field, list, rule, membership, and store limits enforced by Customer Group endpoints.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

List Customer Groups

GET read_customers

List Customer Groups for the store.

Returns a paginated, searchable, sortable list of manual and automatic groups.

Query parameters

Name Type Description
page integer

Page number.

Example: 1
limit integer

Page size.

Example: 50
search string

Search by name or slug.

Example: vip
group_type string

Filter by manual or automatic.

Example: automatic
sort_by string

Sort by name, member_count, created_at, or updated_at.

Allowed values
namemember_countcreated_atupdated_at
Example: name
sort_direction string

Sort direction: asc or desc.

Allowed values
ascdesc
Example: asc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Get a Customer Group

GET read_customers

Get one Customer Group.

Returns the group, its rules, and membership freshness when it belongs to the token's store. membership.ready is false while membership needs refreshing. within_last uses rolling 24-hour days; date boundaries and birthday rules use UTC. birthday_within includes today through the selected number of days ahead; February 29 maps to February 28 in non-leap years.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Create a Customer Group

POST write_customers

Create a Customer Group.

Creates a manual group or an automatic group whose members are selected by its rules.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
name required string

Group name.

Example: VIP customers
slug string

Group slug. Omit on create to generate it from the name.

Example: vip-customers
description string

Merchant description.

Example: Customers eligible for VIP benefits.
type string

Group type: manual or automatic. Type cannot change after creation.

Example: automatic
match_type string

Whether all or any rules must match.

Example: all
rules array<object>

Automatic rules shaped as {field, op, value, value_id}.

Example: [{"field":"orders_count","op":"gte","value":"5"}]

Update a Customer Group

PUT write_customers

Update a Customer Group.

Updates supplied fields. Supplying rules replaces an automatic group's existing rules and refreshes its membership.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
name string

Group name.

Example: VIP customers
slug string

Group slug. Omit on create to generate it from the name.

Example: vip-customers
description string

Merchant description.

Example: Customers eligible for VIP benefits.
type string

Group type: manual or automatic. Type cannot change after creation.

Example: automatic
match_type string

Whether all or any rules must match.

Example: all
rules array<object>

Automatic rules shaped as {field, op, value, value_id}.

Example: [{"field":"orders_count","op":"gte","value":"5"}]

Delete a Customer Group

DELETE write_customers

Delete a Customer Group.

Deletes the group and its memberships without deleting customer profiles.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Preview automatic rules

POST read_customers

Preview Customer Group rules.

Returns the matching customer count and a sample without saving a group.

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
match_type required string

Whether all or any rules must match.

Example: all
rules required array<object>

Rules to preview.

Example: [{"field":"orders_count","op":"gte","value":"5"}]

List group members

GET read_customers

List members of a Customer Group.

Returns store-scoped members with pagination, literal name/email search, and sorting. Each page and its membership metadata use one snapshot. Check membership.ready before reuse; evaluated_at and valid_until are ISO timestamps. A rolling-date selection expires after five minutes; birthday selections expire at UTC midnight. Dirty or never-evaluated automatic groups are not ready. Pages from separate requests are not a frozen export. Membership does not grant marketing consent.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Query parameters

Name Type Description
page integer

Page number.

Example: 1
limit integer

Page size.

Example: 50
search string

Search member names or email addresses.

Example: lee
sort_by string

Member sort field.

Allowed values
namemember_countcreated_atupdated_at
Example: added_at
sort_direction string

Sort direction: asc or desc.

Allowed values
ascdesc
Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

List candidate members

GET read_customers

List customers that can be added to a manual group.

Returns active customers in the token's store that are not already members.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Query parameters

Name Type Description
page integer

Page number.

Example: 1
limit integer

Page size.

Example: 50
search string

Search member names or email addresses.

Example: lee
sort_by string

Member sort field.

Allowed values
namemember_countcreated_atupdated_at
Example: added_at
sort_direction string

Sort direction: asc or desc.

Allowed values
ascdesc
Example: desc

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Add group members

POST write_customers

Add customers to a manual group.

Adds valid store-scoped customers and returns the number newly added.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
customer_ids required array<string>

Customer UUIDs to add.

Example: ["f37a970d-5f56-4ca8-9d4d-4ea10190f8a5"]

Remove group members

POST write_customers

Remove customers from a manual group.

Removes matching memberships in the token's store.

Path parameters

Name Type Description
id required string

Customer Group UUID.

Example: 8eb31980-7f67-453f-bf13-873b62a47b68

Headers

Name Type Description
Authorization required string

Bearer Store API token.

Body parameters

Name Type Description
customer_ids required array<string>

Customer UUIDs to remove.

Example: ["f37a970d-5f56-4ca8-9d4d-4ea10190f8a5"]

Fields#

Field

Type

Create

Update

Required

Translatable

name

text

Yes

Yes

create

No

slug

slug

Yes

Yes

No

description

textarea

Yes

Yes

No

type

select

Yes

Yes

No

match_type

select

Yes

Yes

No

member_count

integer

No

No

No

last_evaluated_at

datetime

No

No

No

created_at

datetime

No

No

No

updated_at

datetime

No

No

No

Webhook events#

Subscribe to these events to keep your integration in sync with customer groups. Each event shows the required Store API scope and store permission, the available payload fields, and an example payload. Subscription setup is validated against those permissions; delivery is always restricted to the subscription's store.

Customer group created

EVENT customer_groups/create App scope: read_customers Staff permission: customers:write

Fired when a customer group is created.

Payload fields

Field Type Description
group.id string Always present
group.name string Selectable in the Payload builder
group.slug string Selectable in the Payload builder
group.description string Selectable in the Payload builder
group.type string Selectable in the Payload builder
group.match_type string Selectable in the Payload builder
group.member_count integer Selectable in the Payload builder
group.created_at string Selectable in the Payload builder
group.updated_at string Selectable in the Payload builder

Customer group updated

EVENT customer_groups/update App scope: read_customers Staff permission: customers:write

Fired when a customer group's definition changes.

Possible changed_fields values

The changed_fields array names exactly which of these changed in this event — use it to skip processing updates your integration doesn't care about.

description match_type name rules slug

Payload fields

Field Type Description
previous.id string Always present
previous.name string Selectable in the Payload builder
previous.slug string Selectable in the Payload builder
previous.description string Selectable in the Payload builder
previous.type string Selectable in the Payload builder
previous.match_type string Selectable in the Payload builder
previous.member_count integer Selectable in the Payload builder
previous.created_at string Selectable in the Payload builder
previous.updated_at string Selectable in the Payload builder
current.id string Always present
current.name string Selectable in the Payload builder
current.slug string Selectable in the Payload builder
current.description string Selectable in the Payload builder
current.type string Selectable in the Payload builder
current.match_type string Selectable in the Payload builder
current.member_count integer Selectable in the Payload builder
current.created_at string Selectable in the Payload builder
current.updated_at string Selectable in the Payload builder
changed_fields array Selectable in the Payload builder

Customer group deleted

EVENT customer_groups/delete App scope: read_customers Staff permission: customers:write

Fired when a customer group is deleted.

Payload fields

Field Type Description
group.id string Always present
group.name string Selectable in the Payload builder
group.slug string Selectable in the Payload builder
group.description string Selectable in the Payload builder
group.type string Selectable in the Payload builder
group.match_type string Selectable in the Payload builder
group.member_count integer Selectable in the Payload builder
group.created_at string Selectable in the Payload builder
group.updated_at string Selectable in the Payload builder