Migration REST to GRAPHQL. How to publish to online store and POS?

I’m migrating a service layer adapter that used the deprecated REST API to the new GraphQL API.My clients install my public application in their stores and manage their products and variants in my (separate) backend.

This service layer adapter listens to the new products on my backend and syncs them on shopify. Roughly, the old procedure was:

def create_product(shop_token: str):
    activate_session(shop_token)
    product = shopify.Product()
    product.title = "title"
    product.published_scope = "global"
    ...
    variant = shopify.Variant()
    variant.option1 = "Default - DO NOT USE"
    variant.price = "100.00"
    ...

    product.variants = [variant]
    product.save()


def create_variant(variant_list)
    activate_session(shop_token)
    for variant in variant_list:
        variant = shopify.Variant()
        ...
        create_metafields(variant)
        variant.save()

Which is a very common pattern so no surprises here.I could port the product, variant and metafields creation and got it to look the same on the store admin. But noticed the publication is not done in the same request.After a good amount of digging I came on suggestions to use a mutation of this shape:

mutation = """
    mutation PublishToCurrentChannel($productId: ID!) {
        publishablePublishToCurrentChannel(id: $productId) {
            userErrors {
                field
                message
            }
        }
    }
"""
variables = {
    "productId": f"gid://shopify/Product/{product_id}",
}
do_query(mutation, variables)

This fails to pubblish complaining about lack of access scopes:

Access denied for publishablePublishToCurrentChannel field. Required access: `write_publications` access scope. Also: The user must have a permission to create and edit products

Which is kind of confusing because I already set those scopes on my application install hook and the manager I use to wrap this do_query call.

Scopes:

MAIN_APP_SCOPES ={
    "read_orders",
    "write_orders",
    "read_products",
    "write_products",
    "read_publications",
    "write_publications",
    ...  # several others

}

Session setup before do_query

def get_session():
    shopify.Session.setup(
        api_key=current_app.config["SHOPIFY_API_KEY"],
        secret=current_app.config["SHOPIFY_SHARED_SECRET"],
    )
    shopify_session = shopify.Session(
        self.shop.shop,
        "2025-07",
        self.shop.token,
        access_scopes=MAIN_APP_SCOPES,
    )
    shopify.ShopifyResource.activate_session(shopify_session)
    self._session = shopify_session
    return shopify_session

App install hook.

@adapter_blueprint.route("/", strict_slashes=False)
def index():
    shop = request.args.get("shop")
    scopes = MAIN_APP_SCOPES

    redirect_uri = url_for("adapter.finalize", _external=True, _scheme="https")
    shopify.Session.setup(
        api_key=current_app.config["SHOPIFY_API_KEY"],
        secret=current_app.config["SHOPIFY_SHARED_SECRET"],
    )
    session = shopify.Session(shop, SHOPIFY_API_VERSION)
    url = session.create_permission_url(scope=scopes, redirect_uri=redirect_uri)

    return redirect(url)

I’m at my wit’s end as most of the examples from the official docs just fail with syntax errors, or have missing key components.

I’ve built most of this flow following recommendations from this forum but I haven’t found THE right mutation to make the publication.

Some recent conversations also point to hard coded publications IDs, which I tired and also fails.

Is there some setup I’m missing?
Is my publish mutation wrong?
If the mutation is wrong, why it complains about permissions and not syntax?

My application is a public application on shopify plus. I’m in the understanding that this scope is supported on my plan.

Thank you all in advance.

Check the user and permission setting from the admin dashboard and confirm the user has product edit and create permission

The user in this context would be the store owner?

  1. May be the user is not store owner, user within the account doesn’t have the necessary permissions to perform the action the app. So confirm the user has permission to create, edit product

  2. Please confirm the api key used above has necessary permissions (write_publications,edit product etc)

  3. Go to your Shopify Partner dashboard and check your app’s permissions includes the

read_products
write_products
read_publications
write_publications

