Varsler om fjernede rabattkoder
Sett opp en Shopify Flow-arbeidsflyt som sender en rapport til Slack når en rabattkode fjernes, med bruksantall og kampanjedetaljer.
Når skal denne arbeidsflyten brukes?
Bruk denne arbeidsflyten når en rabattkode fjernes og du trenger en umiddelbar oversikt over hva som ble berørt. Den hjelper deg med å registrere den fjernede koden, antall ganger den har blitt brukt, kampanjedetaljene og en oppsummering som du kan sende til økonomiavdelingen eller driftsavdelingen i Slack.
Dette er spesielt nyttig ved lekkede influencer-koder, utilsiktet offentliggjøring av kuponger eller i alle tilfeller der du trenger en dokumentert konsekvensrapport etter at en kode er fjernet.
Hva du skal bygge
- En Slack-arbeidsflyt som mottar en
text-variabel fra en webhook og legger ut den samme teksten i en Slack-kanal. - En Shopify Flow-arbeidsflyt utløst av Rabattkode fjernet.
- Et Hent rabatt-datatrinn som slår opp rabatten ved hjelp av ID-en fra utløseren.
- Et Kjør kode-trinn som formaterer en fjerningsrapport.
- Et HTTP Request-trinn som sender rapporten til Slack.
Før du begynner
- Sørg for at appen er installert og synlig i Shopify-administrasjonspanelet under Apps > Workflow Trigger Extensions.
- Sørg for at du har tilgang til Shopify Flow.
- Opprett eller velg en Slack-kanal der varslene skal vises.
- Opprett en Slack-arbeidsflyt som starter med en webhook og godtar et
text-felt.
Videoveiledning
Du kan også se hele implementeringsvideoen.
Opprett først Slack-arbeidsflyten
I Slack oppretter du en arbeidsflyt med utløseren Starter med en webhook. Legg til en tekstvariabel med navnet text, og legg deretter til et meldingstrinn som sender en melding til den valgte kanalen ved hjelp av den samme text-variabelen.

Gi tilgang med rabatt i Workflow Trigger Extensions
Før utløseren vises i Shopify Flow, må du aktivere tilgang til rabatter i appen.
I Shopify-administrasjonspanelet går du til Apper > Workflow Trigger Extensions.
Se etter sjekklisten for oppsett på dashbordet.
Slå på Gi tilgang til rabatter. Dette aktiverer utløsere knyttet til rabatter, for eksempel Rabatt opprettet, Rabatt oppdatert, Rabatt slettet, Rabattkode lagt til, Rabattkode fjernet og Rabatt utløpt.

Opprett en Shopify Flow
Åpne Shopify Flow og opprett en ny arbeidsflyt.
Søk etter utløsere knyttet til rabatter, og velg Rabattkode fjernet fra Workflow Trigger Extensions.

