Generating hundreds of coupon codes is the easy part. The difficult part is proving that every code belongs to the intended campaign, can only be used under the approved conditions, reaches the correct audience, and can be disabled without guessing when something goes wrong. A bulk-coupon endpoint reduces manual work; it does not replace campaign architecture.
Zid's current Generate Bulk Coupons endpoint creates multiple unique codes under one shared configuration. The documented request can define discount type and value, start and end dates, total and per-customer usage limits, cart thresholds, applicable products or categories, conditions and channel flags such as Mazeed, POS and the mobile app. The coupon list and coupon detail reads expose status, usage and sales metadata. Together these primitives are enough for a controlled campaign workflow, but only if the integration treats generation as a state transition rather than a one-click fire-and-forget operation.
This is a current-documentation explainer, not a new product announcement. The official pages were verified on 28 September 2026. Fields and scopes should still be tested against the merchant's authorized environment before a campaign is launched.
Start with an immutable campaign specification
Do not send a bulk-generation request directly from an editable marketing form. First save a versioned campaign specification in your application. It should include the business owner, budget ceiling, intended audience, date window, discount strategy, minimum and maximum cart values, total and per-customer use limits, product or category scope, enabled channels and an approval state. Store monetary values with their currency and an explicit unit; do not let a UI ambiguity turn a percentage into a fixed discount.
The specification becomes immutable after approval. If marketing wants to change the discount or extend the dates, create a new version and record the reason. This gives engineers a stable object to compare with Zid after generation and gives finance a clear answer to “what was approved?”
{
"campaign_id": "sept-retention-v3",
"discount_type": "fixed",
"discount_value": 25,
"minimum_cart": 150,
"maximum_discount": 25,
"uses_per_customer": 1,
"channels": ["storefront"],
"starts_at": "2026-09-28",
"ends_at": "2026-10-05",
"approval_id": "approval-1842"
}That example is an application-side contract, not a verbatim Zid payload. Map it deliberately to documented fields such as `discount_type`, `discount`, `total`, `max_total`, `uses_total`, `uses_customer`, `date_start`, `date_end`, `apply_to`, `apply_to_array` and the relevant channel flags. Reject any specification whose mapping is incomplete.
Treat generation as an idempotent command
The documented bulk endpoint returns a campaign-level success message; the response example does not enumerate every generated code. That means a successful HTTP response is not yet a complete local inventory, and a network timeout creates an ambiguous outcome. Blindly retrying may generate another batch.
Persist a generation command before the API call. Give it a unique business key such as `campaign_id + batch_number`, store a hash of the approved specification, the requested quantity and the request attempt state, then allow only one worker to dispatch it. Mark connection failures after send as `unknown`, not `failed`.
After a confirmed or ambiguous response, use the List Coupons endpoint to discover and reconcile the campaign's codes. The documented list supports pagination and returns code, name, creation time, discount settings, validity dates, usage limits, status and channel flags. Match only on a campaign naming or code-prefix convention that your system owns, plus the expected time window and configuration hash. Do not assume every coupon created near the same time belongs to this campaign.
A safe command state machine is:
approved -> dispatching -> generated -> reconciled -> distributable
\-> unknown -> reconcile -> generated or reviewCodes must not become distributable until reconciliation confirms the expected quantity and configuration. If the provider response and the discovered set disagree, stop the campaign and require review.
Separate code inventory from customer assignment
A unique code is a secret-like entitlement. Store the provider coupon ID, code, campaign version, current status and assignment state separately. Encrypt codes at rest when the operational risk warrants it, restrict bulk export, log every reveal, and never place the complete code pool in analytics events, support logs or client-side source.
Assign a code to a customer in a transaction that locks one unassigned record. Record the channel and message attempt without marking the code “delivered” until the delivery provider confirms what it can confirm. If a message fails, decide whether the same code can be retried safely; do not allocate a new code on every communication retry. This separation prevents a transient email or SMS problem from consuming the inventory.
The documented `uses_customer` and `uses_total` fields are enforcement controls at the coupon layer. They do not replace assignment controls in your campaign system. A per-customer limit of one does not stop the same unassigned code from being accidentally sent to many people, and a unique code does not prove it reached the intended customer.
Make channel flags an allowlist
The bulk request documents flags for Mazeed, POS visibility and the mobile app, while the coupon reads expose those states. Treat the approved channel set as an allowlist. A campaign intended for a private retention segment should not silently become visible in POS or another public surface because a copied form kept an old default.
The `apply_to` and `apply_to_array` fields also deserve an explicit mapping. Resolve product and category identifiers before approval, snapshot them, and validate that they still exist before generation. If the campaign uses free shipping, the documentation notes that `max_weight` applies to that coupon type and has no effect on ordinary discount or fixed-amount coupons. A field being accepted by the API does not mean it changes every coupon type.
Progressive discount settings and general `conditions` add more power but also more test combinations. Prefer a small number of named campaign templates whose mapping is covered by contract tests. Do not expose every raw provider field to every operator.
Validate with a real cart, not local arithmetic
Your application can preview an expected discount, but Zid should decide whether a code is valid for the current cart. The storefront Check Coupon Validity endpoint checks without applying, while Apply Coupon applies the code and recalculates cart totals and rules. Use validation for fast feedback, then treat the post-application cart as the source of truth.
Do not reproduce the full rule engine in JavaScript. Product eligibility, dates, limits and totals can change between preview and application. The UI should handle a validation or apply response of 422 as a business rejection, display an appropriate message, and keep the cart intact. It should not retry the same invalid code as if the service were temporarily unavailable.
Before launch, run a matrix against a staging or controlled merchant context: just below and above the cart threshold, eligible and ineligible products, first and repeated customer use, start and end boundaries, each enabled channel, and a free-shipping case that crosses `max_weight` when that rule is used. Record the expected cart totals, not only whether the endpoint returned success.
Reconcile usage and stop safely
The coupon detail response includes usage statistics, linked orders, total sales, total customers and current status. Pull those fields on a bounded schedule for active campaigns and compare them with assignment and budget projections. The list endpoint also distinguishes active, inactive and expired coupons.
This documentation review did not verify a coupon-specific webhook that reports every change in use or configuration. Zid's webhook overview lists supported merchant events and advises partners to request an event when one is unavailable; do not invent a coupon event. Order events may help business analytics when their documented payload contains the required coupon data, but periodic coupon reads remain the reliable verification path described here.
Define stop conditions before distribution: usage or sales exceeds the approved slope, a code appears on a public leak list, channel flags drift, the reconciled count changes unexpectedly, or validation error rates spike. Use the documented status-update capability to deactivate affected coupons and verify the change by reading them back. Prefer deactivation for an incident response; the coupon overview documents permanent deletion separately, and irreversible cleanup should not be the first emergency action.
Useful observability includes generation commands in `unknown`, expected versus discovered codes, unassigned and assigned inventory, delivery attempts per code, validation rejection reasons, redeemed count, sales and discount cost, configuration drift and time since the last reconciliation. Alert on invariants, not only HTTP errors.
The core principle is simple: generate only from an approved snapshot, distribute from a controlled inventory, let Zid validate the live cart, and reconcile what the platform actually created and used. Bulk generation then becomes a safe operational capability rather than a faster way to multiply a campaign mistake.
Official references
These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.
Prepared by: Noor Yasser
Working through a similar engineering challenge?
I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.




