medusa-wallet
v0.0.7
Published
Production wallet/store-credit ledger for Medusa v2 with cart reserves, gift cards, claim codes, and refunds.
Maintainers
Readme
medusa-wallet
Production-oriented customer wallet / store-credit ledger for Medusa v2: integer minor-unit ledger, cart credit-line reserves, gift cards, claim codes, refunds, reconcile, and Razorpay top-up.
Features
- Integer minor units (BIGINT) only — never float/DECIMAL for money
- Immutable ledger + compensating
reverse(); idempotent mutations return the original result - Atomic conditional balance updates (
WHERE available >= amount) - Cart wallet credits: reserve → commit / release with hold TTL + multi-pod
FOR UPDATE SKIP LOCKEDjob - Gift cards backed by anonymous wallets (create, cart apply, purchase on
order.placed, expiry) - Credit lots with
credit_source+ optional expiry (FIFO spend) - Claimable anonymous wallet / gift-card codes (one-shot, Redis/DB rate-limited; requires
has_account) - Refunds via negative order credit lines + wallet-first PSP saga (
wallet_refund_intent) - Admin create / credit / debit / reverse (reason + audit) + reconcile + refund-intent retry + customer widget
- Full-pay checkout via wallet payment provider (
pp_wallet_*) still supported - Razorpay top-up (initiate, complete, webhook)
Installation
npm install medusa-walletimport { defineConfig, Modules } from "@medusajs/framework/utils"
export default defineConfig({
plugins: [
{
resolve: "medusa-wallet",
options: {
enabled: true,
ledgerWrites: true,
checkoutEnabled: true,
topUpEnabled: true,
cartCreditsEnabled: true,
giftCardsEnabled: true,
defaultCurrency: "INR",
holdTtlMinutes: 90,
// redisUrl: process.env.REDIS_URL,
razorpay: {
keyId: process.env.RAZORPAY_KEY_ID,
keySecret: process.env.RAZORPAY_KEY_SECRET,
webhookSecret:
process.env.RAZORPAY_WEBHOOK_SECRET ||
process.env.WALLET_RAZORPAY_WEBHOOK_SECRET,
},
},
},
],
modules: {
[Modules.PAYMENT]: {
resolve: "@medusajs/medusa/payment",
options: {
providers: [
{
resolve: "medusa-wallet/providers/wallet",
id: "wallet",
options: {},
},
],
},
},
},
})npx medusa db:migrateCheckout paths
- Wallet partial:
POST /store/carts/:id/wallet-credits→ credit linereference=wallet - Gift card:
POST /store/carts/:id/gift-cards{ code }→ credit linereference=gift-card - Full-pay: wallet payment provider only
On complete-cart, reserves for wallet and gift-card lines are committed before payment auth.
Store APIs
| Method | Path | Description |
|---|---|---|
| GET | /store/wallet | Alias of balance |
| GET | /store/wallet/balance | available / reserved / total + expiry hints |
| GET | /store/wallet/transactions | History |
| GET | /store/wallet/gift-cards | List gift cards assigned to the customer (claimable + claimed) |
| POST | /store/wallet/claim | Claim code (wallet or gift-card backed) |
| POST/DELETE | /store/carts/:id/wallet-credits | Apply / remove wallet credit |
| POST/DELETE | /store/carts/:id/gift-cards | Apply / remove gift card |
| GET | /store/gift-cards/:code | Lookup gift card + balance |
| GET/POST | /store/wallet/top-up/* | Razorpay top-up |
Admin APIs
| Method | Path | Description |
|---|---|---|
| GET/POST | /admin/wallets | List / create accounts |
| POST | /admin/wallets/credit | debit | Requires reason |
| POST | /admin/wallets/reverse | Compensating reverse of a ledger entry |
| GET/POST | /admin/wallets/refund-intents | List stuck intents / retry PSP |
| GET|POST | /admin/wallets/:id/reconcile | MATCH / MISMATCH |
| GET/POST | /admin/gift-cards | List / create gift cards |
| GET/POST | /admin/gift-cards/:id | Retrieve / update |
Admin UI: Wallets, Gift cards, customer wallet widget. Transaction reverse action on wallet detail.
Refunds (wallet-first saga)
- Negative order credit line → create
wallet_refund_intent(split viasuggestWalletRefundAmount) - Credit wallet portion (idempotent per OCL id)
- If
psp_amount > 0→refundPaymentWorkflowfor remainder → markcomplete - On PSP failure → stay
wallet_credited; resume job retries; admin can reverse (clawback) or retry
Jobs
| Job | Role |
|---|---|
| release-expired-wallet-holds | TTL expire with SKIP LOCKED |
| resume-stuck-wallet-refund-intents | Retry PSP remainder |
Tests
npm testIncludes crash/retry / dual-expire / gift-card dual-reserve / refund idempotency suites.
