Skip to content

Put a paid membership on sale or take it off

PATCH /program/memberships/{membership_id}/sale
Scopeprogram:write
Customer session tokenNot accepted: call from your server with an API key
Rate limit classwrite_shopify (limits)
Idempotency keyRequired (idempotency)
MCP toolcharm_update_membership_sale

Puts one membership on sale (a purchase of its product grants it) or takes it off sale, through the save the Memberships page uses, logged in the program changes. Going on sale needs the product active in Shopify. Every real change is refused with 409 confirmation_required until the call carries confirm_switch: true; the dry run and the refusal carry impact (the product, its price, current members). Show it to the merchant and get a clear yes.

NameInTypeDescription
membership_idpathstringThe membership’s id.
FieldTypeDescription
on_saleboolean
confirm_switchbooleanRequired on the real call, after the merchant saw impact and said yes. (optional)
dry_runbooleanPreview 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_revisionintegerThe 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)

Returns MembershipSaleWriteResult.

FieldTypeDescription
dry_runboolean
revisioninteger
membershipobject
operationstring: update, none
impactobject or null(nullable)
{
"dry_run": false,
"revision": 1,
"membership": {
"id": "id",
"name": "Gold",
"on_sale": false
},
"operation": "update",
"impact": {
"product": {
"id": "id",
"title": "title",
"status": "active",
"url": "https://example.com/charm-hook"
},
"price": "price",
"members": 1,
"notes": [
"notes"
]
}
}
Terminal window
# 1. Dry run: writes nothing and needs no Idempotency-Key. Show the merchant the result.
curl -X PATCH "https://charm.appfleece.app/api/v1/program/memberships/<membership_id>/sale" \
-H "Authorization: Bearer chrm_live_..." \
-H "Content-Type: application/json" \
-d '{"on_sale":false,"dry_run":true}'
# 2. After the merchant says yes: the real call with the confirmation.
curl -X PATCH "https://charm.appfleece.app/api/v1/program/memberships/<membership_id>/sale" \
-H "Authorization: Bearer chrm_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"on_sale":false,"confirm_switch":true}'

unauthorized · invalid_token · insufficient_scope · access_required · not_found · 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.