Usual Docs
View as Markdown

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, high or financial;
  • 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.

json
{
  "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=true to a command's endpoint, or call POST /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:

WhoNeeds approval for
AgentsAny medium, high or financial risk change, or any change touching more than 25 records
API keysfinancial changes, like retrying a charge
Staff in the adminNothing: 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:

ActorIs
merchant_userSomeone in the store's Shopify admin
api_keyAn integration using an API key
merchant_agentAn AI agent using an agent key
customerThe subscriber, from their account page or the store's portal
systemUsual itself: renewals, retries, syncing from Shopify