Change program settings
PATCH /program/settings| Scope | program:write |
| Customer session token | Not accepted: call from your server with an API key |
| Rate limit class | write_shopify (limits) |
| Idempotency key | Required (idempotency) |
| MCP tool | charm_update_program_settings |
The settings an assistant may change: the program name, the points name (primary language), and the points and reward expiry policies. The program switch, eligibility, join gate and everything else stay in the admin and are unknown fields here. Call with dry_run: true first. The response carries the whole program after the change.
Request body
Section titled “Request body”| Field | Type | Description |
|---|---|---|
program_name | string or null | Null restores the default name. (optional, nullable) |
points_name | string or object or null | The word for points in the shop’s primary language: a plural string (“stars”), or plural forms { one, few, many, other } for languages that decline. Null restores the default word. (optional, nullable) |
points_expiry | object | (optional) |
reward_expiry | object | (optional) |
dry_run | boolean | Preview only: validate, resolve references and return the diff and summary, but write nothing. Costs no idempotency key and is limited as a read. Call with this first, show the merchant, then repeat without it. (optional) |
if_revision | integer | The program revision you last read (from GET /program or a previous write). When the program changed since, the write is refused with 409 revision_conflict instead of overwriting a concurrent admin edit. (optional) |
Response 200
Section titled “Response 200”Returns ProgramWriteResult.
| Field | Type | Description |
|---|---|---|
dry_run | boolean | True when nothing was written: the diff shows what the same call without dry_run would do. |
revision | integer | The program revision after the write (unchanged on a dry run). Send it back as if_revision on the next write. |
operation | string: create, update, delete, none | |
diff | array of FieldChange | |
summary | string or null | The admin’s one-line summary of the rule after the change. (nullable) |
earning_rule | EarningRule or null | (optional, nullable) |
reward | Reward or null | (optional, nullable) |
tier | Tier or null | (optional, nullable) |
program | Program or null | (optional, nullable) |
position | integer | Tier writes: the tier’s place in the ladder, 0 = the entry tier. (optional) |
tiers_enabled | boolean | Tier writes: whether VIP tiers are live. While they are off, adding or removing a tier moves nobody. (optional) |
member_impact | TierMemberImpact or null | (optional, nullable) |
references | array of object | Removing a tier: rules and live campaigns that name it. They keep working, but their per-tier part no longer applies to anyone. (optional) |
{ "dry_run": false, "revision": 1, "operation": "create", "diff": [ { "path": "path", "before": null, "after": null } ], "summary": "summary", "earning_rule": { "id": "id", "type": "earn", "enabled": true, "label": "Points per order", "points": 120, "points_per_currency": 120, "limit": 1, "title": "title", "title_translations": {}, "fields": {}, "summary": "summary" }, "reward": { "id": "id", "type": "earn", "enabled": true, "name": "Gold", "points_cost": 120, "discount_type": "percentage", "discount_value": 1, "code_valid_days": 1, "title": "title", "title_translations": {}, "fields": {}, "summary": "summary" }, "tier": { "id": "id", "name": "Gold", "handle": "handle", "name_translations": {}, "threshold": 1, "points_multiplier": 120, "combine": "any", "criteria": [ null ], "benefits": [ null ] }, "program": { "enabled": true, "program_name": "Rewards Club", "points_name": "points", "points_expiry": { "enabled": null, "months": null }, "reward_expiry": { "enabled": null, "code_valid_days": null }, "eligibility": { "customer_audience": null, "excluded_customer_tags": null, "excluded_product_tags": null }, "referral": { "enabled": true, "code_prefix": "REF", "discount_type": "percentage", "discount_value": 1, "minimum_purchase": 1 }, "memberships_enabled": false, "tiers_enabled": false, "earning_rules": [ null ], "redemption_rules": [ null ], "revision": 1, "updated_at": "2026-10-01T09:30:00.000Z" }, "position": 1, "tiers_enabled": false, "member_impact": { "members_evaluated": 1, "promoted": 1, "demoted": 1, "replaced": 1, "gift_codes": 1, "gifts": [ { "tier_id": null, "tier_name": null, "label": null, "codes": null } ], "per_tier": [ { "tier_id": null, "name": null, "members": null } ], "members_in_removed_tier": 1, "truncated": false }, "references": [ { "kind": "earning_rule", "id": "id", "label": "Points per order" } ]}Example
Section titled “Example”curl -X PATCH "https://charm.appfleece.app/api/v1/program/settings" \ -H "Authorization: Bearer chrm_live_..." \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{}'Errors
Section titled “Errors”unauthorized · invalid_token · insufficient_scope · access_required · validation_error · rate_limited · idempotency_conflict · shopify_unavailable
Every error body carries code, message, request_id and a doc_url pointing at the matching entry in the error catalog.