They Already Used That Code. Why Does Your Scheduled Agent Keep Sending It Again?
They Already Used That Code. Why Does Your Scheduled Agent Keep Sending It Again? A customer redeems a welcome code in March. The order goes through, the discount applies, and the customer forgets about it. In October, your scheduled agent runs its win-back campaign and sends that same customer the same welcome code, as if March never happened. The customer tries it at checkout, the store rejects it as already redeemed, and a small moment of goodwill turns into a support message asking why the
They Already Used That Code. Why Does Your Scheduled Agent Keep Sending It Again?
A customer redeems a welcome code in March. The order goes through, the discount applies, and the customer forgets about it. In October, your scheduled agent runs its win-back campaign and sends that same customer the same welcome code, as if March never happened. The customer tries it at checkout, the store rejects it as already redeemed, and a small moment of goodwill turns into a support message asking why the code does not work.
Nothing in the campaign looks broken. The schedule fired on time, the audience list came from the right place, and the template is the one you approved. The failure is quieter: the agent's memory of who redeemed what never made it from the order into the next run.
The redemption lives somewhere the agent never looks
A scheduled agent usually works from a list. Someone builds an audience: customers who have not ordered in 90 days, or who signed up but never bought. The agent pulls that list, writes a message for each person, and sends. The next run pulls the list again.
The problem is what that list does not contain. Redemption history usually lives in the store or the order system. The agent's audience list lives in the email tool or the automation workflow. Unless someone deliberately connects the two, the agent has no way to know that the person on row 214 already used the code it is about to send. It is not ignoring the redemption. It never saw it.
This is why the bug survives every spot check. Open the workflow and the logic reads correctly: send the win-back offer to lapsed customers. Open the order record and the redemption is right there. The gap is between those two views, and nobody owns the gap, because each system looks correct on its own.
Three places the fact disappears
First, the list is frozen. Many scheduled campaigns build their audience once and reuse it. A customer who redeems a code between list builds stays on the list, because the list was never rebuilt with the new information. The agent sends to a snapshot of the past, not to the present.
Second, the redemption is recorded as an order detail, not as a customer fact. The order system knows the code was used on order 4812. The customer record may not carry a simple, checkable flag like "welcome code redeemed on March 12." An agent that can only read customer-level fields will miss an order-level fact every time.
Third, the send itself is never written back. After the agent sends a code, that send should become part of the customer's history immediately, so the next run, even an hour later, can see it. When sends are only logged in the campaign tool's reporting tab, the next run starts from the same ignorance as the last one. A customer can receive the same offer twice in one week from two runs that each think they are sending it for the first time.
Any one of these gaps is enough to produce the symptom. Most setups have all three.
The check that has to happen before every send
The fix is a gate, not a better list. Before the agent sends a code to a person, it should ask one question and wait for the answer: has this person already redeemed this code, or one like it? If the answer is yes, the run skips them and moves on. No message, no apology needed later, no support ticket.
That gate only works if redemption data is available where the agent makes its decision. That means writing redemptions back to a shared record the moment an order completes, in a form the agent can read: who, which code, when, and on which order. The agent's audience must also be a live check at send time, not a list built last month.
Record scope, not just identity. A customer who used a welcome code may still qualify for a seasonal sale or a loyalty reward. What they should not receive again is that same one-time code. If the record only says "received a discount," the agent has to guess which offers are still open. Record the specific code and offer, so the gate can be precise instead of broad.
Why this one costs more than a bad email
A repeated code is not just an awkward message. If the code still validates, the business gives away margin it never intended to give, sometimes repeatedly to the same customers. If the code rejects at checkout, the customer feels tricked: they were offered something, tried to use it, and were told no. Either way, the customer learns that messages from this business cannot be trusted, and the next offer, even a genuine one, gets ignored.
Support pays for it too. Each rejected code becomes a message, a lookup, and an explanation, and across a win-back list of a few thousand people on a weekly schedule, a small memory gap becomes a standing support queue.
What to check in your own setup
Start with one past campaign. Pick a code sent to at least a hundred people, and check how many of them had already redeemed it before the send. If that number is not zero, the gate is missing, and its size tells you how long it has been missing.
Then trace a single redemption from order to next run. Place a test order with a code, wait for the next scheduled run, and see whether the agent still treats that customer as eligible. If it does, follow the data: where was the redemption recorded, who can read that record, and does the run actually read it before sending?
The memory underneath the campaign
A scheduled agent does not need a cleverer message. It needs to remember what already happened before it acts. When every run can read the same shared record of redemptions, sends, and customer history, the gate works without anyone rebuilding lists by hand. The agent stops offering what was already used, because "already used" is part of what it knows before it writes a single word.
That is how Vilix AI is built to work. It is cloud-hosted, so there is zero infrastructure to manage: no database to provision, no store to babysit. Every agent connects over MCP and reads the same memory, so a redemption recorded by one workflow is visible to the next run of every other workflow. It stores full conversation history, not just extracted facts, so the actual exchange around an offer can be retrieved and checked. It is free to start, with a free plan that stays free forever and a 7-day Pro trial with no credit card required, and your data stays portable: export everything or delete it anytime. See the plans at https://vilix.ai/?utm_source=vilix-blog&utm_medium=article&utm_campaign=scheduled-agent-discount-codes-already-used-memory.
A discount code is a promise. Sending it again to someone who already kept their end of it breaks that promise twice: once when it fails at checkout, and again when the customer stops believing the next offer. Give your agent the memory to check before it sends, and the promise stays intact.