How changes work
Every change in Usual (a skip, a new offer, a cancellation, a setting) goes through one path, whether it comes from the admin, a customer, the API or an agent. That path is what makes it safe to hand to software.
Commands
A command is one kind of change: subscriptions.skip_next, offers.create, shop.update_settings. Each one declares:
- its input, as a JSON schema, checked before anything happens;
- who may run it: staff, API keys, agents, customers;
- the permission it needs, like
subscriptions:write; - its risk:
low,medium,highorfinancial; - whether it can be undone.
GET /commands (or list_commands in MCP) returns every command your key may run, with all of the above. The full list is in Commands.
Plans
Before a command changes anything, it works out a plan: a plain-language summary, the exact fields that would change from what to what, and how many records it touches.
{
"diff": {
"summary": "Deliver every 2 weeks instead of every month. The next charge date stays the same.",
"changes": [{ "path": "billing", "from": { "every": 1, "interval": "MONTH" }, "to": { "every": 2, "interval": "WEEK" } }]
},
"affected": 1
}You get a plan back when you:
- add
?preview=trueto a command's endpoint, or callPOST /plans; - use an agent key: agents always get a plan first, whatever they ask for;
- make a change that needs a person's approval.
Apply it with POST /plans/{id}/apply. Plans are applied exactly as previewed: if the subscription changed since (say the customer skipped in the meantime), the plan is refused as plan_stale instead of doing something nobody saw. Plans expire after 15 minutes; make a new one.
If nothing would change, you get "status": "noop" and nothing is recorded.
Approvals
Some changes wait for a person to approve them in Usual โ Activity. Built in, and merchants can only make these stricter:
| Who | Needs approval for |
|---|---|
| Agents | Any medium, high or financial risk change, or any change touching more than 25 records |
| API keys | financial changes, like retrying a charge |
| Staff in the admin | Nothing: they're the approvers |
A plan waiting for approval has "status": "awaiting_approval" and lasts 72 hours. Check it with GET /plans/{id}; once approved, apply it as usual.
Agents must also say why with every change (X-Change-Reason header, or reason in MCP). It's recorded with the change and shown to the person approving it.
Undo
Every applied change is recorded in the activity log: what changed, from what to what, who did it (and for agents, on whose behalf), why, and when. GET /activity lists them.
If a command is reversible, its record carries its own inverse. POST /activity/{id}/undo runs that inverse as a new change, through the same checks (so an agent's undo is a plan too). A change can only be undone once.
Who did it
Each change records one of these as its actor, and it's shown everywhere the change appears:
| Actor | Is |
|---|---|
merchant_user | Someone in the store's Shopify admin |
api_key | An integration using an API key |
merchant_agent | An AI agent using an agent key |
customer | The subscriber, from their account page or the store's portal |
system | Usual itself: renewals, retries, syncing from Shopify |