Changelog
Every change to the Anlyon API contract, with the date it took effect and a migration note.
Every change to the API contract is listed here with a migration note. The newest entry is at the top. Dates are UTC.
2026-10-05
A plan counts environments, and every workspace starts with Production
Breaking, billing responses. limits.maxEnvironments and betaAllowances.environments are one number, or the string "unlimited". They were objects keyed by development, staging and production.
Affected responses:
GET /api/v2/billing/planGET /api/v2/billing/plansGET /api/v2/public/pricing-policy
| Plan | Environments |
|---|---|
| Early Beta Access | 3 |
| Free | 1 |
| Production | 2 |
| Growth | 3 |
| Enterprise | unlimited |
What else changed with it:
- A new workspace gets a default environment of kind
production, named Production, with protection on. Existing environments keep their kind, name and slug. - A workspace creates environments of kind
development,stagingandproductioninside one total.PATCH /api/v2/workspaces/{workspaceId}/environments/{environmentId}changeskindwith no plan check. - A create over the total returns
429QUOTA_EXCEEDED. - Early Beta Access includes environment protection, promotion between environments and the email notification channel. Email is capped at 500 emails per workspace per UTC month.
features.protectedProductionandfeatures.controlledPromotionaretruethere. - The message of
PAID_PLANS_UNAVAILABLEreads “Paid plans arrive after the beta. Nothing was charged. Your workspace keeps its Early Beta allowances.” The message ofHTTPS_REQUIREDreads “HTTPS is required.” Codes and statuses are unchanged.
Migration note.
- Read
maxEnvironmentsandbetaAllowances.environmentsas a number or the string"unlimited". A client that readmaxEnvironments.production, or summed the three keys, reads the one value. @anlyonhq/sdktypesBillingPlanLimits.maxEnvironmentsandBetaAllowances.environmentsasnumber | 'unlimited'. Update the package and fix the type errors it reports.- Deleting a secret or a schedule in a protected environment needs
confirmProtected: true. That now applies to the default environment of a new workspace. - A client that matched on the old message text of
PAID_PLANS_UNAVAILABLEorHTTPS_REQUIREDmatches on the code.
The Stripe refund adapter accepts a live or a test key
The stripe.refund adapter config names mode: "live" or mode: "test". The credential must be a Stripe key of that mode, and the payment intent must belong to that mode. A mismatch is refused before anything is sent. The fault drill runs with mode: "test".
Migration note. An action created with mode: "test" keeps working with its test key. To refund live payments, create an action with mode: "live" and store a live key as its secret.
2026-10-03
Notification routes are split into read, write and manage
Security fix, breaking. Every method on /api/v2/notifications used to need notifications:read. A key with that scope could change the alert webhook, the email recipients and send a test webhook.
| Route | Scope | Role |
|---|---|---|
GET /, GET /unread-count, GET /preferences |
notifications:read |
any member |
GET /preferences/me (new) |
notifications:read, needs a user |
any member |
PATCH /preferences/me (new) |
notifications:write, needs a user |
any member |
PATCH /{id}/read, PATCH /read-all, DELETE /{id} |
notifications:write |
any member |
PATCH /preferences, POST /preferences/test-webhook |
notifications:manage |
admin |
notifications:writeis in the default API key scope set.notifications:manageis privileged. No key receives it by default.- A member mutes notification types for themselves with
/preferences/me. A muted type is still raised and still delivered to every channel and every other member. - An API key has no user and answers
403USER_IDENTITY_REQUIREDon/preferences/me.
Migration note.
- An OAuth client connected before 2026-10-03 must re-consent before it can mark notifications read, dismiss them or change notification settings.
- An API key with an explicit scope list needs
notifications:writeadded to mark read or dismiss, andnotifications:manageto change workspace notification settings. Until then those calls answer403.
A third adapter, resend.email_send
Additive. POST /api/v2/actions and PATCH /api/v2/actions/{ref} accept adapter.type: resend.email_send with the config { domain, fromAddresses? }.
- Impact is counted in
emails, one per recipient acrossto,ccandbcc. succeededmeans Resend accepted the send and returned an email id. A read-back that matches grades the effectconfirmed. Neither grade means the email was delivered.- A replay is offered for 24 hours, the time Resend keeps an idempotency key.
Migration note. None. Existing actions are unchanged.
Any action can be governed, and every effect returns a grade
An action may carry impact, verify or governed: true. Such an action is governed: each invocation creates an effect, binds its approval to the exact request, reserves its declared quantity against every applicable impact limit before dispatch, and returns a receipt. An action with no declaration and no adapter is unchanged.
Additions:
ActionandActionVersionreturngoverned,impactandverify.Effectreturnsgrade:confirmed,acknowledged,unknown,failed,refused,deniedorpending.GET /api/v2/actions/effectsacceptsgradeas a filter.ImpactLimitreturnsunit, andPOST /api/v2/impact-limitsaccepts a declared unit asdimension.- Changing or removing what a governed action declares needs the
actions:governscope.
Breaking for typed clients. dimension on ImpactQuantity, ImpactLimit and CreateImpactLimitRequest is no longer a closed enum of money and resource_mutations. A workspace that declares a unit, such as emails, sees that unit name there.
Migration note. Treat dimension as a string. A workspace that declares no unit sees the same two values as before. Handle an unrecognised grade value as you would unknown.

