Admin API
The Admin API is a private API that allows you to manage your Shopify store's data, such as orders, customers, products, and inventory. It is designed to be used in server-side applications only, as it requires credentials that should never be exposed to the client.
Authentication
The module supports multiple authentication methods for the Admin API:
The recommended method for apps created via the Shopify Dev Dashboard. The module automatically obtains and refreshes access tokens using your client ID and secret.
export default defineNuxtConfig({
shopify: {
name: "quickstart-abcd1234",
clients: {
admin: {
apiVersion: "2026-01",
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
},
},
},
})
Access tokens are valid for 24 hours and are automatically refreshed before expiry.
For legacy custom apps created in the Shopify Admin that provide a permanent access token.
export default defineNuxtConfig({
shopify: {
name: "quickstart-abcd1234",
clients: {
admin: {
apiVersion: "2026-01",
accessToken: "YOUR_ACCESS_TOKEN",
},
},
},
})
For apps that have pre-obtained an offline access token with a refresh token.
export default defineNuxtConfig({
shopify: {
name: "quickstart-abcd1234",
clients: {
admin: {
apiVersion: "2026-01",
clientId: "YOUR_CLIENT_ID",
clientSecret: "YOUR_CLIENT_SECRET",
accessToken: "YOUR_ACCESS_TOKEN",
refreshToken: "YOUR_REFRESH_TOKEN",
},
},
},
})
Token Storage
When using client credentials or refresh tokens, the module stores obtained tokens using Unstorage. By default, tokens are stored in memory. You can configure a persistent storage driver:
export default defineNuxtConfig({
shopify: {
clients: {
admin: {
// Use a custom storage mount name
tokenStorage: "my-token-store",
// Or configure a driver directly
tokenStorage: {
driver: "redis",
host: "localhost",
port: 6379,
},
},
},
},
nitro: {
storage: {
"my-token-store": {
driver: "redis",
host: "localhost",
port: 6379,
},
},
},
})
Usage
Once configured, you can use the Admin API in your Nuxt application via the useAdmin composable.
This composable can only be used on the server-side (in server routes, middleware, or server-only composables).
Server-side
useAdmin
export default defineEventHandler(async (event) => {
const admin = useAdmin()
return admin.request(`#graphql
query GetOrders($first: Int!) {
orders(first: $first) {
edges {
node {
id
name
totalPrice
createdAt
}
}
}
}
`, {
variables: {
first: 10,
},
})
})
You can also wrap the useAdmin composable in another composable to build an abstracted data fetching method:
export const useOrder = async (id: string) => {
const admin = useAdmin()
return admin.request(`#graphql
query GetOrder($id: ID!) {
order(id: $id) {
id
name
totalPrice
lineItems(first: 10) {
edges {
node {
title
quantity
}
}
}
}
}
`, {
variables: {
id,
},
})
}
Using validation
Using Nitro's built-in input validation, you can match the variables of your GraphQL queries before sending them to the API.
For this example we'll use the Zod library, but you can use any validation library you like.
First, install the validation library:
npm install zod
Then, import it and create a schema:
import { z } from "zod"
const schema = z.object({
first: z.preprocess(v => Number(v), z.number().min(1).max(250)),
status: z.enum(["OPEN", "CLOSED", "CANCELLED"]).optional(),
})
Next, we can use Nitro's built-in getValidatedQuery utility to validate the query variables:
import { z } from "zod"
const schema = z.object({
first: z.preprocess(v => Number(v), z.number().min(1).max(250)),
status: z.enum(["OPEN", "CLOSED", "CANCELLED"]).optional(),
})
export default defineEventHandler(async (event) => {
const admin = useAdmin()
const variables = await getValidatedQuery(event, schema.parse)
const query = `#graphql
query FetchOrders($first: Int!, $status: OrderStatus) {
orders(first: $first, query: $status) {
edges {
node {
id
name
totalPrice
financialStatus
fulfillmentStatus
}
}
}
}
`
return admin.request(query, { variables })
})
Now we can call the API at /api/orders with the following variables:
const { data: orders } = await useFetch("/api/orders", {
query: {
first: 50,
status: "OPEN",
},
})
Now the request will fail before reaching Shopify if the variables don't match the schema.