prices-as-code
TypeScript icon, indicating that this package has built-in type declarations

3.6.0 • Public • Published

Prices as Code (PaC)

Prices as Code

Define your product pricing schemas with type-safe definitions and synchronize them across multiple providers.

🚀 Features

  • Type-Safe: Use TypeScript and Zod schemas to define your pricing models with full type safety
  • Declarative: Define your products and prices in code, sync them to providers
  • Scaffolding: Generate template pricing structures to quickly get started
  • Bidirectional: Use Push mode to sync local configs to providers, or Pull mode to generate configs from existing providers
  • Idempotent: Run it multiple times, only changes what's needed
  • Push Model: Push your config to different environments without ID conflicts
  • Pull Model: Generate config files from existing provider data to onboard existing customers
  • Metadata Support: Add custom metadata to your products and prices
  • YAML or TypeScript: Define your pricing in either YAML or TypeScript format
  • Extensible: Easily add support for your own billing providers

Installation

npm install prices-as-code

Quick Start

1. Create a pricing configuration file (pricing.ts)

import { Config } from "prices-as-code";

const config: Config = {
  products: [
    {
      provider: "stripe",
      name: "Basic Plan",
      description: "For individuals and small teams",
      features: ["5 projects", "10GB storage", "Email support"],
      highlight: false,
      metadata: {
        displayOrder: 1,
      },
    },
    {
      provider: "stripe",
      name: "Pro Plan",
      description: "For growing businesses",
      features: ["Unlimited projects", "100GB storage", "Priority support"],
      highlight: true,
      metadata: {
        displayOrder: 2,
      },
    },
  ],
  prices: [
    {
      provider: "stripe",
      name: "Basic Monthly",
      nickname: "Basic Monthly",
      unitAmount: 999, // $9.99
      currency: "usd",
      type: "recurring",
      recurring: {
        interval: "month",
        intervalCount: 1,
      },
      productKey: "basic_plan",
      metadata: {
        displayName: "Basic Monthly",
      },
    },
    {
      provider: "stripe",
      name: "Pro Monthly",
      nickname: "Pro Monthly",
      unitAmount: 1999, // $19.99
      currency: "usd",
      type: "recurring",
      recurring: {
        interval: "month",
        intervalCount: 1,
      },
      productKey: "pro_plan",
      metadata: {
        displayName: "Pro Monthly",
      },
    },
  ],
};

export default config;

2. Set up environment variables

# .env file
STRIPE_SECRET_KEY=sk_test_...

3. Run the synchronization

npx prices-as-code pricing.ts

CLI Options

prices-as-code [command] [configPath] [options]

Commands:
  sync             Synchronize your pricing schema with provider (default)
  pull             Pull pricing from provider into a local config file
  generate         Generate a template pricing structure

Options:
  --env=<path>          Path to .env file
  --stripe-key=<key>    Stripe API key
  --write-back          Write provider IDs back to config file (only for sync)
  --format=<format>     Output format for 'pull' and 'generate' commands (yaml, json, ts)
  
Generate Options:
  --tiers=<tiers>       Comma-separated list of product tiers (default: basic,pro,enterprise)
  --currency=<cur>      ISO currency code (default: usd)
  --intervals=<int>     Comma-separated list of intervals (default: month,year)
  --no-metadata         Don't include metadata in generated file
  --no-features         Don't include feature lists in generated products

Examples

# Sync local pricing to provider (Push mode)
npx prices-as-code pricing.ts

# Pull provider pricing to local file (Pull mode)
npx prices-as-code pull pricing.yml

# Pull provider pricing with specific format
npx prices-as-code pull --format=ts pricing.ts

# Generate a template pricing structure
npx prices-as-code generate pricing.yml

# Generate with custom tiers and currency
npx prices-as-code generate --tiers=free,basic,pro --currency=eur pricing.yml

Supported Providers

Stripe

The Stripe provider allows you to sync products and prices to your Stripe account.

Required environment variables:

  • STRIPE_SECRET_KEY: Your Stripe secret key
  • STRIPE_API_VERSION (optional): Stripe API version to use

Programmatic Usage

Push Mode (Sync)

import { pac } from "prices-as-code";

async function syncPricing() {
  try {
    const result = await pac({
      configPath: "./pricing.ts",
      providers: [
        {
          provider: "stripe",
          options: {
            secretKey: process.env.STRIPE_SECRET_KEY,
            apiVersion: "2025-02-24",
          },
        },
      ],
      // Set to true to write IDs back to config file (legacy behavior)
      // Default is false (push mode - no writes to config file)
      writeBack: false,
    });

    console.log("Sync result:", result);
  } catch (error) {
    console.error("Sync failed:", error);
  }
}

syncPricing();

Pull Mode (Import)

import { pac } from "prices-as-code";

async function pullPricing() {
  try {
    const result = await pac.pull({
      configPath: "./pricing.yml", // Output file path
      providers: [
        {
          provider: "stripe",
          options: {
            secretKey: process.env.STRIPE_SECRET_KEY,
          },
        },
      ],
      format: "yaml", // 'yaml', 'json', or 'ts'
    });

    console.log("Pull complete:", result);
  } catch (error) {
    console.error("Pull failed:", error);
  }
}

pullPricing();

Generate Mode (Scaffolding)

import { pac } from "prices-as-code";

async function generatePricing() {
  try {
    const result = await pac.generate({
      configPath: "./pricing.yml", // Output file path
      format: "yaml", // 'yaml', 'json', or 'ts'
      provider: "stripe",
      productTiers: ["basic", "pro", "enterprise"], // Custom tiers
      intervals: ["month", "year"], // Billing intervals
      currency: "usd",
      includeMetadata: true,
      includeFeatures: true
    });

    console.log("Template generated:", result);
  } catch (error) {
    console.error("Generation failed:", error);
  }
}

generatePricing();

Adding Your Own Provider

You can extend the library with your own providers by implementing the ProviderClient interface:

import { ProviderClient, Product, Price } from "prices-as-code";

export class MyCustomProvider implements ProviderClient {
  constructor(options: any) {
    // Initialize your provider client
  }

  // Push mode methods - required
  async syncProducts(products: Product[]): Promise<Product[]> {
    // Implement product synchronization
    return products;
  }

  async syncPrices(prices: Price[]): Promise<Price[]> {
    // Implement price synchronization
    return prices;
  }

  // Pull mode methods - required
  async fetchProducts(): Promise<Product[]> {
    // Implement product fetching from provider
    return [];
  }

  async fetchPrices(): Promise<Price[]> {
    // Implement price fetching from provider
    return [];
  }
}

📖 Documentation

Visit our documentation website for comprehensive guides and API reference.

Guides

API Reference

🧩 Why Prices as Code?

Managing pricing configurations across multiple systems is challenging. Prices as Code provides:

  1. Single Source of Truth: Define your pricing once, deploy everywhere
  2. Type Safety: Catch errors before they happen with TypeScript validation
  3. Version Control: Track pricing changes alongside your codebase
  4. CI/CD Integration: Automate pricing updates as part of your deployment pipeline

📄 License

MIT

Package Sidebar

Install

npm i prices-as-code

Weekly Downloads

2

Version

3.6.0

License

MIT

Unpacked Size

424 kB

Total Files

58

Last publish

Collaborators

  • wickdninja