Setup Guide

Shopify Admin API Token Setup

New Dev Dashboard flow (post-Jan 2026) — Fill in your values and they populate every command.

What Changed

As of January 1, 2026, Shopify deprecated legacy custom apps. You can no longer create apps that show a static shpat_ token to copy-paste. The new Dev Dashboard gives you a Client ID and Client Secret which you exchange programmatically for a short-lived access token (24hr expiry).

Tokens no longer appear in the UI. You request them via API using your Client ID and Client Secret.

1 Create & Install the App

Open the Dev Dashboard

1

Go to your store admin. Fill in your store name below — it populates every URL and command:

SHOPIFY_SHOPYour myshopify subdomain (e.g. my-cool-store)
2

Click Develop apps

3

Click the Build apps in Dev Dashboard button (yellow banner at top)

4

This opens the Shopify Dev Dashboard at dev.shopify.com

Create a New App

1

Click Create an app

2

Give it a name (e.g. my-migration-tool)

3

You'll land on a Create version page

Configure the App Version

App URL: Leave as https://example.com — doesn't matter for API-only use.

Scopes: Click Select scopes or paste directly into the Scopes text box:

read_products,write_products,read_metaobjects,write_metaobjects,read_metaobject_definitions,write_metaobject_definitions,read_files,write_files,read_inventory,write_inventory,read_themes,write_themes,read_online_store_pages,write_online_store_pages,read_content,write_content
If your first token exchange fails: return here, check the Use legacy install flow checkbox, click Release to push a new version, then click Install on the new version before retrying. In some app/store configurations this is required for client-credentials to work; in others it isn't — skip it on the first attempt and only come back if you hit app_not_installed or shop_not_permitted.

Click the Release button (bottom-right).

Install on Your Store

1

After release, look for an Install option

2

Confirm the permissions dialog and click Install

3

The app opens an embedded view showing example.com — ignore it, close the tab

2 Get Your Credentials

1

Go back to the Dev Dashboard: dev.shopify.com

2

Open your app → Settings

3

Copy the Client ID (long hex string) and enter it below:

SHOPIFY_CLIENT_IDHex string from Dev Dashboard Settings
4

Reveal and copy the Client Secret (starts with shpss_) and enter it below:

SHOPIFY_CLIENT_SECRETStarts with shpss_ — NOT a usable API token
The shpss_ value is your Client Secret, not a Storefront token. It's only used to request a token.

Your .env file

3 Request an Access Token

Exchange your credentials for a short-lived access token. This replaces the old copy-paste shpat_ flow.

PowerShell

cURL

Expected Response

{
  "access_token": "f85632530bf277ec9ac6...",
  "scope": "read_products,write_products,...",
  "expires_in": 86399
}

The access_token is your Admin API token. Use it in the X-Shopify-Access-Token header. Expires in 24 hours.

4 Auto-Refreshing Auth Module

For scripts that run repeatedly, use a shared auth module that fetches and caches the token automatically. Both implementations below cache the token in memory and refresh on the next call after expiry. Pick whichever matches your project — they're functionally identical.

Node.js — auth.js

import 'dotenv/config';
import { URLSearchParams } from 'node:url';

const SHOP = process.env.SHOPIFY_SHOP;
const CLIENT_ID = process.env.SHOPIFY_CLIENT_ID;
const CLIENT_SECRET = process.env.SHOPIFY_CLIENT_SECRET;

let token = null;
let tokenExpiresAt = 0;

export async function getToken() {
  if (token && Date.now() < tokenExpiresAt - 60_000) return token;

  const response = await fetch(
    `https://${SHOP}.myshopify.com/admin/oauth/access_token`,
    {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams({
        grant_type: 'client_credentials',
        client_id: CLIENT_ID,
        client_secret: CLIENT_SECRET,
      }),
    }
  );

  const { access_token, expires_in } = await response.json();
  token = access_token;
  tokenExpiresAt = Date.now() + expires_in * 1000;
  return token;
}

Node.js — usage

import { getToken } from './auth.js';

const token = await getToken();
// Use in X-Shopify-Access-Token header

Node.js — package.json

{
  "name": "shopify-tooling",
  "type": "module",
  "private": true,
  "dependencies": {
    "dotenv": "^16.4.0"
  }
}

Run npm install in your project folder, then node test-auth.js to verify.

Python — auth.py

import json
import os
import time
import urllib.request
from urllib.parse import urlencode

from dotenv import load_dotenv
load_dotenv()

SHOP = os.environ['SHOPIFY_SHOP']
CLIENT_ID = os.environ['SHOPIFY_CLIENT_ID']
CLIENT_SECRET = os.environ['SHOPIFY_CLIENT_SECRET']

_token = None
_expires_at = 0


def get_token():
    global _token, _expires_at
    if _token and time.time() < _expires_at - 60:
        return _token

    body = urlencode({
        'grant_type': 'client_credentials',
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
    }).encode()
    req = urllib.request.Request(
        f'https://{SHOP}.myshopify.com/admin/oauth/access_token',
        data=body,
        headers={'Content-Type': 'application/x-www-form-urlencoded'},
    )
    with urllib.request.urlopen(req) as resp:
        data = json.loads(resp.read())

    _token = data['access_token']
    _expires_at = time.time() + data['expires_in']
    return _token

Python — usage

from auth import get_token

token = get_token()
# Use in X-Shopify-Access-Token header

Python — requirements.txt

python-dotenv>=1.0.0

Run pip install -r requirements.txt, then python test_auth.py to verify. Pure stdlib otherwise — works on Windows, macOS, and Linux without changes.

5 Troubleshooting

Error: app_not_installed

Your .myshopify.com subdomain doesn't match the store the app is installed on. Check Settings → Domains in your store admin for the correct subdomain.

Error: shop_not_permitted

The app and store are in different Shopify organizations. Client credentials only works within the same org.

Only seeing shpss_ token, no shpat_

The shpss_ is your Client Secret, not an access token. You must exchange it programmatically (see Part 3).

Token expired

Tokens last 24 hours. Use the auto-refreshing auth module (Part 4) or re-run the token request.

6 Quick Reference

Token prefixes

shpat_Admin API access token from a Dev Dashboard / public app. Sent in the X-Shopify-Access-Token header.
shpca_Admin API access token from a legacy Develop apps custom app. New ones can't be created after Jan 1, 2026; existing tokens still work.
shppa_Admin API access token from a legacy private app (long deprecated).
shpss_App's Client Secret (Shopify Shared Secret). Used to mint access tokens via client-credentials; never sent as a token itself.
shptka_Theme Access password — scoped to write_themes only. Used by Shopify CLI / theme tooling, generated by the Theme Access app.
(no prefix)Storefront API token — typically a 32-char hex string. Sent in X-Shopify-Storefront-Access-Token header. Different surface from the Admin API.

Other terms

Client IDPublic app identifier (hex string).
X-Shopify-Access-TokenHTTP header for all Admin API requests.
grant_type=client_credentialsOAuth grant type — literal string, don't replace it.