Skip to Content
Core ConceptsProviders

Providers

Hoikka uses a provider pattern for payments and shipping, making it easy to add new integrations.

Payment Providers

Interface

Defined in src/lib/server/services/payments/types.ts:

interface PaymentProvider { code: string; // unique code like 'stripe', 'paypal' createPayment: (order: OrderWithRelations) => Promise<PaymentInfo>; confirmPayment?: (paymentId: string) => Promise<PaymentStatus>; refundPayment?: (paymentId: string, amount?: number) => Promise<RefundInfo>; }

Adding a Provider

src/lib/server/services/payments/providers/klarna.ts
export class KlarnaProvider implements PaymentProvider { code = "klarna"; async createPayment(order: OrderWithRelations): Promise<PaymentInfo> { // Create Klarna payment session const session = await klarnaClient.createSession({ amount: order.total, currency: "EUR" // ... }); return { providerTransactionId: session.id, redirectUrl: session.redirect_url }; } async confirmPayment(paymentId: string): Promise<PaymentStatus> { const payment = await klarnaClient.getPayment(paymentId); return payment.status === "CAPTURED" ? "settled" : "pending"; } }

Register it:

src/lib/server/services/payments/index.ts
import { KlarnaProvider } from "./providers/klarna"; PROVIDERS.set("klarna", new KlarnaProvider());

Then add a matching row to the payment_methods table (the built-in methods are seeded by drizzle/0002_seed_defaults.sql).

Enabling Stripe

Stripe is the built-in real payment provider. To enable it:

  1. Get API keys from Stripe Dashboard 
  2. Set environment variables:
STRIPE_SECRET_KEY="sk_test_..." PUBLIC_STRIPE_PUBLISHABLE_KEY="pk_test_..."

Stripe is already registered in the provider map and seeded in the database. Once the env vars are set, customers will see a card form powered by Stripe Elements at checkout.

Without Stripe keys, use the built-in mock payment method instead; Stripe payments fail when STRIPE_SECRET_KEY is unset. Mock payments complete the order immediately without a separate confirmation step.

Shipping Providers

Interface

Defined in src/lib/server/services/shipping/types.ts:

interface ShippingProvider { code: string; // unique code like 'flat_rate' getRates: (order: OrderWithRelations) => Promise<ShippingRate[]>; createShipment: (order: OrderWithRelations) => Promise<ShipmentInfo>; trackShipment?: (trackingNumber: string) => Promise<ShipmentStatus>; }

Adding a Provider

src/lib/server/services/shipping/providers/dhl.ts
export class DhlProvider implements ShippingProvider { code = "dhl"; async getRates(order: OrderWithRelations): Promise<ShippingRate[]> { const rates = await dhlClient.getRates({ from: WAREHOUSE_ADDRESS, to: order.shippingCity, weight: calculateWeight(order) }); return rates.map((rate) => ({ id: rate.serviceCode, name: rate.serviceName, price: rate.totalPrice, // in cents estimatedDeliveryDays: rate.transitDays })); } // ... other methods }

Register it:

src/lib/server/services/shipping/index.ts
import { DhlProvider } from "./providers/dhl"; PROVIDERS.set("dhl", new DhlProvider());

Then add a matching row to the shipping_methods table (the built-in flat_rate method is seeded by drizzle/0002_seed_defaults.sql).

Built-in Providers

Payments

  • Stripe - Full integration with Payment Intents and Stripe Elements
  • Mock - For development/testing (auto-completes orders immediately)

Shipping

  • Flat Rate - Simple flat-rate shipping for development and demos
Last updated on