Get a free Shopify store audit

Shopify's appDowngradeAccessScopes: Write to Read Without Reauth

Shopify's new appDowngradeAccessScopes mutation lets apps drop a write scope while keeping its matching read access intact, no merchant reauthorization needed.

Shopify's appDowngradeAccessScopes: Write to Read Without Reauth — ASSOSIATIX Journal

Most integration teams think about access scopes in one direction: request more when a feature needs them, revoke when it doesn't. Shopify's Admin GraphQL API version 2027-01, announced October 7, 2026, adds a narrower option in between: appDowngradeAccessScopes, which replaces an optional write scope with its matching read scope instead of dropping access outright.

What the mutation actually changes

For apps using Shopify-managed installation, appDowngradeAccessScopes takes a list of write scope handles, such as write_products, and downgrades each one to its matching read scope, such as read_products. The app keeps reading products; it loses the ability to write them. The mutation only affects the calling app's own installation on the shop, and it only works on scopes the app has declared as optional. Required scopes can't be downgraded, scopes the app never declared are rejected, and write scopes that aren't currently granted are simply ignored rather than causing an error.

The request is atomic across the whole list: if any requested scope fails validation, Shopify rejects the entire call and the installation's scopes remain unchanged. There's no partial downgrade where some scopes change and others don't.

Why this is different from revoking

Before this mutation existed, the only lever for narrowing access was appRevokeAccessScopes. That works for removing scopes entirely, but it has a side effect that matters for least-privilege work: revoking a write scope also removes its read access when that read access was only ever granted through the write scope. An app that wants to stop writing products but keep reading them couldn't safely revoke write_products without risking read_products going with it.

appDowngradeAccessScopes closes that gap. It's built specifically for the case where an app's needs have shrunk from read-write to read-only, and it guarantees the read scope survives the change.

The error surface is explicit

Shopify documents a small, specific set of rejection reasons: APP_NOT_INSTALLED, APPLICATION_CANNOT_BE_FOUND, CANNOT_DOWNGRADE_NON_WRITE_SCOPES, CANNOT_DOWNGRADE_REQUIRED_SCOPES, CANNOT_DOWNGRADE_UNDECLARED_SCOPES, and UNKNOWN_SCOPES. That's useful for integration teams writing scope-hygiene automation: a failed downgrade call tells you precisely which guardrail you hit, rather than a generic failure, so you can decide whether the fix is changing the app's declared scopes or just not downgrading that particular one.

Where this fits in an integration's lifecycle

The practical use case is an app whose footprint has narrowed over time. A connector that used to sync inventory counts and prices both ways, for example, might eventually only need to read current state. Previously, cutting the write scope meant either living with a slightly looser-than-necessary permission set, or risking a revoke that breaks the read paths the app still depends on. appDowngradeAccessScopes gives teams a way to tighten what an app can do without touching what it still needs to see, and without asking the merchant to reauthorize the app from scratch. That's a small mutation, but it's the kind of primitive that makes ongoing least-privilege maintenance practical instead of theoretical.

Sources

Integrations & APIs

Working on something like this? We build it for clients every day.

Tell us what you're building.

Share a few details and we'll reply within 1–2 business days with questions, a scope and a quote.