Changing a live application
A sandbox application is edited in place. A live production application changes through releases, and production keeps serving until you switch.
Two regimes
While an application is a sandbox record or a production draft, PATCH /v1/developer/applications/{applicationId} edits it directly. Once production is approved and serving, that stops: a live application is changed through a release — the next version of the whole configuration, prepared beside what is serving — and through a small set of live changes that apply at once because they only ever narrow or stay inside what was already approved.
What needs review
Review is for material changes only. A release that contains none is approved the moment you submit it, with nobody reading it, and is ready to switch.
Material changes — the ones a reviewer reads
| Change | Why it is material |
|---|---|
| A redirect URI on a new domain | The response could go somewhere the review never saw. A new path on an already-approved origin is not material. |
| An added restricted scope, and the data categories added with it | Restricted scopes are gated on review; the reason you give becomes the justification the checklist reads. |
| A new name | It is the name on the consent screen. |
| A new privacy policy or terms address | They are what the person was told they could read before agreeing. |
Everything else — description, website, support email, removing a redirect URI, removing a scope, adding a non-restricted scope, which publisher profile the application names — is ready to switch at once.
A release, start to finish
- 1
Create a draft
POST …/releasesmakes a new draft prefilled from what production serves now. There is at most one open release per application. - 2
Edit it
PATCH …/releases/{releaseId}with any ofname,description,websiteUrl,supportEmail,privacyPolicyUrl,termsUrl,redirectUris,allowedClaimScopes,allowedDataCategories,publisherProfileId,restrictedScopeJustifications. Anything else in the body is refused.POST …/releases/{releaseId}/bring-overwith{ fields: [...] }copies chosen fields from the sandbox record instead of retyping them. - 3
Submit
POST …/releases/{releaseId}/submitwith{ reason }when the release is material — the reason is required then, and read by the reviewer. A non-material release goes straight toapproved. - 4
Wait, or withdraw
An
in_reviewrelease can be withdrawn withPOST …/releases/{releaseId}/withdraw. Staff may answerapproved,changes_requestedorrejected. - 5
Rebase if production moved
If a live change landed while the release was open, its base is stale and switching is refused with
RELEASE_BASE_CHANGED.POST …/releases/{releaseId}/rebasecarries your edits onto what production serves now; a release that is material afterwards goes back to draft. - 6
Switch
POST …/releases/{releaseId}/switchmakes production serve the approved release from now on. It requiresapproved, a current base, and a passing go-live checklist — otherwiseRELEASE_NOT_APPROVED,RELEASE_BASE_CHANGEDorRELEASE_CHECKLIST_FAILING. - 7
Switch back, within 30 days
POST …/releases/switch-backreturns production to the immediately previous version without review, for 30 days after it was replaced. After that it isRELEASE_SWITCH_BACK_EXPIRED; with nothing to go back to it isRELEASE_NO_PREVIOUS_VERSION.
Release statuses
draft- Being edited.
RELEASE_EMPTYblocks submitting one that changes nothing. in_review- Submitted with material changes; not editable.
changes_requested- Staff asked for something. Editable again; submit again when ready.
approved- Ready to switch, once its base is current and the checklist passes.
rejected- Refused. A new draft starts over.
withdrawn- You took it back before a decision.
live- What production serves now.
superseded- A version production used to serve. The most recent one can be switched back to for 30 days.
GET …/releases lists every version with a summary — including blockedBy, the list of codes above that currently stop a switch, and readyToSwitch. GET …/releases/{releaseId} is one release in full.
Live changes that apply at once
PUT …/live-changes/redirect-uris with { redirectUris, reason? } and PUT …/live-changes/scopes with { allowedClaimScopes, allowedDataCategories?, reason? } send the whole intended list. The service splits it:
- Removals, a new path on an already-approved origin, and an added non-restricted scope apply immediately. The application's owners are told, and the change is recorded as applied by the owner.
- A new redirect domain or an added restricted scope joins the release — a draft prefilled from what is live, or the release already in progress — and is submitted for review with your
reason(required then, up to 2000 characters). Production keeps its current values until you switch. - At least one approved redirect URI must stay. Removing them all while a new domain waits for review is refused.
Both need the admin level on the application and a change_production_application passkey confirmation. They are refused while UnifyID holds the application under a staff-imposed status, while it is suspended or terminating, or while anything above it stops it serving.
GET …/live-changes lists change requests opened before releases existed — still decided by staff, still withdrawable with POST …/live-changes/change-requests/{changeRequestId}/withdraw — plus the open release and whether the application is live. New change requests are never opened.
What this does not do
- Credentials and webhooks are never part of a release. They change in place, with a passkey, on the live record.
- The go-live checklist still applies at switch time. An approved release cannot be switched on while the production record fails a check — a lapsed
sandbox_sign_inincluded. - A release is a whole configuration, not a patch. Two people editing the one open release edit the same draft; there is no second draft to merge.
Verified against API commit 234dba22 on 2026-10-18. The routes, scopes, checklist, events and limits on these pages are read from that export, not typed.