Define your product pricing schemas with type-safe definitions and synchronize them across multiple providers.
- 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
npm install prices-as-code
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;
# .env file
STRIPE_SECRET_KEY=sk_test_...
npx prices-as-code pricing.ts
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
# 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
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
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();
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();
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();
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 [];
}
}
Visit our documentation website for comprehensive guides and API reference.
- Getting Started
- Push Model
- Pull Model (New in v3.3.0)
- Generate Templates (New in v3.5.0)
- Configuration Format
- Command Line Interface
- Custom Providers
- CI/CD Integration
- Working with Metadata
- Custom Pricing Logic
Managing pricing configurations across multiple systems is challenging. Prices as Code provides:
- Single Source of Truth: Define your pricing once, deploy everywhere
- Type Safety: Catch errors before they happen with TypeScript validation
- Version Control: Track pricing changes alongside your codebase
- CI/CD Integration: Automate pricing updates as part of your deployment pipeline
MIT