Continue rollout discovery separately from treatment changes
Description
Continue the outer rollout connection using `rollouts.pageInfo.endCursor` as `rolloutsAfter`.
Don't pass a treatment's changes cursor here: each connection has its own pagination state.
Newly discovered treatments start without a changes cursor. Continue any unfinished earlier treatments
separately through their Node IDs, using their own saved cursors and unchanged query filters and directions.
Query
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { rollouts(first: 1, after: $rolloutsAfter) { nodes { id treatments { id changes(first: $first, query: $changeQuery, reverse: $reverse) { nodes { id __typename } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } } } pageInfo { hasNextPage endCursor } } } } } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true,
"rolloutsAfter": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI0LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNCJ9"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/1789387200000025",
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/1789387200000033",
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/9bf114894e87e680afb332bfbf80c384d919eaedb2f692066805918828af3b78",
"__typename": "RolloutDiscountActivateChange"
}
],
"pageInfo": {
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": "WzEsImY0M2FhOTA5MTZlMjcwZTc0MGFjZmZmM2JlNjQ3ZTgzMGM1NzIzYTU2MGJkNmY2YTUxMTBkODZhM2M3NzBmNzIiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsIjliZjExNDg5NGU4N2U2ODBhZmIzMzJiZmJmODBjMzg0ZDkxOWVhZWRiMmY2OTIwNjY4MDU5MTg4MjhhZjNiNzgiXQ",
"endCursor": "WzEsImY0M2FhOTA5MTZlMjcwZTc0MGFjZmZmM2JlNjQ3ZTgzMGM1NzIzYTU2MGJkNmY2YTUxMTBkODZhM2M3NzBmNzIiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsIjliZjExNDg5NGU4N2U2ODBhZmIzMzJiZmJmODBjMzg0ZDkxOWVhZWRiMmY2OTIwNjY4MDU5MTg4MjhhZjNiNzgiXQ"
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDI1LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDAyNSJ9"
}
}
}
}
}
Discover independent treatment change cursors
Description
Start at a discount to discover its rollouts and the first page of each treatment's changes.
Your app needs `read_discounts` and `read_rollouts`. This public graph is unavailable before API version 2026-10.
This example requests one change per treatment so that the independent page boundaries are visible.
Store each treatment ID with its own changes end cursor, query filter, and reverse value.
The empty baseline has no changes and `hasNextPage: false`; skip it rather than borrowing another treatment's cursor.
For each treatment with `hasNextPage: true`, use `node(id: treatmentId)` and select `RolloutTreatment.changes`
with that treatment's cursor as `after`, keeping `changeQuery` and `reverse` unchanged. Repeat until its own `hasNextPage` is false.
Treatment order isn't an identifier. Key continuation state by treatment ID, not by its position in the list.
The outer `rollouts.pageInfo` is independent: pass that cursor only to `Discount.rollouts(after:)` to discover more rollouts.
Query
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { rollouts(first: 1, after: $rolloutsAfter) { nodes { id treatments { id changes(first: $first, query: $changeQuery, reverse: $reverse) { nodes { id __typename } pageInfo { hasNextPage hasPreviousPage startCursor endCursor } } } } pageInfo { hasNextPage endCursor } } } } } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscoverTreatmentChanges($id: ID!, $rolloutsAfter: String, $first: Int!, $changeQuery: String!, $reverse: Boolean!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
rollouts(first: 1, after: $rolloutsAfter) {
nodes {
id
treatments {
id
changes(first: $first, query: $changeQuery, reverse: $reverse) {
nodes {
id
__typename
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
}
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"first": 1,
"changeQuery": "type:RolloutDiscountActivateChange",
"reverse": true
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/1789387200000075",
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/1789387200000100",
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/c40b9313555f1160d5dcba2e5ae35aa537e251cc0d0b78c0cd06933c8d4d38c7",
"__typename": "RolloutDiscountActivateChange"
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false,
"startCursor": "WzEsIjM5YTgyOGM4N2Q4YzBhYWE3NWFiMDA2ZGQ5MGNjYTUzMGYxODc3ODQ5MGYyYTg0YjUwMmEwMmIxMDJlZTkzNzgiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsImM0MGI5MzEzNTU1ZjExNjBkNWRjYmEyZTVhZTM1YWE1MzdlMjUxY2MwZDBiNzhjMGNkMDY5MzNjOGQ0ZDM4YzciXQ",
"endCursor": "WzEsIjM5YTgyOGM4N2Q4YzBhYWE3NWFiMDA2ZGQ5MGNjYTUzMGYxODc3ODQ5MGYyYTg0YjUwMmEwMmIxMDJlZTkzNzgiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsImM0MGI5MzEzNTU1ZjExNjBkNWRjYmEyZTVhZTM1YWE1MzdlMjUxY2MwZDBiNzhjMGNkMDY5MzNjOGQ0ZDM4YzciXQ"
}
}
},
{
"id": "gid://shopify/RolloutTreatment/1789387200000102",
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/6c3df9267ce792cf56ae487ad320d47a4f5b1ae5e4964cb79cecb28b0fb9d0b2",
"__typename": "RolloutDiscountActivateChange"
}
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false,
"startCursor": "WzEsIjFjMjNjNDkzNTZhOTRlNzBiZDg4NjQ4ZDVkMjk3YjRhOTRlYmZkNGVlZmIxMjkwMWI3YTM5YmQ4MzhhZmE3ZDEiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsIjZjM2RmOTI2N2NlNzkyY2Y1NmFlNDg3YWQzMjBkNDdhNGY1YjFhZTVlNDk2NGNiNzljZWNiMjhiMGZiOWQwYjIiXQ",
"endCursor": "WzEsIjFjMjNjNDkzNTZhOTRlNzBiZDg4NjQ4ZDVkMjk3YjRhOTRlYmZkNGVlZmIxMjkwMWI3YTM5YmQ4MzhhZmE3ZDEiLCIyMDI2LTExLTI4VDAwOjAwOjAwLjAwMDAwMDAwMFoiLDAsIjZjM2RmOTI2N2NlNzkyY2Y1NmFlNDg3YWQzMjBkNDdhNGY1YjFhZTVlNDk2NGNiNzljZWNiMjhiMGZiOWQwYjIiXQ"
}
}
},
{
"id": "gid://shopify/RolloutTreatment/1789387200000103",
"changes": {
"nodes": [],
"pageInfo": {
"hasNextPage": false,
"hasPreviousPage": false,
"startCursor": null,
"endCursor": null
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": true,
"endCursor": "eyJsYXN0X2lkIjoxNzg5Mzg3MjAwMDAwMDc1LCJsYXN0X3ZhbHVlIjoiMTc4OTM4NzIwMDAwMDA3NSJ9"
}
}
}
}
}
Filter rollout changes by operation type
Description
Use `type:` with an exact, case-sensitive concrete typename to return only discount expiration changes.
An inline fragment selects fields; it doesn't filter the changes connection.
This query starts with the sale discount but returns the sibling clearance discount's expiration.
Your app needs both `read_discounts` and `read_rollouts` access scopes.
Query
query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { title rollouts(first: 10) { nodes { id name status treatments { id split changes(first: 10, query: $changeQuery) { nodes { id __typename ... on RolloutDiscountChange { discount { id discount { ... on DiscountAutomaticBasic { title } ... on DiscountCodeBasic { title } } } } } pageInfo { hasNextPage } } } } pageInfo { hasNextPage } } } } } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query FilterDiscountRolloutChanges($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "type:RolloutDiscountExpireChange"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"title": "Black Friday discount",
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/532060658",
"name": "Black Friday offer changeover",
"status": "ACTIVE",
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/522314081",
"split": 50,
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountExpireChange/c2f0dd9c068a6dba4866e563632bc485070d427fd72568094e761b30fa639467",
"__typename": "RolloutDiscountExpireChange",
"discount": {
"id": "gid://shopify/DiscountCodeNode/672017907",
"discount": {
"title": "Clearance discount"
}
}
}
],
"pageInfo": {
"hasNextPage": false
}
}
},
{
"id": "gid://shopify/RolloutTreatment/755492298",
"split": 50,
"changes": {
"nodes": [],
"pageInfo": {
"hasNextPage": false
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": false
}
}
}
}
}
Identify a rollout discount to advertise
Description
`trafficAllocation: 100` configures full traffic; `effectiveTrafficAllocation: 100` confirms competing rollouts do not reduce it.
With an `ACTIVE` rollout, a `split: 100` treatment, and a matching `RolloutDiscountActivateChange`, the client can advertise the discount to its full eligible audience.
The discount shows `EXPIRED` because its end date passed. The treatment still activates it for its buyers.
Check every changes page for the activation. Effective allocation describes new buyer assignments, not exposure or guaranteed redemption.
Normal discount conditions still apply. Recheck the rollout before advertising. Your app needs both `read_discounts` and `read_rollouts` access scopes.
Query
query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { title status startsAt endsAt rollouts(first: 10) { ...DiscountAdvertisingRollouts } } ... on DiscountCodeBasic { title status startsAt endsAt rollouts(first: 10) { ...DiscountAdvertisingRollouts } } } } } fragment DiscountAdvertisingRollouts on RolloutConnection { nodes { id name status trafficAllocation effectiveTrafficAllocation treatments { id split changes(first: 10, query: $changeQuery) { nodes { id __typename ... on RolloutDiscountChange { discount { id discount { ... on DiscountAutomaticBasic { title } ... on DiscountCodeBasic { title } } } } } pageInfo { hasNextPage } } } } pageInfo { hasNextPage } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'\''gid://shopify/DiscountNode/299501151'\''"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscountRolloutAdvertising($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountAdvertisingRollouts
}
}
}
}
}
fragment DiscountAdvertisingRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
effectiveTrafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"title": "Black Friday discount",
"status": "EXPIRED",
"startsAt": "2026-01-01T00:00:00Z",
"endsAt": "2026-01-02T00:00:00Z",
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/532060658",
"name": "Black Friday offer changeover",
"status": "ACTIVE",
"trafficAllocation": 100,
"effectiveTrafficAllocation": 100,
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/522314081",
"split": 100,
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/19562284969ac8973c308a5159bf122bb6cc5966282d620bfbf81e7029f1e686",
"__typename": "RolloutDiscountActivateChange",
"discount": {
"id": "gid://shopify/DiscountAutomaticNode/299501151",
"discount": {
"title": "Black Friday discount"
}
}
}
],
"pageInfo": {
"hasNextPage": false
}
}
},
{
"id": "gid://shopify/RolloutTreatment/755492298",
"split": 0,
"changes": {
"nodes": [],
"pageInfo": {
"hasNextPage": false
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": false
}
}
}
}
}
Inspect a rollout that replaces one discount with another
Description
Inspect the treatments of a rollout that activates a sale discount and expires a clearance discount.
The treatment with no changes keeps the discounts' native behavior.
Use `__typename` to distinguish `RolloutDiscountActivateChange` from `RolloutDiscountExpireChange`.
Select their shared discount fields through the `RolloutDiscountChange` interface.
The changes connection includes sibling discounts, not just the discount used to find the rollout.
These operations affect the buyers served by the treatment; they don't mean the discount's native dates changed.
Your app needs both `read_discounts` and `read_rollouts` access scopes.
Query
query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscountOfferChangeover($id: ID!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { title rollouts(first: 10) { nodes { id name status treatments { id split changes(first: 10) { nodes { id __typename ... on RolloutDiscountChange { discount { id discount { ... on DiscountAutomaticBasic { title } ... on DiscountCodeBasic { title } } } } } pageInfo { hasNextPage } } } } pageInfo { hasNextPage } } } } } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscountOfferChangeover($id: ID!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
nodes {
id
name
status
treatments {
id
split
changes(first: 10) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"title": "Black Friday discount",
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/532060658",
"name": "Black Friday offer changeover",
"status": "ACTIVE",
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/522314081",
"split": 50,
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/19562284969ac8973c308a5159bf122bb6cc5966282d620bfbf81e7029f1e686",
"__typename": "RolloutDiscountActivateChange",
"discount": {
"id": "gid://shopify/DiscountAutomaticNode/299501151",
"discount": {
"title": "Black Friday discount"
}
}
},
{
"id": "gid://shopify/RolloutDiscountExpireChange/c2f0dd9c068a6dba4866e563632bc485070d427fd72568094e761b30fa639467",
"__typename": "RolloutDiscountExpireChange",
"discount": {
"id": "gid://shopify/DiscountCodeNode/672017907",
"discount": {
"title": "Clearance discount"
}
}
}
],
"pageInfo": {
"hasNextPage": false
}
}
},
{
"id": "gid://shopify/RolloutTreatment/755492298",
"split": 50,
"changes": {
"nodes": [],
"pageInfo": {
"hasNextPage": false
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": false
}
}
}
}
}
Querying a non-existent discount returns null
Description
This example shows the response that's returned when you query a discount that doesn't exist.
Query
query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query { discountNode(id: \"gid://shopify/DiscountNode/999999999\") { id } }"
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}`,
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}
QUERY
response = client.query(query: query)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: `query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}`,
});
Shopify CLI
shopify app execute \
--query \
'query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query {
discountNode(id: "gid://shopify/DiscountNode/999999999") {
id
}
}
`,
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": null
}
Read a discount's rollout changes and configured traffic
Description
Read changes for a basic automatic or code discount together with rollout allocation and treatment splits.
Use `discount_id:` with a numeric discount ID or a quoted GID, passing the complete expression in `changeQuery`.
In this example, the treatment that activates the natively expired discount has 50% of a 40% rollout allocation: 20% configured traffic.
Buyers outside that treatment receive no activation from this rollout.
Competing rollouts and discount eligibility can further limit who can use the discount.
Do not advertise this discount as available to all buyers.
Check the rollout's status before treating its configuration as active.
These percentages precede competing-rollout effects; they aren't measured exposure or proof that a buyer can redeem the discount.
Activation and expiration affect buyers served by a treatment; they don't change the discount's native dates.
An empty filtered connection for a treatment means no matching readable changes were returned there.
It does not prove that no change exists or that the discount is unavailable.
Your app needs both `read_discounts` and `read_rollouts` access scopes.
Query
query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) { discountNode(id: $id) { discount { ... on DiscountAutomaticBasic { title status startsAt endsAt rollouts(first: 10) { ...DiscountTrafficRollouts } } ... on DiscountCodeBasic { title status startsAt endsAt rollouts(first: 10) { ...DiscountTrafficRollouts } } } } } fragment DiscountTrafficRollouts on RolloutConnection { nodes { id name status trafficAllocation treatments { id split changes(first: 10, query: $changeQuery) { nodes { id __typename ... on RolloutDiscountChange { discount { id discount { ... on DiscountAutomaticBasic { title } ... on DiscountCodeBasic { title } } } } } pageInfo { hasNextPage } } } } pageInfo { hasNextPage } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'\''gid://shopify/DiscountNode/299501151'\''"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscountRolloutTraffic($id: ID!, $changeQuery: String!) {
discountNode(id: $id) {
discount {
... on DiscountAutomaticBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
... on DiscountCodeBasic {
title
status
startsAt
endsAt
rollouts(first: 10) {
...DiscountTrafficRollouts
}
}
}
}
}
fragment DiscountTrafficRollouts on RolloutConnection {
nodes {
id
name
status
trafficAllocation
treatments {
id
split
changes(first: 10, query: $changeQuery) {
nodes {
id
__typename
... on RolloutDiscountChange {
discount {
id
discount {
... on DiscountAutomaticBasic {
title
}
... on DiscountCodeBasic {
title
}
}
}
}
}
pageInfo {
hasNextPage
}
}
}
}
pageInfo {
hasNextPage
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151",
"changeQuery": "discount_id:'gid://shopify/DiscountNode/299501151'"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"discount": {
"title": "Black Friday discount",
"status": "EXPIRED",
"startsAt": "2026-01-01T00:00:00Z",
"endsAt": "2026-01-02T00:00:00Z",
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/532060658",
"name": "Black Friday offer changeover",
"status": "ACTIVE",
"trafficAllocation": 40,
"treatments": [
{
"id": "gid://shopify/RolloutTreatment/522314081",
"split": 50,
"changes": {
"nodes": [
{
"id": "gid://shopify/RolloutDiscountActivateChange/19562284969ac8973c308a5159bf122bb6cc5966282d620bfbf81e7029f1e686",
"__typename": "RolloutDiscountActivateChange",
"discount": {
"id": "gid://shopify/DiscountAutomaticNode/299501151",
"discount": {
"title": "Black Friday discount"
}
}
}
],
"pageInfo": {
"hasNextPage": false
}
}
},
{
"id": "gid://shopify/RolloutTreatment/755492298",
"split": 50,
"changes": {
"nodes": [],
"pageInfo": {
"hasNextPage": false
}
}
}
]
}
],
"pageInfo": {
"hasNextPage": false
}
}
}
}
}
Read the rollouts associated with a discount
Description
Read the names, statuses, and schedules of rollouts that include a discount.
The query includes fragments for all eight discount types; keep the fragments your app needs.
Your app needs both `read_discounts` and `read_rollouts` access scopes.
A rollout's schedule is separate from the discount's own start and end dates.
Membership alone doesn't establish whether a buyer can use the discount.
If `hasNextPage` is `true`, [paginate the rollouts connection](https://shopify.dev/docs/api/usage/pagination-graphql).
Query
query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
Variables
{
"id": "gid://shopify/DiscountNode/299501151"
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query DiscountRollouts($id: ID!) { discountNode(id: $id) { id discount { __typename ... on DiscountAutomaticApp { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountAutomaticBasic { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountAutomaticBxgy { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountAutomaticFreeShipping { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountCodeApp { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountCodeBasic { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountCodeBxgy { title rollouts(first: 10) { ...RolloutMemberships } } ... on DiscountCodeFreeShipping { title rollouts(first: 10) { ...RolloutMemberships } } } } } fragment RolloutMemberships on RolloutConnection { nodes { id name status schedule { activateAt concludeAt } } pageInfo { hasNextPage endCursor } }",
"variables": {
"id": "gid://shopify/DiscountNode/299501151"
}
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}`,
{
variables: {
"id": "gid://shopify/DiscountNode/299501151"
},
},
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
QUERY
variables = {
"id": "gid://shopify/DiscountNode/299501151"
}
response = client.query(query: query, variables: variables)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: {
"query": `query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}`,
"variables": {
"id": "gid://shopify/DiscountNode/299501151"
},
},
});
Shopify CLI
shopify app execute \
--query \
'query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}' \
--variables \
'{
"id": "gid://shopify/DiscountNode/299501151"
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query DiscountRollouts($id: ID!) {
discountNode(id: $id) {
id
discount {
__typename
... on DiscountAutomaticApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountAutomaticFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeApp {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBasic {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeBxgy {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
... on DiscountCodeFreeShipping {
title
rollouts(first: 10) {
...RolloutMemberships
}
}
}
}
}
fragment RolloutMemberships on RolloutConnection {
nodes {
id
name
status
schedule {
activateAt
concludeAt
}
}
pageInfo {
hasNextPage
endCursor
}
}
`,
variables: {
"id": "gid://shopify/DiscountNode/299501151"
},
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"id": "gid://shopify/DiscountAutomaticNode/299501151",
"discount": {
"__typename": "DiscountAutomaticBasic",
"title": "My automatic discount",
"rollouts": {
"nodes": [
{
"id": "gid://shopify/Rollout/885624881",
"name": "Black Friday sale",
"status": "SCHEDULED",
"schedule": {
"activateAt": "2026-11-27T00:00:00Z",
"concludeAt": "2026-12-01T00:00:00Z"
}
}
],
"pageInfo": {
"hasNextPage": false,
"endCursor": "eyJsYXN0X2lkIjo4ODU2MjQ4ODEsImxhc3RfdmFsdWUiOiI4ODU2MjQ4ODEifQ=="
}
}
}
}
}
Retrieve a discount by its ID
Description
Retrieve a
[discount](https://help.shopify.com/manual/discounts)
that's applied on a cart and at checkout when an order meets specific criteria.
Query
query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}
cURL
curl -X POST \
https://your-development-store.myshopify.com/admin/api/2026-10/graphql.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}' \
-d '{
"query": "query { discountNode(id: \"gid://shopify/DiscountAutomaticNode/299501151\") { id discount { ... on DiscountCodeBasic { title summary status codes(first: 1) { nodes { code } } } ... on DiscountAutomaticBasic { title summary status } ... on DiscountCodeBxgy { title summary status codes(first: 1) { nodes { code } } } ... on DiscountAutomaticBxgy { title summary status } ... on DiscountCodeFreeShipping { title summary status codes(first: 1) { nodes { code } } } ... on DiscountCodeApp { title status appDiscountType { title } codes(first: 1) { nodes { code } } } ... on DiscountAutomaticApp { title status appDiscountType { title } } } } }"
}'
React Router
import { authenticate } from "../shopify.server";
export const loader = async ({request}) => {
const { admin } = await authenticate.admin(request);
const response = await admin.graphql(
`#graphql
query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}`,
);
const json = await response.json();
return json.data;
}
Ruby
session = ShopifyAPI::Auth::Session.new(
shop: "your-development-store.myshopify.com",
access_token: access_token
)
client = ShopifyAPI::Clients::Graphql::Admin.new(
session: session
)
query = <<~QUERY
query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}
QUERY
response = client.query(query: query)
Node.js
const client = new shopify.clients.Graphql({session});
const data = await client.query({
data: `query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}`,
});
Shopify CLI
shopify app execute \
--query \
'query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}'
Direct API Access
const response = await fetch('shopify:admin/api/2026-10/graphql.json', {
method: 'POST',
body: JSON.stringify({
query: `
query {
discountNode(id: "gid://shopify/DiscountAutomaticNode/299501151") {
id
discount {
... on DiscountCodeBasic {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBasic {
title
summary
status
}
... on DiscountCodeBxgy {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticBxgy {
title
summary
status
}
... on DiscountCodeFreeShipping {
title
summary
status
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountCodeApp {
title
status
appDiscountType {
title
}
codes(first: 1) {
nodes {
code
}
}
}
... on DiscountAutomaticApp {
title
status
appDiscountType {
title
}
}
}
}
}
`,
}),
});
const { data } = await response.json();
console.log(data);
Response
{
"discountNode": {
"id": "gid://shopify/DiscountAutomaticNode/299501151",
"discount": {
"title": "My automatic discount",
"summary": "$100.00 off entire order • Minimum quantity of 1",
"status": "SCHEDULED"
}
}
}