API changelog
How versions work
Section titled “How versions work”The Charm API is versioned by date. The current version is 2026-10-01.
-
Additive changes ship continuously in the current version: new endpoints, new optional request fields, new response fields, new webhook topics and new error
details. Build your client to ignore fields it does not know. -
Breaking changes ship only in a new dated version, which you opt into. Nothing changes for your integration until you do.
-
A key answers in the version it was created with. Upgrade it in Settings → API (open the key, then Upgrade), or send the
Charm-Versionheader to choose per request:Terminal window curl https://charm.appfleece.app/api/v1/shop \-H "Authorization: Bearer chrm_live_..." \-H "Charm-Version: 2026-10-01" -
Webhook endpoints deliver in the version they were created with, shown as
api_versionon the endpoint and sent as theCharm-Versionheader on every delivery. -
Every response carries
Charm-Version, the version it was rendered in. An unknown version answers422 validation_errorwith the live versions indetails.allowed. -
At most two versions are live. When a new one ships, the previous one keeps working and its retirement is announced here well in advance.
-
MCP tools always speak the current version; their schemas describe it.
Keys created before dated versions existed answer in 2026-10-01, the first version.
2026-10-03
Section titled “2026-10-03”- Changing a tier’s bar asks first: while VIP tiers are live,
PATCH /program/tiers/{tier_id}with newcriteriareturnsmember_impacton the dry run and needsconfirm_member_impact: true, like adding or removing a tier. A preview that stopped at its member limit asks for confirmation too. - Stricter program input: a social-follow or visit-a-link rule needs its
url; a product or collection discount perk needs its target, and members-only access at least one page, product or collection; every product, collection and page a tier’s or membership’s perk names must exist in the shop. Partner UTM values are refused with a422instead of being rewritten (letters, digits,_,-,{}; up to 60). fields.earnDenominatoron the purchase rule round-trips: send back whatGETreturned.- Change log:
target.kindalso listsreferral,membershipandaffiliate_group; the partner programme’s invoicing details are left out of a change’s diff; a campaign status change is not undoable (a campaign only moves forward). - MCP:
tools/listleaves out output schemas, the points estimates are marked read-only, deletes destructive; atools/callsent as a notification is not run, and every tool call appears in the developer console. 409 confirmation_requirednow says to send a new idempotency key with the confirmed call.- Tier changes reach every member reliably: after a tier is added, removed or changed, members are re-evaluated in batches that pick up where they stopped, even across a restart. A member of a removed tier who qualifies above the tier below it is promoted as usual, gifts included.
2026-10-01
Section titled “2026-10-01”program:write: an assistant or integration can now change the program itself, rule by rule.GET /program/rule-typesdescribes every earning rule, reward and tier benefit type with the fields it takes;POST/PATCH/DELETEon/program/earn-rulesand/program/rewards,PATCH /program/tiers/{tier_id}andPATCH /program/settings(names and expiry policies only). Validation comes from the same catalog the admin uses: a field outside its range is a422with the field path.- Dry runs and revisions on program writes:
dry_run: truereturns the exact diff and the admin’s summary line and writes nothing;if_revisionrefuses a write when the program changed since you read it (new error409 revision_conflict).GET /programcarriesrevision. - Change log and undo:
GET /program/changeslists every rule, reward, tier and settings change made in the admin or through the API, with the actor and the field-level diff;POST /program/changes/{change_id}/undoputs one back. - Richer rule objects:
EarningRuleandRewardcarryfields(the full configuration, as the write endpoints accept it),summaryandtitle;Tiercarrieshandleandbenefits. Additive. - The program, tier and referral switches cannot be flipped through the API;
those stay in the admin. Undo follows
the same rule: a change that flipped a switch, or touched a setting outside
PATCH /program/settings, is listed withundoable: false. Reward.typenow carries the reward type (it was alwaysnull); it equalsdiscount_type.- Bonus campaigns:
GET,POST,PATCHandDELETE /campaigns, withdry_run(includingwould_email, the members an enabled email phase would reach) andif_revisionon the campaign. Campaigns created through the API send no email until a phase is switched on. Campaign changes appear inGET /program/changesand can be undone. New error403 feature_disabledfor shops without campaigns. - Titles in every language:
title_translationson earning rules and rewards,name_translationson tiers,label_translationson tier benefits;GET /program/rule-typesreturns the shop’slanguages. - Change history in the admin: Programs → Change history lists every program and campaign change, from the admin or the API, with undo.
- Add and remove VIP tiers:
POST /program/tiers(atposition, default the top; the bar must climb) andDELETE /program/tiers/{tier_id}(not the entry tier;referenceslists rules and campaigns that name it). While tiers are live the dry run returnsmember_impact, and a write that moves members needsconfirm_member_impact: true(new error409 confirmation_required). Members of a removed tier are re-placed without a promotion email or tier gifts, in the admin too. - The referral program:
GET /program/referralsandPATCH /program/referrals: the referral rule’sfields(both sides’ rewards and conditions),friend_discount(the friend’s first-order code; its minimum followsfields.referralMinimumOrderAmount) andcode_prefix, withdry_run,if_revision, the change log (kindreferral) and undo. The referral rule is no longer changed throughPATCH /program/earn-rules/{rule_id}; that answers422pointing here. The switch stays in the admin. - Eligibility and e-mail templates:
GETandPATCH /program/eligibility(audience, excluded tags, products, variants and collections checked in Shopify, gift cards, discounted items, subscription renewals, membership purchases,opt_in);GET /program/emailsandPATCH /program/emails/{type}(one template on or off, withreach). Both write through the program settings save:dry_run,if_revision, change log and undo. The global e-mail switch stays in the admin. - Paid memberships:
GET,POST,PATCHandDELETE /program/memberships. Created off sale, on an existing product or a new draft (create_product); the price is read from the product; billing and length are fixed once a membership has members; delete only off sale and never sold. Change log (kindmembership) and undo, on the same save as the admin. - Partner programme:
GETandPATCH /program/affiliates/settings(commission, buyer discount, commission base, holdback, attribution window, code prefix, terms, UTM; through the program settings save with change log and undo) and partner groups (GET,POST,PATCH,DELETE /program/affiliates/groups).403 feature_disabledwhere the programme is not available. The switch, applications, approvals and payouts stay in the admin. - Connect an assistant with a one-time code: the admin’s Set up in chat
card (onboarding and the home page) shows the MCP address and a one-time
connection code; Charm’s OAuth approval page accepts the code instead of an
API key. The connection runs on a key Charm manages (Chat assistant
(Charm)), limited to
shop:read,program:read,program:writeandanalytics:read, and works without the per-store API enablement. Changes it makes are logged under the assistant’s name.
2026-09-30
Section titled “2026-09-30”- Dated versions: the
Charm-Versionheader, a version pinned on every key and webhook endpoint, andapi_versionon webhook endpoints. The first version is 2026-10-01; there are no breaking changes to act on. - Developer console in Settings → API: every request of the last 7 days
with its status, error and
request_id; webhook endpoints with their recent deliveries, Send again, test events and turning a switched-off endpoint back on; a Test key button. Test events carry"test": truein the payload and an event id starting withevt_test_. - Session tokens without a backend:
POST /session-tokens/exchangetrades a Shopify Customer Account API access token for a session token, and theme stores fetch one from/apps/charm/session-token. Headless storefronts. - Shopper self-serve actions with a session token: birthday, children,
pets, claiming a way to earn, tier gifts, referral shares;
variant_idon redemptions puts a gift product in the cart. - Referrals:
POST /referrals/claimreturns the friend’s discount and attributes the referral.
2026-09-29
Section titled “2026-09-29”- One call for a whole loyalty page:
include=rewards,history,program,referralonGET /customers/{customer_id}. - AI agents: the UCP loyalty extension
(AI agents and UCP) and cart points estimates with
POST /estimates. - Contract: typed response schemas for every endpoint, every list as
{ data, next_cursor, has_more }, every write reportingchanged, and adoc_urlon every error pointing into the error catalog. - Webhook payloads:
customer_idis now the customer GID, the id every endpoint accepts, with the numeric id incustomer_legacy_id. (No endpoint was subscribed at the time.) - Customer session tokens for browsers and apps (overview).
2026-09-26
Section titled “2026-09-26”- Product points estimates, the explicit join for join-gated programs
(
POST /customers/{customer_id}/enroll) andnext_tieron customers.
2026-08-20
Section titled “2026-08-20”- Outbound webhooks, OAuth for AI assistant connectors and
GET /analytics/summary.