@duabalabs/sellub-pricing
Pure-TypeScript pricing engine behind Sellub’s plans, commission and fee math. Same code path runs in the server, the dashboard and 3rd-party integrations so quotes match invoices.
Install
pnpm add @duabalabs/sellub-pricingModules
| Module | Exports |
|---|---|
plans | SellerPlan, SellerPlanVariant, PLAN_CATALOG, ALL_PLANS, getMonthlyPricePesewas, getDirectCommissionPercent |
commission | resolveCommissionRate({ plan, variant?, source, sellerOverridePercent? }) |
attribution | AttributionSource, ALL_ATTRIBUTION_SOURCES, isMarketplaceAttributed, parseAttributionSource |
fees | calculateOrderFees(input), applyRefund |
addons | ADDONS, ALL_ADDONS, calculatePerformanceAdFee |
currency | formatMinor, formatPercent, pesewasToGhs, ghsToPesewas, DEFAULT_CURRENCY |
education | EDUCATION, ALL_EDUCATION — seller-facing explanations of plans and fees |
Everything is tree-shakeable — import only what you need. All amounts are integers in pesewas (GHS × 100).
Plan catalog
import { PLAN_CATALOG, SellerPlan } from "@duabalabs/sellub-pricing";
PLAN_CATALOG[SellerPlan.MARKETPLACE];
//=> { plan: 'MARKETPLACE', label: 'Sell on Sellub', isFree: true, directCommissionPercent: 5, … }| Plan | Variants (monthly) | Direct rate | Marketplace-attributed rate |
|---|---|---|---|
MARKETPLACE | free | 5% | — |
CUSTOM_DOMAIN | Starter GHS 250 · Pro GHS 600 | 3% · 2% | 4.5% |
COMMERCE_API | Developer GHS 500 · Growth GHS 1,500 · Enterprise (contact sales) | 1.5% · 1% · 1% | 3.5% |
Resolve effective commission
import {
resolveCommissionRate,
SellerPlan,
SellerPlanVariant,
AttributionSource,
} from "@duabalabs/sellub-pricing";
resolveCommissionRate({
plan: SellerPlan.CUSTOM_DOMAIN,
variant: SellerPlanVariant.CUSTOM_DOMAIN_PRO,
source: AttributionSource.SELLER_DIRECT_DOMAIN,
});
//=> { ratePercent: 2, basis: "direct", overrideApplied: false }
resolveCommissionRate({
plan: SellerPlan.MARKETPLACE,
source: AttributionSource.MARKETPLACE_SEARCH,
sellerOverridePercent: 6,
});
//=> { ratePercent: 6, basis: "override", overrideApplied: true }Quote order fees
import { calculateOrderFees, SellerPlan, SellerPlanVariant, AttributionSource } from "@duabalabs/sellub-pricing";
const quote = calculateOrderFees({
grossAmountPesewas: 50_000, // GHS 500
plan: SellerPlan.CUSTOM_DOMAIN,
variant: SellerPlanVariant.CUSTOM_DOMAIN_STARTER,
source: AttributionSource.SELLER_DIRECT_DOMAIN,
});
quote.commissionRatePercent; // 3
quote.commissionAmountPesewas; // 1_500
quote.sellerPayoutPesewas; // 48_500sellerPayoutPesewas is gross − commission — exactly what Sellub’s Paystack split pays
the seller. paymentProcessingFeePesewas is optional: Sellub pays Paystack’s fee, so when
you pass it, it comes out of platformRevenuePesewas (commission − fee, negative when the
fee is the larger), never out of the seller’s payout. (Before 1.1.0 it was subtracted from
the payout.)
Attribution-aware billing
On the paid plans, a sale that came through the Sellub marketplace is billed at the
plan’s marketplace rate; a sale on the seller’s own domain, app or link at the direct rate.
isMarketplaceAttributed tells the two apart:
import { isMarketplaceAttributed, parseAttributionSource } from "@duabalabs/sellub-pricing";
isMarketplaceAttributed(AttributionSource.MARKETPLACE_HOMEPAGE); // true
parseAttributionSource("seller_direct_domain"); // AttributionSource.SELLER_DIRECT_DOMAIN
parseAttributionSource("nonsense"); // nullSources: marketplace_search, marketplace_category, marketplace_homepage,
marketplace_recommendation (marketplace rate) and seller_direct_storefront,
seller_direct_domain, seller_direct_link, external_api, external_app,
ad_campaign, social_campaign (direct rate).
Format minor units
import { formatMinor, formatPercent } from "@duabalabs/sellub-pricing";
formatMinor(5_000); // "GHS 50.00"
formatMinor(5_000, { compact: true }); // "GHS 50"
formatPercent(2.5); // "2.5%"Why this lives in npm (not the server)
The same math has three callers:
- The Sellub Vendure server (
sellub-pricing-plugin) — persists the breakdown. - The Sellub dashboard — shows plans, prices and rates.
- Your integration — quotes “you’ll be charged X commission” in your UI.
By shipping it on npm, all three stay in lock-step. Bumping this package is the single source of truth for a rate change.
Related
sellub-pricing-plugin— the server plugin that consumes this package and persists the resultingOrderFeeBreakdown.sellub-types— shared types for webhooks and API results.