Skip to content
Cloud

Plans and approvals

Risk classes, which changes need a person, and how a passkey approval binds to the exact plan.

Change kinds and their risk

ChangeRisk classNotes
deployPROD_CHANGE in production, otherwise REVERSIBLECan send data out when it ships new code. Optional canary
rollbackREVERSIBLEReturns to an earlier deployment. Never reverses a migration
scaleREVERSIBLE0–50 replicas
env_changePROD_CHANGE in production, otherwise REVERSIBLEValues that look like secrets are refused; pass a secret handle instead
webhook_changePROD_CHANGE in production, otherwise REVERSIBLEHTTPS only
domain_changeIRREVERSIBLE
migration (expand)PROD_CHANGENeeds a down-migration digest
migration (contract)IRREVERSIBLECannot share a plan with a deploy
drop_databaseIRREVERSIBLE
exportIRREVERSIBLEAlways needs a passkey approval

A plan takes the risk class of its riskiest change.

When a person must approve

  • IRREVERSIBLE plans and exports: always.
  • PROD_CHANGE plans: when the plan is tainted, or when a deploy in it has no canary.
  • Anything else: only when the plan is tainted and can send data out (a preview of new code, settings, webhooks, domains, exports).

How many people must approve depends on your tier and policy. Business and above can require two for production database changes and irreversible actions. See Pricing.

The approval ceremony

  1. Create an approval request for a plan. Only named approvers can be asked, and the requester is never one of them.
  2. A WhatsApp message (falling back to SMS or email) carries a single-use link. Opening it shows what changes, what it affects, how it rolls back and who asked.
  3. The approver’s browser asks the server for a challenge bound to the request, the plan hash and the approver.
  4. The approver signs it with a passkey. If the plan has changed since, the approval is refused.

Create a plan

POST /v1/plans
x-aspian-tenant: <tenant uuid>
Content-Type: application/json

{
  "riskClass": "PROD_CHANGE",
  "summary": "Add partial refunds to payments",
  "steps": [{ "kind": "deploy", "idempotent": true, "params": { … } }]
}

Then POST /v1/plans/{planId}/approval-requests to ask for approval, and POST /v1/plans/{planId}/apply once it is approved. Full list: API reference.