Run a promotional code
Launch shared or customer-specific promotional codes in OfferKit, set eligibility and usage limits, and connect validation and redemption to checkout.
Use this pattern when a customer should enter a code such as WELCOME10, or when you
want to distribute a unique code to each recipient. OfferKit validates the code against
the customer and cart, calculates the result, and records committed use.
Decide how codes should work
Choose a shared code when memorability and reach matter. A single SUMMER20 code
can be placed in an advertisement, shared by an affiliate, or given to support agents.
Use per-customer limits when the same customer should not use it repeatedly.
Choose unique codes when attribution, leakage control, or individual assignment matters. Generate them in bulk or create them on demand and optionally attach each voucher to a customer.
Before building, decide:
- fixed amount or percentage discount;
- whether eligibility depends on specific products or collections;
- total and per-customer usage limits;
- start and end dates;
- whether the code can combine with other vouchers;
- what your checkout should say when it does not apply.
Configure the campaign
In Campaigns, create a campaign with type DISCOUNT. Set its currency, timezone, activation window, and any campaign-wide per-user limit. For generated codes, configure the default prefix and length. Activate the campaign when it is ready to accept use.
Then create the voucher:
- enter a memorable code for a shared campaign; or
- use Bulk generate on the campaign for a pool of unique codes;
- choose
AMOUNTorPERCENTAGE; - set voucher-specific dates, limits, priority, exclusivity, or customer assignment.
All monetary amounts use minor units. Percentage values use basis points: 1000 means
10%, and 10000 means 100%. A percentage voucher can include maxDiscountAmount.
Integrate the checkout
Send the code to your own server. Validate it whenever the customer applies the code or the cart changes:
const validation = await offerkit.vouchers.validate({
params: { code: submittedCode },
body: {
customerExternalId: session.user.id,
order: {
amount: cart.totalCents,
currency: cart.currency,
items: cart.items.map((item) => ({
productId: item.productId,
collectionId: item.collectionId,
quantity: item.quantity,
unitPrice: item.unitPriceCents,
})),
},
},
});When validation.valid is true, use validation.preview.finalOrder and the breakdown
to display the result. Keep the original cart amount authoritative in your commerce
system and persist the accepted discount explicitly.
When the order should consume the code, redeem it:
const redemption = await offerkit.vouchers.redeem({
params: { code: submittedCode },
body: {
customerExternalId: session.user.id,
externalOrderId: order.id,
order: {
amount: order.subtotalCents,
currency: order.currency,
items: order.items,
},
idempotencyKey: `${order.id}:vouchers`,
},
});Use the same customer and order context for validation and redemption. Revalidate on the server at commit time; do not trust a preview stored in the browser.
Show useful failures
Validation and redemption can explain conditions such as:
- campaign or voucher inactive;
- activation window not reached or already ended;
- redemption limit reached;
- customer required or not assigned to this voucher;
- customer has reached their personal limit;
- currency mismatch;
- validation rule failed.
Map these reason codes to clear customer copy, and retain the code and details in server logs for support. Do not reduce every failure to “invalid coupon.”
Test before launch
Test at least:
- a qualifying customer and cart;
- a cart just below the threshold;
- the wrong currency;
- an expired or future code;
- a customer using the code twice when a per-user limit is one;
- two concurrent requests with the same idempotency key;
- any product or collection inclusion boundary.
Launch and operate
Watch Insights for volume and failure reasons. Use the voucher page to inspect or disable a leaked code without pausing every voucher in the campaign. Pause the campaign when the whole promotion must stop temporarily; mark it ended when it is complete.
For several codes on one order, use Combine discounts safely. For code-free behavior, use Build an automatic cart discount.
Limits, assignment, and generated codes
A voucher’s redemptionLimit caps its total uses across all customers. Its
perUserRedemptionLimit caps uses by one identified customer. A campaign’s
perUserRedemptionLimit counts that customer’s voucher uses across the entire campaign.
For example, campaign limit 1 means using WELCOME10 prevents the same customer from
using another voucher in that campaign. It does not mean one use of each code. There is
no campaign-wide total redemption limit field. Failed attempts do not consume per-user
usage; internal rollback records are excluded from that count. A payment refund alone
does not restore usage, and there is no public rollback command. Assigned vouchers require the matching
customer; unassigned codes may allow guests when no customer-dependent condition or
per-user limit is configured.
Creating or generating a code does not assign or send it to anyone. Set customerId on
the voucher to assign it, then deliver the code through your application. Assigned codes
can appear in the customer’s available-offers list. A shared public code is not returned
there just because the customer could use it.
Bulk generation runs inline for up to 10,000 codes. Larger requests return generated: 0
and a jobId while the worker generates them. That response is acceptance, not completion.
Check the campaign’s voucher list and count, and correlate worker logs by job ID before
sending a batch. There is no public job-status endpoint. Check for a completed batch
before resubmitting a timed-out request; bulk generation has no body idempotency key.
A product condition makes the whole offer eligible when the product is present. The
current calculator uses order.amount as its discount base and does not enforce
discount.appliesTo as a line-item filter. See Rule inputs and operators.
Build for a goal
Choose an OfferKit guide for promotional codes, gift cards, loyalty, referrals, customer targeting, automatic discounts, or combining voucher codes.
Build an automatic cart discount
Build automatic cart discounts with OfferKit promotion tiers, qualify eligible offers from customer and cart data, and apply the selected result.