Legg til Shopify-handlingen Hent rabattdata.
I Velg et søk for å filtrere data velger du Avansert. I Rediger søk bruker du rabatt-ID-en fra utløseren og fjerner Shopify-GID-prefikset:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Legg til et Kjør kode-trinn etter Hent rabattdata.
Bruk følgende GraphQL-spørring i Velg inndata fra de foregående trinnene:
query {
redeemCode {
code
usageCount
bulkRemoval
}
getDiscountData {
discount {
... on DiscountCodeBasic {
title
startsAt
endsAt
asyncUsageCount
codes {
code
asyncUsageCount
}
customerGets {
value {
... on DiscountAmount {
amount { amount currencyCode }
}
... on DiscountPercentage {
percentage
}
}
}
}
}
}
}Definer utgangene slik:
"Output of discount code removal report"
type Output {
"Discount code that was removed"
code: String!
"Discount campaign title"
title: String!
"Campaign start date"
startsAt: String!
"Campaign end date"
endsAt: String!
"Number of times it was redeemed"
usageCount: Int!
"Total discount impact as a formatted string"
totalImpact: String!
"When it was removed"
removedAt: String!
"Full summary for alerts"
summary: String!
}Lim deretter inn denne koden i feltet Skriv kode:
export default function main(input) {
// ── Trigger: removed code ──
const removedCode = input?.redeemCode?.code ?? "Unknown";
const usageCount = input?.redeemCode?.usageCount ?? null; // null = bulk removal or unknown
const bulkRemoval = input?.redeemCode?.bulkRemoval ?? false;
const currency = input?.shop?.currencyCode ?? "";
const shopName = input?.shop?.name ?? "(not bound)";
const removedAt = new Date().toISOString();
// ── Find matching discount ──
const dataItems = input?.getDiscountData ?? [];
let matchedDiscount = null;
for (const item of dataItems) {
const d = item?.discount?.DiscountCodeBasic ?? item?.discount;
if (!d) continue;
const codesArray = Array.isArray(d.codes)
? d.codes.map(c => (typeof c === "string" ? c : c?.code ?? ""))
: [];
if (codesArray.includes(removedCode)) {
matchedDiscount = d;
break;
}
}
// fallback to first entry if removed code already gone from list
if (!matchedDiscount && dataItems.length > 0) {
matchedDiscount =
dataItems[0]?.discount?.DiscountCodeBasic ?? dataItems[0]?.discount ?? null;
}
const title = matchedDiscount?.title ?? "Untitled";
const startsAt = matchedDiscount?.startsAt ?? "N/A";
const endsAt = matchedDiscount?.endsAt ?? "None (no expiry)";
const totalUsageCount = matchedDiscount?.asyncUsageCount ?? null;
// ── Discount value ──
const valueWrapper = matchedDiscount?.customerGets?.value ?? {};
const pctObj = valueWrapper?.DiscountPercentage ?? null;
const amtObj = valueWrapper?.DiscountAmount ?? valueWrapper?.amount ?? null;
let discountLabel = "Unknown";
if (pctObj?.percentage != null) {
discountLabel = `${(pctObj.percentage * 100).toFixed(0)}% off`;
} else if (amtObj?.amount != null) {
const cur = amtObj.currencyCode || currency;
discountLabel = `${cur} ${parseFloat(amtObj.amount).toFixed(2)} off`;
}
// ── This code's impact ──
let thisCodeImpact;
if (bulkRemoval) {
thisCodeImpact = `Not available - removed as part of bulk deletion`;
} else if (usageCount === null) {
thisCodeImpact = `Could not be determined`;
} else if (pctObj?.percentage != null) {
thisCodeImpact = `${discountLabel} × ${usageCount} use(s)`;
} else if (amtObj?.amount != null) {
const perUse = parseFloat(amtObj.amount);
const cur = amtObj.currencyCode || currency;
thisCodeImpact = `${cur} ${(perUse * usageCount).toFixed(2)} (${cur} ${perUse.toFixed(2)} × ${usageCount} uses)`;
} else {
thisCodeImpact = "Unknown";
}
// ── Campaign-wide impact using asyncUsageCount on the discount ──
let campaignImpact;
if (totalUsageCount === null) {
campaignImpact = "Not available";
} else if (pctObj?.percentage != null) {
campaignImpact = `${discountLabel} × ${totalUsageCount} total use(s) across all codes`;
} else if (amtObj?.amount != null) {
const perUse = parseFloat(amtObj.amount);
const cur = amtObj.currencyCode || currency;
campaignImpact = `${cur} ${(perUse * totalUsageCount).toFixed(2)} total (${cur} ${perUse.toFixed(2)} × ${totalUsageCount} uses)`;
} else {
campaignImpact = "Unknown";
}
// ── Per-code breakdown ──
const codesNodes = Array.isArray(matchedDiscount?.codes)
? matchedDiscount.codes
: [];
const allCodes = codesNodes
.map(c => (typeof c === "string" ? c : c?.code ?? ""))
.filter(Boolean);
const codesRoster = codesNodes.length
? codesNodes.map(c => {
const code = typeof c === "string" ? c : c?.code ?? "";
const used = c?.asyncUsageCount ?? "?";
const flag = code === removedCode ? " ← REMOVED" : "";
return `${code} (used ${used}×)${flag}`;
}).join("\n ")
: "N/A";
const usageCountLabel = bulkRemoval
? "N/A (bulk removal)"
: usageCount !== null
? String(usageCount)
: "Unknown";
const summary =
`DISCOUNT CODE REMOVED\n` +
`─────────────────────\n` +
`Store: ${shopName}\n` +
`Code removed: ${removedCode}\n` +
`Bulk removal: ${bulkRemoval ? "Yes" : "No"}\n` +
`Campaign: ${title}\n` +
`Discount: ${discountLabel}\n` +
`Valid from: ${startsAt}\n` +
`Valid until: ${endsAt}\n` +
`\n` +
`THIS CODE\n` +
` Times used: ${usageCountLabel}\n` +
` Impact: ${thisCodeImpact}\n` +
`\n` +
`CAMPAIGN TOTAL\n` +
` Total uses: ${totalUsageCount ?? "Unknown"}\n` +
` Total impact: ${campaignImpact}\n` +
`\n` +
`CODE BREAKDOWN\n` +
` ${codesRoster}\n` +
`\n` +
`Removed at: ${removedAt}`;
const safeSummary = summary
.replace(/\\/g, "\\\\") // escape backslashes first
.replace(/"/g, '\\"') // escape quotes
.replace(/\n/g, "\\n") // escape newlines
.replace(/\r/g, "\\r");
return {
code: removedCode,
bulkRemoval,
title,
discountLabel,
startsAt,
endsAt,
usageCount: usageCount ?? 0,
usageCountLabel,
thisCodeImpact,
totalUsageCount: totalUsageCount ?? 0,
campaignImpact,
allCodes,
codesRoster,
removedAt,
summary: safeSummary,
};
}
Legg til handlingen HTTP Request. I feltet Variabler** eller Body Override (JSON)** sender du sammendraget som returneres av kodetrinnet Kjør:
{
"body": {
"text": "{{runCode.summary}}"
}
}Dette sender det genererte sammendraget til Slack-webhook-arbeidsflyten ved hjelp av variabelen text.

Lagre arbeidsflyten når alle trinnene er på plass.
For å teste dette, slett en rabattkode fra rabattkampanjen din og sjekk at Slack-kanalen mottar oppsummeringsmeldingen.

Hva Slack-varselet inneholder
- Den fjernede rabattkoden
- Uansett om det dreide seg om en storstilt fjerning
- Kampanjetittelen
- Rabattbeløpet
- Start- og sluttdatoer
- Tider brukt på den fjernede koden
- Anslått innvirkning av den fjernede koden
- Bruk og virkning på tvers av kampanjene
- En oversikt kode for kode, der dette er tilgjengelig
- Tidspunktet da slettingen ble gjennomført
Feilsøking
Gå tilbake til Apps > Workflow Trigger Extensions og sjekk at Grant Discount Access er aktivert. Rabattutløserne vises først etter at tilgang er gitt.
Kontroller den avanserte søkeformelen nøye under Rediger søkeformel. ID-en skal renses nøyaktig slik det er vist:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"Sørg for at Slack-arbeidsflyten starter med en webhook, at webhook-URL-en er den samme som brukes i HTTP-forespørselen din, og at forespørselens innhold inneholder feltet text.
Noen slettinger kan være en del av en samlet handling, eller det kan hende at de ikke gir fullstendige bruksopplysninger. I slike tilfeller vil oversikten likevel inneholde den beste tilgjengelige informasjonen, og manglende verdier vil bli tydelig merket.
Gode praksiseksempler
- Send disse varslene til en egen kanal for økonomi eller drift i stedet for til en generell supportkanal.
- Gi arbeidsflyten et konkret navn, for eksempel Rabattkode fjernet, slik at den er lett å gjenkjenne i Shopify Flow og Slack.
- Test først med en rabattkode som ikke er ment for produksjonsbruk for å bekrefte meldingsformatet og hvordan webhooken fungerer.
