Docs
Tutorial

Payment Integration (Stripe & PayPal)

Complete step-by-step guide to setting up Stripe and PayPal in TikShip — API keys, webhook configuration, product price IDs, subscription plans, local testing with the Stripe CLI, and a production checklist.

TikShip ships with a dual payment provider architecture: Stripe and PayPal can both be active simultaneously and are selected per-product. Everything flows through the unified service at src/lib/payment/unified-service.ts — no code changes are needed, only environment variables and dashboard configuration.


Architecture Overview

User clicks Pay


/api/payment/create          ← UnifiedPaymentService

  ┌────┴────┐
  ▼         ▼
Stripe    PayPal
Checkout   Orders/Subscriptions API
  │         │
  ▼         ▼
Webhook   Webhook
  │         │
  └────┬────┘

  Order status updated in DB
  Email notification sent

Each product in the admin panel has one or more Payment Methods attached to it. A payment method records:

  • provider: stripe or paypal
  • mode: payment (one-time) or subscription
  • stripePriceId: the Stripe Price ID (for Stripe methods)
  • paypalPlanId: the PayPal Plan ID (for PayPal subscriptions)

Part 1 — Stripe

Create a Stripe Account

  1. Go to stripe.com and sign up.
  2. Complete the account activation steps (business info, banking details for live mode).
  3. Navigate to Developers → API keys in the Stripe Dashboard.

Copy API Keys

You will see two key pairs: Test and Live. Always start with Test keys.

# .env
STRIPE_SECRET_KEY="sk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"
STRIPE_PUBLISHABLE_KEY="pk_test_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Never commit secret keys to git. sk_test_... and especially sk_live_... must stay in .env (which is in .gitignore).

Create a Product and Price in Stripe

TikShip maps each purchasable item to a Stripe Price ID (price_xxx). You create these in the Stripe Dashboard:

  1. Go to Product Catalog → Add product.
  2. Enter a name (e.g. "Pro Plan").
  3. Under Pricing, choose:
    • One time — for a one-time payment
    • Recurring — for a subscription (set billing period: monthly, yearly, etc.)
  4. Enter the price and currency.
  5. Click Save product.
  6. On the product detail page, copy the Price ID (format: price_1ABC...).

You will paste this Price ID into the TikShip admin panel when configuring a product's payment method.

Configure Webhook

Stripe sends payment events to your server via webhook. TikShip's webhook handler lives at:

POST /api/stripe/webhook

For local development — use the Stripe CLI

  1. Install the Stripe CLI:
    # macOS
    brew install stripe/stripe-cli/stripe
    
    # or download from https://github.com/stripe/stripe-cli/releases
  2. Log in:
    stripe login
  3. Forward events to your local server:
    stripe listen --forward-to localhost:3000/api/stripe/webhook
  4. The CLI prints a webhook signing secret (format: whsec_...). Copy it.
# .env  (development only — use CLI secret)
STRIPE_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

For production — register in the Dashboard

  1. Go to Developers → Webhooks → Add endpoint.
  2. Endpoint URL: https://yourdomain.com/api/stripe/webhook
  3. Select these events to listen for:
EventWhy
checkout.session.completedOne-time payment success
checkout.session.expiredCheckout window timed out
checkout.session.async_payment_succeededAsync payment methods (e.g. bank transfers)
checkout.session.async_payment_failedAsync payment failure
  1. After saving, reveal the Signing secret and add it to your production .env:
STRIPE_WEBHOOK_SECRET="whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

TikShip verifies the webhook signature on every request using stripe.webhooks.constructEvent(). Requests with invalid signatures are rejected with HTTP 400.

Set Success and Cancel URLs

# .env
STRIPE_SUCCESS_URL="https://yourdomain.com/payment/success"
STRIPE_CANCEL_URL="https://yourdomain.com/payment/cancel"

For local development:

STRIPE_SUCCESS_URL="http://localhost:3000/payment/success"
STRIPE_CANCEL_URL="http://localhost:3000/payment/cancel"

Add a Product's Payment Method in the Admin Panel

  1. Go to Admin → Products → Edit (or create a new product).
  2. Scroll to the Payment Methods section.
  3. Click Add Payment Method.
  4. Select Provider: Stripe, Mode: payment (one-time) or subscription.
  5. Paste the Price ID from step 3.
  6. Toggle Active on.
  7. Save the product.

The customer will now see a Stripe checkout option on the product page.

Test with Stripe Test Cards

With the Stripe CLI running (stripe listen ...), start your dev server and attempt a purchase:

ScenarioCard NumberExpiryCVC
Successful payment4242 4242 4242 4242Any future dateAny 3 digits
Payment declined4000 0000 0000 0002Any future dateAny 3 digits
Insufficient funds4000 0000 0000 9995Any future dateAny 3 digits
3D Secure required4000 0025 0000 3155Any future dateAny 3 digits
Async payment4000 0038 0000 0446Any future dateAny 3 digits