May you include a bit more detail on how to do that above?

I found no place on the partner dashboard listing the permissions.
Build configuration doesn’t list the permissions.
API Access doesn’t list anything related to publications (or access scopes).

The user-specific permissions you can get from Settings > Users > Click in the user.
Does feel by the code above that you are using a store token though
do you happen to have a request Id? I can try check logs on my side to see if we see anything that can help here

See if this works.
‘x-request-id’: ‘0dc3f080-6c70-4cb5-b31a-f03f575d31f7-1757090202’

If you are using any SHOPIFY_API_KEY, please check it has permission for read/write publications

worked, in the request I see that it’s missing “read_publications”.
Likely:

  • The app is using a per-user token and the user is missing that access scope, the solution, as @AMaL mentioned would be to go to the specific user and grant the access
  • if you are certain that you are using a shop scope, then I’d try refreshing the installation of the app (uninstall / install) to ensure it loaded the latest wrt scopes when installed

Thanks you both for the information.
I’m having a hard time finding the pannel AMaL is showing.
Is it to be found on the store > settings > apps and sales channels or rather on partner admin > apps > <select the app> > API Access.

Sorry if it’s a silly question but I’m maintaining this public app but were not involved in this setup. It is all new to me.

Setting > apps and sale channel > develop app > select you app > configuration > edit

My app is a public app. Not a custom app.
I don’t access develop app on the store.

Can you confirmed the user has read_publications?

Sorry again if this is being tedious.
Who’d be the user in this context?
Logging in the partner admin, on my app configuration I don’t have anything related to scopes.

In my test store settings, on apps and sales channels and app details, there’s no information about the scopes enabled.

What’s what I’m missing?

Are my customers required to re install the app?

Go to user and permission > select user > add product create edit permission

So, that is in the store settings. Right?
I’m not the store owner, and in my “user“, I don’t have any panel related to permissions.
I see other staff users that don’t have “publications” on the product permissions but I can’t enable (not listing anything related to publications).

I can’t access the details of the store owner (getting on it ATM).

But then again. This means every store owner that has my app installed needs to enable the publications permissions on their store?

When i check a sample code, i noticed scopes are passed as array, please see the code.

shop_url = “SHOP_NAME.myshopify.com”
api_version = ‘2024-07’
state = binascii.b2a_hex(os.urandom(15)).decode(“utf-8”)
redirect_uri = “应用宝官网-全网最新最热手机应用游戏下载
scope should be omitted if provided by app’s TOML
scopes = [‘read_products’, ‘read_orders’]

newSession = shopify.Session(shop_url, api_version)
scope should be omitted if provided by app’s TOML
auth_url = newSession.create_permission_url(redirect_uri, scopes, state)

But in your code passed as object, can you please check the code by using the scope as below.

MAIN_APP_SCOPES = [
“read_orders”,
“write_orders”,
“read_products”,
“write_products”,
“read_publications”,
“write_publications”,
# … other scopes
]

So, that is in the store settings. Right?
Yes

it’s actually a set (it’s python, not js), so it’s the same.

SHOPIFY_API_SCOPES= write_products,write_customers,write_draft_orders

return apps.get_app_config(“shopify_app”).SHOPIFY_API_SCOPES.split(“,”)

As my knowledge session.create_permission_url to be a list, not a set

Fyi: i am not a python dev

I could acquire the required pemissions building a redirect uri like so:

https://<store>.myshopify.com/admin/oauth/authorize?client_id=<client_id>&scope=read_orders,write_orders,read_products,write_products,read_publications,write_publications,write_script_tags,read_checkouts,read_merchant_managed_fulfillment_orders,write_merchant_managed_fulfillment_orders,write_customers,read_customers,read_customer_payment_methods,write_customer_payment_methods,read_own_subscription_contracts,write_own_subscription_contracts&redirect_uri=<redirect_uri>

So it seems to me that re installing the application is mandatory.