Features
Everything You Need to Sell on Your Terms
💰 Payment Plans
Create reusable payment structures that fit your products and customers:
- Deposit — Pay a percentage (e.g., 50% now) or fixed amount (e.g., $500 now) at checkout. Balance is charged later on fulfillment.
- Pre-order — Collect a deposit to reserve inventory. Balance is auto-charged when the product launches or ships.
- Deferred / Split — Split the full amount into N installments after a configurable down payment.
Each plan has a name, description, deposit type (percent or fixed), deposit value, installment count, and auto-charge flag. Plans can be paused or archived without deleting them.
⚙️ Plan Rules Engine
Automate which plan applies to which order with a flexible rules engine:
- AND conditions: Match on product (specific SKUs), collection (entire categories), minimum order value, or customer tags
- Priority ordering: Rules are evaluated top-to-bottom — the first matching rule wins
- Propose vs Require:
proposeauto-applies the plan when conditions match;requireflags it for merchant review - Enable/disable individual rules without losing their configuration
Example use cases
"All products in the Handmade collection → 50% deposit, balance on fulfillment"
"Orders over $500 → deferred, split into 3 installments"
"VIP customer tag → 10% deposit only"
🤖 AI Suggestions (MODE B)
When an order doesn't match any manual rule, the AI engine analyzes the order context and suggests a payment plan:
- Heuristic scoring based on order total bands, product type, and customer signals
- Suggested split: deposit amount, balance amount, with a confidence percentage
- Approve — apply the suggested plan
- Override — choose a different active plan
- Reject — no plan assigned (merchant handles manually)
All suggestions are recorded with their reason and confidence score, so merchants always know why a plan was proposed.
🔗 Stripe Payments
All money movement happens through Stripe — reliable, PCI-compliant, globally available:
- Stripe Checkout Sessions: Customers pay on Stripe's hosted, mobile-optimized payment page
- Shareable deposit links: Each order gets a unique, unguessable payment URL
- Manual capture for deposits: Authorize now, capture on fulfillment (reduces refund risk)
- Auto-capture for balances: Once the balance is due, it's captured immediately
- Webhook integration:
payment_intent.succeededandpayment_intent.payment_failedare handled with full idempotency — no double charges
📋 Orders Dashboard
Track every order with a payment plan in one place:
| Column | Details |
|---|---|
| Status | awaiting_deposit → deposit_paid → balance_paid / failed / voided |
| Deposit link | Copy and send to customer |
| Charge balance | Manual trigger for non-autocharge plans |
| Refund | Refund captured deposits and balances |
| History | Charge attempts, dunning events, AI recommendations |
❤️ Dunning (Payment Recovery)
Failed payments don't mean lost sales — the dunning engine automatically escalates:
- 4 stages: Reminder 1 → Reminder 2 → Final Notice → Escalation
- Configurable timing: Defaults 3 → 7 → 14 days between stages
- Full event log: Every notification is recorded with timestamp and stage
- Extensible: Designed to connect to email/SMS for customer-facing notifications
🔄 Installments
Deferred plans support splitting the balance into multiple payments:
- Configurable installment count (2, 3, 4, 6, etc.)
- Equal payment amounts per installment
- Schedule tracked on the OrderPayment record
- Each installment creates its own ChargeAttempt
⏰ Autocharge Cron
A standalone script (npm run autocharge) runs on a schedule to collect outstanding balances:
- Finds orders with status
deposit_paid, past due date, and auto-charge enabled - Creates a Stripe PaymentIntent for the balance
- Records a pending ChargeAttempt
- Transitions status to
auto_charging - Success/failure is reconciled by the Stripe webhook
🔐 Security
- Stripe secret keys are never stored in the database — only referenced by environment variable name
- All Stripe webhooks verify the
stripe-signatureHMAC before processing - Idempotency keys prevent duplicate processing of the same event
- Payment tokens are
crypto.randomUUID()— unguessable, no PII leakage - No customer payment data (credit card numbers) ever touches our servers — Stripe handles it directly