Skip to main content

Send thousands of discount codes at once

Generate a batch or import a CSV, download the codes, match them to email in Mailchimp, and export the usage record.

Written by Firstory

Do you need to send one code per person to a list of several thousand, and then work out who used theirs? This article covers the full flow. To send one code that everybody shares, read Send discount codes with Membership Offers instead.

Every code in a batch can be used once, and you cannot change that. A batch exists to give one code to one person. To send a code that many people share, add a single code instead.

Two ways to make codes

Click Add code under a campaign. Beside Single, you get two more options:

  • Generate a batch. The platform draws the strings. You enter a quantity (up to 20,000 per batch) and can add a prefix, so a code reads SUMMER-K7M2-9XQP. Generated codes are upper case and leave out 0, O, 1, I and L, because your listener types them by hand and those glyphs are easy to misread. A prefix can use upper-case letters and the digits 2 to 9 only

  • Import a CSV. Upload your own list of codes. This suits a numbering scheme you already use, such as MEMBER-000123. We store an imported code exactly as it is, with no rewrite and no format check. The trade-off is a higher typing error rate. If your listener types the code by hand, avoid glyphs that are easy to confuse

Codes are written in the background

20,000 codes are not written the instant you click the button. The batch appears in the list at once and shows its progress, and you can leave the page and come back. Generation blocks nothing: you can start another batch under the same campaign, and you can add a single code.

A batch row shows five states: Queued (starts within a minute), Generating, Active, Disabled, and Generation failed.

Two things to know:

  • You cannot export while a batch is generating. The file is incomplete, so you would download half a list and send dead codes

  • A failed batch is not retried. It leaves no half-written codes behind. To make the codes again, start a new batch. The failure reason is kept, so support can still find out why a batch never went out. Clear this row only removes the row from the list. It deletes no data

Importing a CSV takes two steps

The button reads Validate file, not Import. This step creates nothing. It only tells you how many rows can be imported.

File format. One code per row, in the first column. A first row that reads code, coupon, promo code or a similar column name is skipped automatically. One file holds up to 20,000 rows and 4 MB.

The report splits the errors into three groups, because each one is fixed differently:

  • Duplicated in the file. The same code appears twice in your file. Remove the duplicates in your spreadsheet. Case is ignored, so abc and ABC count as duplicates

  • Conflicts with a live code. Your show already has another code that uses this string. Change the code in your file, or find that code and disable it

  • Bad format. A code cannot hold a space or a comma, cannot be empty, and cannot exceed 64 characters. A space at the start or the end is trimmed and the row is imported. A space inside the code is refused

Each group shows up to 5 example rows and then a count of the rest. You can import only the clean rows, or fix the file and upload it again. A validation result is valid for 30 minutes. After that, select the file again.

Match email addresses with the CSV the platform exports

This is the step to guard most carefully. Say you upload 979 rows and only 842 are imported. If you match email addresses with the file you uploaded, then 137 people get a code that does not exist.

The import result screen asks you to download the exported CSV. That file holds the codes your listeners can actually redeem. The batch row keeps its export button, so you can download the file again at any time.

When you confirm, the platform validates the file again. A different count from the first check is normal, usually because another code went live in between. The screen shows you both numbers.

Send the codes out (Mailchimp example)

Firstory makes the codes, keeps each string unique, exports them, validates them, and counts the redemptions. Your email tool matches a code to a person and sends the message. We never touch your recipient list. That is also why a code is not tied to an email address.

  1. Generate or import the codes in Firstory, then download the CSV (one column, code). Make more codes than you have recipients

  2. In Mailchimp, export the email addresses of the audience or segment you want

  3. In a spreadsheet, put the email addresses and the codes in two columns side by side

  4. Mailchimp > Import contacts > upload the file > select "Update any existing contacts" (without it, existing contacts are not updated) > in column matching, create a new audience field, for example COUPON

  5. Put *|COUPON|* in the email content

  6. Before you send, create a segment for "COUPON is blank" and confirm the result is 0

Step six is the most important check. An email tool only replaces the merge field. It does not track how many codes are left, and it does not track which codes are redeemed. So the usual failure is one person who gets an email with no code in it. Too few codes, a misaligned import, or a missed checkbox in step four all produce that same symptom.

Two Mailchimp limits: one audience holds up to 30 fields (80 on Premium), and the built-in Promo Code content block does not work here. It needs a store integration such as Shopify, and one block holds one code.

See who redeemed: export the usage record

In the campaign row, open the ... menu and click Export usage record. The file holds seven columns:

  • code: the code string

  • source: where the code came from. generated means the platform drew it, imported means you imported it, single means you added it one at a time. unknown means a data fault. Tell us if you see it, and do not read it as a single code

  • status: redeemed or unredeemed

  • redeemed_at, email, tier_plan, amount: the redemption time, the member email address, the plan they bought, and the amount actually charged

The file holds one row per redemption, plus one row for every code nobody has used. So it answers two questions at once: who used this campaign, and how many codes are still out there. On an unredeemed row the last four columns are empty, but the columns are still there.

Three things that are easy to misread:

  • tier_plan holds the plan bought at the time of redemption. If that member upgrades later, this row is not rewritten

  • The "N redemptions left" figure on screen counts slots, not codes. A code with a limit of 100 and 3 settled uses reports 97, and a batch disabled as a whole reports 0. So that number can differ from the row count

  • A redemption still in progress counts as unredeemed. This file reports settled charges only

You cannot export the usage record while any batch is generating. Wait until every batch in the campaign is ready, or the file will be missing rows.

Troubleshooting

  • "This file is not UTF-8 text": in Excel, save the file as "CSV UTF-8". Do not save it as "Unicode Text"

  • More than 20,000 rows or more than 4 MB: split the list and import it as two batches

  • "No row can be imported": no batch is created. Every code in the file is a duplicate, already live, or badly formatted

  • "You have too many validated files that are not imported": import one of them, or wait 30 minutes for the oldest one to expire

  • "This file was validated for another campaign": upload it again from the campaign you want the codes in

  • No export button: a batch must reach Active or Disabled before you can export it. A disabled batch can still be exported, because you still need to know which codes you sent out

Related articles

Did this answer your question?