IntroductionTech StackQuick Start
Overview
Logo
Payment
X logoShare to XLinkedIn logoShare to LinkedIn

ShipNowKit ships a payment module that supports Stripe and Paddle for one-time purchases and subscriptions. Users can stay signed in while checking out, switching plans, and viewing order summaries.

What’s included

  • Provider switch: Pick Stripe or Paddle in Dashboard “Payment Settings”; store public keys, secrets, and webhook secrets separately.
  • Price mapping: Use priceMappings to map business keys (e.g., PRO_MONTHLY) to provider priceIds; frontend reads with getPriceId.
  • Pricing UI: PriceBtn handles login guard + checkout/upgrade flows; usePriceAmounts batches price fetch; useCheckout / useChangeSubscriptionPlan handle purchase vs. plan change.

Quick setup

Go to Dashboard > Settings > Payment, choose Stripe or Paddle, and save.

Stripe: stripe.publicKey, stripe.secretKey, stripe.webhookSecret (optional stripe.billingPortalConfigId).
Paddle: paddle.clientToken, paddle.apiKey, paddle.webhookSecret, paddle.environment.

Add mappings in “Price Mappings”, e.g., PRO_MONTHLY -> price_123, then the frontend can read them.

paymentConfig.successPage defaults to /payment/success; pricing section anchor is /#pricing; adjust as needed.

Tip: getPriceId('PRO_MONTHLY') reads Dashboard priceMappings first, then falls back to NEXT_PUBLIC_PRO_MONTHLY env var for local/preview overrides.

Pricing UI & Hooks

usePriceAmounts — fetch price amounts in batch

Input

Prop

Type

Output

Prop

Type

import { getPriceId } from "@/lib/client-config";
import { usePriceAmounts } from "@/components/price/hooks/usePriceAmounts";

const priceIds = ["PRO_MONTHLY", "PRO_YEARLY"]
  .map((key) => getPriceId(key))
  .filter(Boolean) as string[];

const { priceAmounts, isLoadingPriceAmounts } = usePriceAmounts(priceIds);

useActivePlans — fetch active subscriptions / one-time purchases

Input

Prop

Type

Output

Prop

Type

  • Typical uses:
    • Pricing page: pass to PriceBtn activePlans to decide new purchase vs. change plan vs. redirect.
    • UI copy: show “Activated”, “Switch to annual”, etc., based on existing plans.
import { useActivePlans } from "@/components/price/hooks/useActivePlans";
import { PriceBtn } from "@/components/price/PriceBtn";
import { getPriceId } from "@/lib/client-config";

const { userActiveSubscriptions, userActiveOneTimePayments } = useActivePlans(true, true);

<PriceBtn
  btnText="Subscribe now"
  targetPlan={{ isSubscription: true, priceId: getPriceId("PRO_MONTHLY") || undefined }}
  activePlans={[...userActiveSubscriptions, ...userActiveOneTimePayments]}
/>;

PriceBtn — handle login, checkout, upgrade

Prop

Type

import { PriceBtn } from "@/components/price/PriceBtn";
import { useActivePlans } from "@/components/price/hooks/useActivePlans";

const { userActiveSubscriptions } = useActivePlans(true, false);

<PriceBtn
  btnText="Upgrade to Pro"
  targetPlan={{
    isSubscription: true,
    name: "Pro",
    priceId: getPriceId("PRO_MONTHLY") || undefined,
    isYearly: false,
  }}
  activePlans={userActiveSubscriptions}
  className="w-full bg-primary text-white py-3 rounded-lg"
/>;

Customize Theme

Learn how to customize theme styles in ShipNowKit, including colors, fonts, and appearance modes.

Stripe Integration

Configure Stripe payments in ShipNowKit: dashboard setup, webhook validation, price sync, and event handling.

On this page

What’s included
Quick setup
Pricing UI & Hooks
usePriceAmounts — fetch price amounts in batch
useActivePlans — fetch active subscriptions / one-time purchases
PriceBtn — handle login, checkout, upgrade