Skip to content

Undo a program change

POST /program/changes/{change_id}/undo
Scopeprogram:write
Customer session tokenNot accepted: call from your server with an API key
Rate limit classwrite_shopify (limits)
Idempotency keyRequired (idempotency)
MCP toolcharm_undo_program_change

Puts the rule, reward, tier or setting back to how it was before the change, through the same save — so the storefront follows, and the undo is logged as a change of its own. Refused with 409 revision_conflict when the target changed again since, was undone already, or the program moved past if_revision. A change that flips a program switch or touches a setting outside PATCH /program/settings cannot be undone here (422). Undoing an undo re-applies the original change. Call with dry_run: true first.

NameInTypeDescription
change_idpathstringThe change’s id from GET /program/changes.
FieldTypeDescription
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 ProgramUndoResult.

FieldTypeDescription
dry_runboolean
revisioninteger
operationstring: create, update, delete, none
diffarray of FieldChange
summarystring or null(nullable)
undoneProgramChange
{
"dry_run": false,
"revision": 1,
"operation": "create",
"diff": [
{
"path": "path",
"before": null,
"after": null
}
],
"summary": "summary",
"undone": {
"id": "id",
"at": "2026-10-01T09:30:00.000Z",
"actor": {
"type": "admin",
"id": "id",
"label": "Points per order"
},
"operation": "create",
"target": {
"kind": "earning_rule",
"id": "id",
"label": "Points per order"
},
"diff": [
{
"path": null,
"before": null,
"after": null
}
],
"revision": 1,
"undone_at": "2026-10-01T09:30:00.000Z",
"undo_of": "undo of",
"summary": "summary",
"undoable": false
}
}
Terminal window
curl -X POST "https://charm.appfleece.app/api/v1/program/changes/<change_id>/undo" \
-H "Authorization: Bearer chrm_live_..." \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"dry_run":false,"if_revision":1}'

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.