How OfferKit works
Understand how campaigns, programs, customers, rules, and rewards connect in OfferKit, and which decisions your application must handle at checkout.
OfferKit decides which incentive applies and keeps the record of what was used. It does not replace your cart, checkout, payment processor, user database, or messaging system. Your application sends it the customer and the cart, OfferKit answers with what applies, and your application commits the business event when it really happens.
The lifecycle of an offer
Most integrations follow the same path:
- Configure the benefit, audience, limits, dates, and stacking behavior.
- Preview what applies by validating a code or qualifying a cart.
- Present the code, discount, balance, points, or reward in your UI.
- Commit the business event: a voucher redemption, a referral conversion, a points earning, or a loyalty reward purchase.
- Record: OfferKit updates counters, balances, and ledgers.
- React: your systems pick up the result, either from the API response or, for voucher redemptions, from a webhook.
Previews consume no voucher usage or balance, so you can repeat them when the cart
changes. Voucher qualification can still create a customer record when you pass a
customerExternalId that OfferKit has not seen before.
Commit calls change state. How safely you can retry them depends on the operation:
| Commit | Retry protection |
|---|---|
| Voucher redemption and stack redemption | idempotencyKey |
| Referral conversion | conversionEventId, unique per referral code |
| Loyalty earning | eventId is stored on the ledger entry but is not deduplicated |
| Loyalty reward redemption | No body replay key. Use application tracking and the HTTP replay header |
For loyalty, your application has to do its own deduplication. Retries and recovery covers each case.
Start with the customer experience
Pick the object based on what the customer should experience:
| Customer experience | What you configure |
|---|---|
“Enter SAVE10 at checkout” | A discount voucher in a discount campaign |
| “Your cart automatically qualifies for 10 off” | A promotion tier in a promotion campaign |
| “You have 24.50 left on this card” | A gift-card voucher in a gift-voucher campaign |
| “You earned 200 points and reached Gold” | A member of a loyalty program |
| “Invite a friend and you both get 15 off” | A referral code and conversion in a referral program |
In these docs, offer is the everyday word for all of the above. It is not an API resource.
How the objects connect
Campaigns group benefit configuration. Loyalty and referral campaigns each carry a program, and the program holds everything specific to that kind of incentive.
Campaign (DISCOUNT / GIFT_VOUCHERS) ── has many ──▶ Vouchers
Campaign (PROMOTION) ── has many ──▶ Promotion tiers
Campaign (any type) ── may use one ─▶ Validation rule
Campaign (LOYALTY_PROGRAM) ── at most one ──▶ Loyalty program
Loyalty program ── has many ──▶ Tiers, Earning rules, Rewards, Members
Member ── belongs to one ──▶ Customer
Member ── has many ──▶ Ledger entries
Campaign (REFERRAL_PROGRAM) ── at most one ──▶ Referral program
Referral program ── has many ──▶ Referral codes (one per advocate)
Referral code ── has many ──▶ Conversions (one per referred friend)
Conversion ── creates ──▶ Reward vouchers in the same campaign,
or loyalty points, or a custom payloadA customer has at most one membership in each loyalty program and one advocate code in each referral program. Each advocate code can have many conversions, but only one per friend. Campaigns and promotion tiers can each attach one validation rule. Segments have no runtime campaign link.
OfferKit rejects a second program on a campaign that already has one. Deleting the program frees the campaign so you can create a new one. Both kinds of program need a campaign of the matching type.
How objects connect follows a customer through these links.
The main objects
Campaign
A campaign holds a name, currency, timezone, activation window, status, code defaults, an optional per-customer redemption limit, and an optional validation rule. Its type says what it contains.
A campaign is draft, active, paused, or ended. New campaigns start as drafts.
How much a campaign’s settings matter depends on what is inside it:
- Vouchers and promotion tiers respect campaign status, dates, currency, and the campaign validation rule on every validation, qualification, and redemption. A draft or ended campaign makes them unusable.
- Loyalty programs do not check campaign status or dates. Enrollment, earning, adjustments, and reward redemption work the same whether the campaign is a draft, active, or ended. If you want a loyalty program to stop, stop calling it.
- Referral programs do not check campaign status or dates when issuing codes or
converting. The reward vouchers a conversion creates do live in the referral campaign,
so they cannot be redeemed until that campaign is active and inside its dates. A
conversion on a draft campaign will succeed and hand out codes that fail at checkout
with
campaign_inactive.
Voucher
A voucher is a code. A discount voucher carries a fixed or percentage discount. A gift-card voucher carries a spendable balance. Vouchers can be shared, generated in bulk, or assigned to one customer.
A voucher can add its own dates, redemption limits, priority, exclusivity, and metadata. These can narrow what the campaign allows but cannot make an inactive campaign usable.
Promotion tier
A promotion tier is a discount without a code. Your server asks OfferKit to qualify the cart, and OfferKit returns the tiers that apply with a calculated preview. Each tier has its own conditions, priority, dates, and exclusivity.
Loyalty program and referral program
A loyalty program adds tiers, earning rules, rewards, members, and a points ledger. A referral program adds the reward for each side, advocate codes, and conversions. See Launch a loyalty program and Launch a referral program.
Customer
A customer links your user to vouchers, redemptions, loyalty memberships, referral
activity, and targeting data. Put your stable user ID in externalId, so you can upsert
without storing OfferKit’s UUID as your only lookup key.
Voucher validation, qualification, and redemption accept either customerId or
customerExternalId. Promotion qualification, loyalty, and referral calls accept only the
internal customerId (or a memberId), so upsert the customer first and use the returned
ID.
Order
An order records a transaction and links it to its redemptions. For a light integration you can send cart details inline with validation and redemption. Create order records when you also want order lookup and redemption history inside OfferKit.
Validation rule and segment
A validation rule answers a question such as “Is the order over 50.00?” or “Does the cart contain this product?”. OfferKit evaluates rules attached to campaigns and promotion tiers. A loyalty earning rule can store a validation rule ID, but OfferKit does not evaluate it, and loyalty rewards have no rule field at all.
A segment is a saved customer rule you can preview to see how many customers match. It is a design tool. Campaign decisions do not consult segments. See Target customers with rules and Rules reference.
Reward type
Discounts and gift-card credit are built in. A reward type names a benefit your own
application delivers, such as free shipping or a free sample. Promotion qualification
returns a tier’s custom rewards in eligible[].customRewards. For a voucher, read
customRewards with vouchers.get after a successful decision; validation, qualification,
and redemption responses do not include those payloads.
OfferKit does not check a custom payload against the reward type’s schema or check that its key names a registered reward type. Your application validates and delivers the benefit.
Three kinds of decisions
Qualification
Qualification finds offers the customer did not have to type in. Promotion qualification
returns the automatic promotions that fit the cart. Voucher qualification lists vouchers
assigned to the customer that work for the cart. Neither consumes anything, but voucher
qualification will create a customer for an unknown customerExternalId.
Validation
Validation checks one known voucher code and returns a discount preview, or a reason it
does not apply. It writes nothing, and an unknown customerExternalId is treated as a new
customer with no history. Call it again whenever the cart, currency, or customer changes.
Redemption
Redemption commits a voucher use. It increments counters, reduces gift-card balance when
relevant, and records the redemption. Discount redemptions emit voucher.redeemed; gift
spends currently do not emit that event. Send an idempotencyKey.
Referral conversion, loyalty earning, and loyalty reward redemption are the commit steps for their programs. They return their results in the API response and do not emit webhook events. See Webhooks for the current event list.
Where each responsibility belongs
| Responsibility | Usually owned by |
|---|---|
| Prices, tax, inventory, and the final order total | Your commerce system |
| Users, sign-in, and sessions | Your application |
| Payment capture and refunds | Your payment provider or commerce system |
| Offer configuration, eligibility, usage limits, balances, and ledgers | OfferKit |
| Deciding how many loyalty points an event is worth | Your application |
| Delivering custom rewards and loyalty reward payloads | Your application |
| Email, push, SMS, and in-app messages | Your messaging stack |
The integration blueprint turns this into an implementation plan. If you already know what you want to build, go to Build for a goal.
Build your first working offer
Run OfferKit locally, create a welcome discount, validate and redeem it at checkout, then inspect the result before building your own integration.
Build for a goal
Choose an OfferKit guide for promotional codes, gift cards, loyalty, referrals, customer targeting, automatic discounts, or combining voucher codes.