Use ZIP 00000 and any billing name. After a successful test payment you should see:

  • The order status change to completed in Admin → Orders
  • A confirmation email in the server logs (or delivered to the user's inbox)

Part 2 — PayPal

Create a PayPal Developer Account

  1. Go to developer.paypal.com and log in with your PayPal account.
  2. Navigate to Apps & Credentials.
  3. Make sure you are in Sandbox mode (toggle at the top right).

Create a REST API App

  1. Click Create App under the REST API apps section.
  2. Give it a name (e.g. TikShip).
  3. Select Merchant as the app type.
  4. Click Create App.
  5. Copy the Client ID and Secret from the app detail page.
# .env
PAYPAL_MODE="sandbox"          # sandbox | live
PAYPAL_CLIENT_ID="Axxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
PAYPAL_CLIENT_SECRET="Exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Create Sandbox Test Accounts

PayPal provides auto-generated sandbox accounts for testing:

  1. Go to Testing → Sandbox Accounts.
  2. You should see a Personal account (buyer) and a Business account (seller) already created.
  3. Click on the personal account → View/Edit Account to see the sandbox buyer's email and password.

Use these credentials when approving a sandbox payment in the PayPal popup.

Create a Subscription Plan (for subscriptions only)

For one-time payments, no plan is needed — TikShip passes the amount directly to the PayPal Orders API.

For subscriptions:

  1. In the PayPal Developer Dashboard, go to Subscriptions → Plans → Create Plan.
  2. First create a Product (not the same as a TikShip product — this is PayPal's internal product).
  3. Then create a Plan linked to that product, set the billing cycle (monthly, yearly), and the price.
  4. After saving, copy the Plan ID (format: P-xxxxxxxxxxxxxxxxxxxxxxxx).

You will paste this Plan ID into the TikShip admin panel.

Configure Webhook

TikShip's PayPal webhook handler is at:

POST /api/paypal/webhook

For local development — use ngrok or similar

PayPal does not provide a CLI forwarder. Use ngrok to expose your local server:

# Install ngrok (macOS)
brew install ngrok

# Start ngrok tunnel
ngrok http 3000

ngrok gives you a public URL like https://abc123.ngrok-free.app. Use this as the webhook URL.

Register the Webhook in PayPal

  1. In your PayPal app settings, scroll to Webhooks → Add Webhook.
  2. Webhook URL: https://abc123.ngrok-free.app/api/paypal/webhook (or your production URL).
  3. Select these events:
EventWhy
CHECKOUT.ORDER.APPROVEDBuyer approved the order — triggers capture
PAYMENT.CAPTURE.COMPLETEDPayment captured successfully
PAYMENT.CAPTURE.DENIEDPayment capture failed
BILLING.SUBSCRIPTION.ACTIVATEDSubscription activated
BILLING.SUBSCRIPTION.CANCELLEDSubscription cancelled
BILLING.SUBSCRIPTION.EXPIREDSubscription expired
  1. After saving, copy the Webhook ID (format: 0SY50921UE9614629):
# .env
PAYPAL_WEBHOOK_ID="0SY50921UE9614629"

TikShip verifies the webhook signature on every request by calling PayPal's /v1/notifications/verify-webhook-signature API. Requests that fail verification are rejected.

Add a Product's Payment Method in the Admin Panel

  1. Go to Admin → Products → Edit.
  2. Scroll to Payment Methods → Add Payment Method.
  3. Select Provider: PayPal.
  4. For Mode: payment (one-time) — no Plan ID needed.
  5. For Mode: subscription — paste the PayPal Plan ID from step 4.
  6. Toggle Active on and save.

Test a PayPal Sandbox Payment

  1. Ensure PAYPAL_MODE="sandbox" in .env.
  2. Start your dev server and ngrok.
  3. Click Pay with PayPal on a product page.
  4. Log in with your sandbox Personal (buyer) account credentials.
  5. Approve the payment.
  6. PayPal sends a webhook to your ngrok URL → forwarded to localhost:3000/api/paypal/webhook.
  7. Check Admin → Orders — the order should be completed.

Switching to Live / Production

Stripe

  1. In the Stripe Dashboard, switch to Live mode.
  2. Copy your live API keys (sk_live_... / pk_live_...).
  3. Create a new webhook endpoint pointing to your production domain.
  4. Update .env on the server:
STRIPE_SECRET_KEY="sk_live_xxxx"
STRIPE_PUBLISHABLE_KEY="pk_live_xxxx"
STRIPE_WEBHOOK_SECRET="whsec_xxxx"   
Payment Integration (Stripe & PayPal) | Tikship