Varningar om borttagna rabattkoder
Få en Slack-avisering när en rabattkod tas bort, med antal användningar och kampanjdetaljer, via ett Shopify Flow-arbetsflöde och en Slack-webhook.
När ska man använda detta arbetsflöde?
Använd det här arbetsflödet när en rabattkod tas bort och du behöver omedelbart få en översikt över vad som påverkats. Det hjälper dig att registrera den borttagna koden, antalet gånger den använts, kampanjuppgifterna samt en sammanfattning som du kan skicka till ekonomi- eller driftsavdelningen via Slack.
Detta är särskilt användbart vid läckta influencer-koder, oavsiktlig publicering av kuponger eller i alla fall där du behöver en dokumenterad effektanalys efter att en kod har tagits bort.
Vad du kommer att bygga
- Ett Slack-arbetsflöde som tar emot en
text-variabel från en webhook och publicerar samma text i en Slack-kanal. - Ett Shopify Flow-arbetsflöde som utlöses av att en rabattkod har tagits bort.
- Ett datasteg av typen ”Hämta rabatt” som hämtar rabatten med hjälp av ID:t från utlösaren.
- Ett kodsteg av typen ”Kör” som formaterar en borttagningsrapport.
- Ett ”HTTP Request”-steg som skickar rapporten till Slack.
Innan du börjar
- Se till att appen är installerad och synlig i Shopify-admin under Appar > Workflow Trigger Extensions.
- Se till att du har tillgång till Shopify Flow.
- Skapa eller välj en Slack-kanal där aviseringarna ska visas.
- Skapa ett Slack-arbetsflöde som startas av en webhook och tar emot ett
text-fält.
Videoguide
Du kan också titta på hela videon som visar hur det går till.
Skapa först Slack-arbetsflödet
I Slack skapar du ett arbetsflöde med utlösaren ”Börjar med” och en webhook. Lägg till en textvariabel med namnet text och lägg sedan till meddelandesteget som skickar ett meddelande till den kanal du valt med hjälp av just den variabeln text.

Bevilja rabatterad åtkomst i Workflow Trigger Extensions
Innan utlösaren visas i Shopify Flow måste du aktivera tillgång till rabatter i appen.
I Shopify-admin går du till Appar > Workflow Trigger Extensions.
Leta efter installationschecklistan på instrumentpanelen.
Aktivera ”Bevilja rabattåtkomst”. Detta aktiverar rabattrelaterade händelser som ”Rabatt skapad”, ”Rabatt uppdaterad”, ”Rabatt raderad”, ”Rabattkod tillagd”, ”Rabattkod borttagen” och ”Rabatt har gått ut”.

Skapa ett Shopify Flow
Öppna Shopify Flow och skapa ett nytt arbetsflöde.
Sök efter utlösare som rör rabatter och välj ”Rabattkod borttagen” bland utökningarna för Workflow Trigger Extensions.

Lägg till Shopify-åtgärden ”Hämta rabattdata”.
I avsnittet ”Välj en sökfråga för att filtrera data” väljer du ”Avancerat”. I ”Redigera sökfråga” använder du rabatt-ID:t från utlösaren och tar bort Shopify-prefixet GID:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Lägg till ett steg med koden ”Kör” efter ”Hämta rabattdata”.
Använd följande GraphQL-fråga i inmatningsfälten ”Välj” från tidigare steg:
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
}
}
}
}
}
}
}Definiera utgångarna på följande sätt:
"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!
}Klistra sedan in den här koden i fältet ”Skriv kod”:
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,
};
}
Lägg till åtgärden ”HTTP Request”. I fältet ”Variabler”** eller ”Body Override (JSON)**” skickar du den sammanfattning som returneras av kodsteget ”Kör”:
{
"body": {
"text": "{{runCode.summary}}"
}
}Detta skickar den genererade sammanfattningen till Slack-webhook-arbetsflödet med hjälp av variabeln text.

Spara arbetsflödet när alla steg är på plats.
För att testa, ta bort en rabattkod från din rabattkampanj och kontrollera att Slack-kanalen tar emot sammanfattningsmeddelandet.

Vad Slack-aviseringen innehåller
- Den borttagna rabattkoden
- Oavsett om det handlade om en stor utflyttning
- Kampanjens titel
- Rabattbeloppet
- Start- och slutdatum
- Tider som användes för den borttagna koden
- Uppskattad påverkan av den borttagna koden
- Användning och genomslagskraft inom hela kampanjen
- En uppdelning per kod, i den mån sådan finns tillgänglig
- Tidsstämpeln för när borttagningen genomfördes
Felsökning
Gå tillbaka till Appar > Workflow Trigger Extensions och kontrollera att ”Grant Discount Access” är aktiverat. Rabattutlösarna visas först efter att åtkomst har beviljats.
Kontrollera noga den avancerade sökfrågan under ”Redigera sökfråga”. ID:t ska rensas exakt enligt följande:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"Se till att Slack-arbetsflödet startas med en webhook, att webhook-URL:en är densamma som används i din HTTP-förfrågan och att förfrågans innehåll innehåller fältet text.
Vissa borttagningar kan ingå i en samlad åtgärd eller kanske inte ger fullständiga användningsuppgifter. I sådana fall kommer sammanfattningen ändå att innehålla den bästa tillgängliga informationen och tydligt markera saknade värden.
Bästa praxis
- Skicka dessa meddelanden till en särskild kanal för ekonomi eller drift istället för till en allmän supportkanal.
- Ge arbetsflödet ett konkret namn, till exempel ”Rabattkod borttagen”, så att det är lätt att känna igen i Shopify Flow och Slack.
- Testa först med en rabattkod som inte är avsedd för produktion för att kontrollera meddelandeformatet och hur webhooken fungerar.
