Open-source Voucherify alternative

Launch checkout promotions without another deploy.

OfferKit is an open-source promotion engine for teams that own their checkout. Integrate one API for coupons, gift cards, loyalty, and referrals. After that, your team changes offers from the dashboard.

Run it locally · requires Docker
git clone https://github.com/offerkit/offerkit
cd offerkit && cp .env.example .env
docker compose up

Then open localhost:3000, mint an API key, and create WELCOME10. Quickstart steps →

checkout.ts
// On your server, with an OfferKit API key
await offerkit.vouchers.validate({
  params: { code: "WELCOME10" },
  body: {
    order: { amount: 5000, currency: "USD" },
  },
});
Response · trimmedvalid
{
  "valid": true,
  "preview": {
    "amount": 1000,
    "finalOrder": {
      "amount": 4000,
      "currency": "USD"
    }
  }
}

WELCOME10 takes a fixed USD 10.00 off. 5000 means USD 50.00, because amounts are integers in minor units.

License
MIT. No enterprise edition.
Latest release
v0.2.1 · Oct 15, 2026
Runs on
Node.js, Postgres, Redis
Docker image
ghcr.io/offerkit/offerkit

Four incentive types on one data model.

Campaigns, customers, orders, and rules are shared by every incentive. Each result below came from a real call against a local instance.

Discounts

Fixed or percentage codes with caps, product and collection eligibility, and limits. Generate up to 100,000 unique codes in one call.

vouchers.validate WELCOME10, USD 50.00 cartUSD 10.00 off · USD 40.00 due

Gift cards

Stored balances you can spend in part. Every debit lands in an append-only transaction ledger.

vouchers.redeem on a USD 50.00 card, USD 18.50 orderUSD 18.50 spent · USD 31.50 left

Loyalty

Programs with tiers, rewards, and a points ledger. Points can expire per earning.

loyalty.members.earn, 129 base points for order_5003+129 points · balance 129 · EARN ledger entry

Referrals

A stable code per advocate. Each conversion is recorded once and rewards both sides.

referrals.convert ANNA-UfXSjyQqUSD 10.00 voucher to each person

Target who qualifies

Attach a JSON Logic rule to a campaign. This one limits VIPWEEKEND to VIP customers with a cart of USD 40.00 or more.

{
  "and": [
    { ">=": [
      { "var": "order.amount" },
      4000
    ] },
    { "===": [
      { "var": "customer.metadata.vip" },
      true
    ] }
  ]
}
  • VIP, USD 50.00 cartvalid · USD 10.00 off
  • VIP, USD 25.00 cartvalidation_failed
  • Not VIP, USD 50.00 cartvalidation_failed

See exactly why codes fail.

The admin dashboard ships in the same image. Support sees every failed redemption grouped by its typed reason, and marketing adjusts the offer in the same place. Screens are from a local instance with demo data.

Insights: validation failure breakdown
OfferKit Insights validation failure breakdown: currency_mismatch 21, campaign_inactive 13, redemption_limit_reached 12, customer_required 8, no_discount_effect 5, per_user_redemption_limit_reached 1.
WELCOME10 discount settings
OfferKit dashboard Discount settings for WELCOME10: fixed amount, discount amount 10.00, no maximum cap, priority 0, exclusive (no stacking) off, active on.

Safe to call while money is moving.

Checkouts retry, double-submit, and fail halfway. These are OfferKit's guarantees inside each call, and the one thing your application still owns.

01

Validation never writes

Preview a code each time the cart changes. Counters, balances, and limits stay untouched.

POST /api/v1/vouchers/{code}/validate
02

Retries are idempotent

Use the order ID as the idempotency key. A retry returns the first result instead of redeeming twice.

idempotencyKey: order.id
retry.ts
const body = {
  order: { amount: 5000, currency: "USD" },
  idempotencyKey: "order_5001",
};
const redeem = () =>
  offerkit.vouchers.redeem({
    params: { code: "WELCOME10" },
    body,
  });

try {
  await redeem();
} catch {
  // Only transport errors throw. Rejections
  // return { ok: false, code } instead.
  await redeem();
}
Retry responsesame redemption
{
  "ok": true,
  "redemptionId": "b32060f3-46e9-…",
  "amount": 1000,
  "idempotent": true
}
03

Stacking is all-or-nothing

Apply up to 20 codes to one order in a single database transaction. All commit, or none do.

POST /api/v1/redemptions/stack
04

Every rejection has a reason

Sixteen typed codes, from expired vouchers to spent limits, each with a message support can read.

"code": "redemption_limit_reached"
05

Your application handles reversals

There is no public rollback endpoint, and cancelling an order does not reverse a redemption. Issue a replacement voucher, adjust loyalty points, or refund through your commerce system.

Recovery guide →

Call it from code, a terminal, or an agent.

The REST API, SDK, CLI, and MCP server share one typed contract. They accept the same inputs and return the same results.

Install with npm install @offerkit/sdk. The SDK, REST API, and CLI authenticate with a server API key from the dashboard. The hosted MCP server uses OAuth account sign-in.

SDK, REST, CLI, and MCP reference

Typed from the contract. Nothing to regenerate.

import { createClient } from "@offerkit/sdk";

const offerkit = createClient({
  baseUrl: process.env.OFFERKIT_API_URL,
  apiKey: process.env.OFFERKIT_API_KEY,
});

// In your order handler
await offerkit.vouchers.redeem({
  params: { code: "WELCOME10" },
  body: {
    order: { amount: 5000, currency: "USD" },
    idempotencyKey: order.id,
  },
});

OfferKit or Voucherify?

AspectOfferKitVoucherify
PriceFree. You pay for your own hosting.From $650/month for 25,000 API calls (Business plan)
LicenseMIT. Read, fork, and patch the engine.Proprietary
Hosting and dataYour infrastructure and your PostgresVendor cloud. Private hosting on Enterprise.
OperationsYou run Postgres, Redis, and upgradesManaged, with custom SLAs on Enterprise
InterfacesREST, SDK, CLI, and a self-hosted MCP server, all from one contractREST API and SDKs
ProgramsCoupons, gift cards, loyalty, referralsThose, plus bundling, gamification, and wallets
Usage limitsNone. Throughput depends on your hardware.25,000 API calls a month and 100 a minute on Business
MaturityYoung project (v0.x), community-supportedEstablished commercial vendor

Choose Voucherify for a managed platform with the widest feature set.

Choose OfferKit to own the code, the data, and the deployment, if you're comfortable running it.

There is no Voucherify importer yet. Campaigns, vouchers, customers, and validation rules are the same core concepts, so offers can be recreated through the API; see how objects connect. Voucherify figures are from its pricing page, checked November 2026.

Start with a working offer.

Once docker compose up is running, add the SDK to your checkout server or try a code from the CLI. The quickstart walks through creating WELCOME10.

Terminal
# In your checkout server
npm install @offerkit/sdk

# Or try the CLI against your instance
npm install -g @offerkit/cli
offerkit login --url http://localhost:3000 \
  --api-key offerkit_…
offerkit vouchers validate WELCOME10 \
  --amount 5000