Alertas de códigos de descuento eliminados
Cuándo utilizar este flujo de trabajo
Utiliza este flujo de trabajo cuando se elimine un código de descuento y necesites un registro inmediato de lo que se ha visto afectado. Te ayuda a registrar el código eliminado, su número de usos, los detalles de la campaña y un resumen que puedes enviar a los departamentos de finanzas u operaciones a través de Slack.
Esto resulta especialmente útil en el caso de códigos de influencers filtrados, la divulgación involuntaria de cupones o cualquier situación en la que se necesite un informe documentado sobre las repercusiones tras la retirada de un código.
Lo que vas a crear
- Un flujo de trabajo de Slack que recibe una variable
textdesde un webhook y publica ese mismo texto en un canal de Slack. - Un flujo de trabajo de Shopify Flow activado por la eliminación de un código de descuento.
- Un paso de datos «Obtener descuento» que busca el descuento utilizando el ID del desencadenante.
- Un paso de «Ejecutar código» que genera un informe de eliminación.
- Un paso de solicitud HTTP que envía el informe a Slack.
Antes de empezar
- Asegúrate de que la aplicación esté instalada y sea visible en el panel de administración de Shopify, en la sección «Apps» > «Workflow Trigger Extensions».
- Asegúrate de tener acceso a Shopify Flow.
- Crea o elige un canal de Slack en el que deban aparecer las alertas.
- Crea un flujo de trabajo de Slack que se inicie con un webhook y admita un campo
text.
Guía en vídeo
También puedes ver el vídeo completo de la implementación.
Crea primero el flujo de trabajo de Slack
En Slack, crea un flujo de trabajo con el desencadenante «Empieza por un webhook». Añade una variable de texto llamada text y, a continuación, añade el paso «Mensaje» que envía un mensaje al canal que hayas elegido utilizando esa misma variable text.

Conceder acceso con descuento en Workflow Trigger Extensions
Antes de que aparezca el disparador en Shopify Flow, activa el acceso a los descuentos en la aplicación.
En el panel de administración de Shopify, ve a «Apps» > «Workflow Trigger Extensions».
En el panel de control, busca la lista de comprobación de configuración.
Activa la opción «Conceder acceso a descuentos». Esto habilita los desencadenantes relacionados con los descuentos, como «Descuento creado», «Descuento actualizado», «Descuento eliminado», «Código de descuento añadido», «Código de descuento eliminado» y «Descuento caducado».

Construye el Shopify Flow
Abre Shopify Flow y crea un nuevo flujo de trabajo.
Busca los desencadenantes relacionados con los descuentos y selecciona «Código de descuento eliminado» en «Workflow Trigger Extensions».

Añade la acción Shopify para obtener datos sobre descuentos.
En «Seleccionar una consulta para filtrar datos», elige «Avanzado». En «Editar consulta», utiliza el ID de descuento del disparador y elimina el prefijo GID Shopify:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"
Añade un paso «Ejecutar código» después de «Obtener datos del descuento».
Utiliza la siguiente consulta GraphQL en las entradas de «Seleccionar» de los pasos anteriores:
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
}
}
}
}
}
}
}Define las salidas de la siguiente manera:
"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!
}A continuación, pega este código en «Escribir código»:
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,
};
}
Añade la acción «Solicitud HTTP». En el campo «Variables» o «Sustitución del cuerpo (JSON)», envía el resumen devuelto por el paso de código «Ejecutar»:
{
"body": {
"text": "{{runCode.summary}}"
}
}Esto publica el resumen generado en el flujo de trabajo del webhook de Slack utilizando la variable text.

Guarda el flujo de trabajo una vez que hayas completado todos los pasos.
Para comprobarlo, elimina un código de descuento de tu campaña de descuentos y comprueba que el canal de Slack reciba el mensaje resumen.

Qué incluye la alerta de Slack
- El código de descuento eliminado
- Ya fuera una recogida de residuos voluminosos
- El título de la campaña
- El importe del descuento
- Fechas de inicio y finalización
- Tiempos utilizados para el código eliminado
- Impacto estimado de la eliminación del código
- Uso e impacto en toda la campaña
- Un desglose código por código, cuando esté disponible
- La marca de tiempo en la que se procesó la eliminación
Solución de problemas
Vuelve a «Aplicaciones» > Workflow Trigger Extensions y comprueba que la opción «Conceder acceso a descuentos» esté activada. Los activadores de descuento solo aparecen una vez que se ha concedido el acceso.
Comprueba bien la consulta avanzada en «Editar consulta». El ID debe estar formateado exactamente como se muestra:
id:"{{discount.id|remove:'gid://shopify/DiscountCodeNode/'}}"Asegúrate de que el flujo de trabajo de Slack se inicie con un webhook, de que la URL del webhook sea la misma que la utilizada en tu solicitud HTTP y de que el cuerpo de la solicitud incluya el campo text.
Algunas eliminaciones pueden formar parte de una acción masiva o es posible que no proporcionen datos completos sobre el uso. En esos casos, el resumen seguirá mostrando la mejor información disponible e indicará claramente los valores que faltan.
Buenas prácticas
- Envía estas alertas a un canal específico de finanzas u operaciones, en lugar de a un canal de asistencia general.
- Elige un nombre concreto para el flujo de trabajo, como «Código de descuento eliminado», para que sea fácil de identificar en Shopify Flow y en Slack.
- Prueba primero con un código de descuento que no sea de producción para comprobar el formato del mensaje y el comportamiento del webhook.

