UNPKG

prices-as-code

Version:

Prices as Code (PaC) - Define your product pricing schemas with type-safe definitions

565 lines (516 loc) 20.5 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Configuration File - Prices as Code</title> <meta name="description" content="Learn about the configuration file format for Prices as Code"> <link rel="stylesheet" href="../assets/css/main.css"> <link rel="icon" href="https://raw.githubusercontent.com/wickdninja/assets/refs/heads/main/PaC.webp"> </head> <body> <header class="site-header"> <div class="container"> <div class="header-content"> <div class="logo"> <a href="../index.html"> <img src="https://raw.githubusercontent.com/wickdninja/assets/refs/heads/main/PaC.webp" alt="Prices as Code" width="40"> <span>Prices as Code</span> </a> </div> <nav class="main-nav"> <ul> <li><a href="index.html">Guides</a></li> <li><a href="../api/index.html">API</a></li> <li><a href="../providers/index.html">Providers</a></li> <li><a href="https://github.com/wickdninja/prices-as-code" target="_blank">GitHub</a></li> <li><a href="https://www.npmjs.com/package/prices-as-code" target="_blank">NPM</a></li> </ul> </nav> </div> </div> </header> <main class="content"> <div class="container"> <h1>Configuration File Format</h1> <span class="badge">Updated for v3.0.0</span> <p>The Prices as Code configuration file is where you define your products and pricing structures. This guide explains the configuration format in detail and provides examples for both TypeScript and YAML formats.</p> <div class="whats-new"> <h2>Version 3.0.0 Updates</h2> <ul> <li><strong>Simplified Provider Support:</strong> Now focuses exclusively on Stripe integration</li> <li><strong>Enhanced Sample Configurations:</strong> More comprehensive example files included</li> <li><strong>Improved Type Safety:</strong> Better TypeScript type definitions and validation</li> </ul> </div> <h2>File Formats</h2> <p>Prices as Code supports both TypeScript/JavaScript and YAML configuration files:</p> <ul> <li><code>.ts</code>, <code>.js</code> - TypeScript/JavaScript configuration</li> <li><code>.yml</code>, <code>.yaml</code> - YAML configuration</li> </ul> <h2>Configuration Structure</h2> <div class="tabs"> <div class="tab active" onclick="showTab('ts')">TypeScript</div> <div class="tab" onclick="showTab('yaml')">YAML</div> </div> <div id="ts-tab" class="tab-content"> <p>Every configuration file has two main sections: <code>products</code> and <code>prices</code>:</p> <div class="highlight"> <pre><code class="language-typescript">// TypeScript example import { Config } from 'prices-as-code'; const config: Config = { products: [ // Product definitions ], prices: [ // Price definitions ] }; export default config;</code></pre> </div> </div> <div id="yaml-tab" class="tab-content" style="display: none;"> <p>Every configuration file has two main sections: <code>products</code> and <code>prices</code>:</p> <div class="highlight"> <pre><code class="language-yaml"># YAML example products: - # First product definition - # Second product definition prices: - # First price definition - # Second price definition</code></pre> </div> </div> <h2>Products Configuration</h2> <p>The <code>products</code> section defines your product offerings with the following properties:</p> <div class="table-responsive"> <table> <thead> <tr> <th>Property</th> <th>Type</th> <th>Required</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code>provider</code></td> <td>string</td> <td>Yes</td> <td>The payment provider (e.g., 'stripe')</td> </tr> <tr> <td><code>name</code></td> <td>string</td> <td>Yes</td> <td>The product name</td> </tr> <tr> <td><code>description</code></td> <td>string</td> <td>No</td> <td>A description of the product</td> </tr> <tr> <td><code>features</code></td> <td>string[]</td> <td>No</td> <td>Array of feature descriptions for the product</td> </tr> <tr> <td><code>highlight</code></td> <td>boolean</td> <td>No</td> <td>Whether to highlight this product in UI (e.g., as a recommended option)</td> </tr> <tr> <td><code>metadata</code></td> <td>object</td> <td>No</td> <td>Custom metadata for the product</td> </tr> <tr> <td><code>key</code></td> <td>string</td> <td>No</td> <td>Unique identifier for referencing this product (auto-generated if not provided)</td> </tr> <tr> <td><code>id</code></td> <td>string</td> <td>No</td> <td>Provider-specific ID (populated after syncing)</td> </tr> </tbody> </table> </div> <h3>Product Example</h3> <div class="tabs"> <div class="tab active" onclick="showTab('product-ts')">TypeScript</div> <div class="tab" onclick="showTab('product-yaml')">YAML</div> </div> <div id="product-ts-tab" class="tab-content"> <div class="highlight"> <pre><code class="language-typescript">// TypeScript example { provider: "stripe", name: "Pro Plan", description: "For growing businesses", features: [ "Unlimited projects", "100GB storage", "Priority support", "Advanced analytics" ], highlight: true, metadata: { icon: "Star", color: "purple", displayOrder: 2, }, key: "pro" }</code></pre> </div> </div> <div id="product-yaml-tab" class="tab-content" style="display: none;"> <div class="highlight"> <pre><code class="language-yaml"># YAML example - provider: stripe name: Pro Plan description: For growing businesses features: - Unlimited projects - 100GB storage - Priority support - Advanced analytics highlight: true metadata: icon: Star color: purple displayOrder: 2 key: pro</code></pre> </div> </div> <h2>Prices Configuration</h2> <p>The <code>prices</code> section defines the pricing structure for your products with the following properties:</p> <div class="table-responsive"> <table> <thead> <tr> <th>Property</th> <th>Type</th> <th>Required</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code>provider</code></td> <td>string</td> <td>Yes</td> <td>The payment provider (e.g., 'stripe')</td> </tr> <tr> <td><code>name</code></td> <td>string</td> <td>Yes</td> <td>The name of the price</td> </tr> <tr> <td><code>nickname</code></td> <td>string</td> <td>No</td> <td>A shorter name for display purposes</td> </tr> <tr> <td><code>unitAmount</code></td> <td>number</td> <td>Yes</td> <td>The amount in smallest currency units (e.g., cents for USD)</td> </tr> <tr> <td><code>currency</code></td> <td>string</td> <td>Yes</td> <td>The three-letter currency code (e.g., 'usd', 'eur')</td> </tr> <tr> <td><code>type</code></td> <td>string</td> <td>Yes</td> <td>Price type ('recurring' or 'one_time')</td> </tr> <tr> <td><code>recurring</code></td> <td>object</td> <td>Conditionally</td> <td>Required if type is 'recurring'</td> </tr> <tr> <td><code>productKey</code></td> <td>string</td> <td>Yes</td> <td>The key that links to a product</td> </tr> <tr> <td><code>metadata</code></td> <td>object</td> <td>No</td> <td>Custom metadata for the price</td> </tr> <tr> <td><code>key</code></td> <td>string</td> <td>No</td> <td>Unique identifier for this price (auto-generated if not provided)</td> </tr> <tr> <td><code>id</code></td> <td>string</td> <td>No</td> <td>Provider-specific ID (populated after syncing)</td> </tr> <tr> <td><code>active</code></td> <td>boolean</td> <td>No</td> <td>Whether the price is active (default: true)</td> </tr> </tbody> </table> </div> <h3>Recurring Object Properties</h3> <div class="table-responsive"> <table> <thead> <tr> <th>Property</th> <th>Type</th> <th>Required</th> <th>Description</th> </tr> </thead> <tbody> <tr> <td><code>interval</code></td> <td>string</td> <td>Yes</td> <td>Billing interval ('day', 'week', 'month', or 'year')</td> </tr> <tr> <td><code>intervalCount</code></td> <td>number</td> <td>No</td> <td>Number of intervals between billings (default: 1)</td> </tr> </tbody> </table> </div> <h3>Price Example</h3> <div class="tabs"> <div class="tab active" onclick="showTab('price-ts')">TypeScript</div> <div class="tab" onclick="showTab('price-yaml')">YAML</div> </div> <div id="price-ts-tab" class="tab-content"> <div class="highlight"> <pre><code class="language-typescript">// TypeScript example { provider: "stripe", name: "Pro Monthly", nickname: "Pro Monthly", unitAmount: 1999, // $19.99 currency: "usd", type: "recurring", recurring: { interval: "month", intervalCount: 1, }, productKey: "pro", metadata: { plan_code: "pro_monthly", display_price: "$19.99", }, active: true }</code></pre> </div> </div> <div id="price-yaml-tab" class="tab-content" style="display: none;"> <div class="highlight"> <pre><code class="language-yaml"># YAML example - provider: stripe name: Pro Monthly nickname: Pro Monthly unitAmount: 1999 currency: usd type: recurring recurring: interval: month intervalCount: 1 productKey: pro metadata: plan_code: pro_monthly display_price: "$19.99" active: true</code></pre> </div> </div> <h2>Key Generation and Mapping</h2> <p>Prices as Code automatically generates keys for products and prices if they're not explicitly provided:</p> <ul> <li>For <strong>products</strong>, a key is typically derived from the product name (e.g., "Pro Plan" becomes "pro")</li> <li>For <strong>prices</strong>, keys are auto-generated based on the price name and a timestamp</li> <li>The <code>productKey</code> in prices refers to the <code>key</code> of a product, forming a relationship between them</li> </ul> <h2>Metadata</h2> <p>Both products and prices support a <code>metadata</code> field for adding custom attributes. This is useful for:</p> <ul> <li>UI display preferences (order, highlighting, icons, colors, etc.)</li> <li>Feature flags</li> <li>Integration with other systems</li> <li>Any other custom data you need to associate with products or prices</li> </ul> <div class="note"> <p>Metadata is highly flexible and can contain any valid JSON data. Stripe limits metadata to strings, so PaC will convert non-string values automatically when syncing with Stripe.</p> </div> <h2>Sample Configuration</h2> <div class="sample-config"> <h3>Real-World Example</h3> <p>Here's a comprehensive example based on a tiered subscription model:</p> <div class="highlight"> <pre><code class="language-yaml">products: - name: Free description: Start your learning journey metadata: icon: Book color: blue key: free features: - Access to free content - Limited features - Core lessons - Ad-supported experience highlight: false provider: stripe key: free - name: Pro description: Help us shine bright with new features metadata: icon: Star color: purple key: pro features: - Support ongoing development - Supporter recognition - Early access to new features - Ad-free experience - Unlimited access highlight: true provider: stripe key: pro - name: Ultra description: The ultimate experience metadata: icon: Trophy color: amber key: ultra features: - All Pro perks - Ultra member recognition - Input on future features - Priority support - Personalized plans highlight: false provider: stripe key: ultra prices: - name: Free unitAmount: 0 currency: usd type: recurring recurring: interval: year intervalCount: 1 active: true metadata: plan_code: free display_price: $0 nickname: Free plan provider: stripe productKey: free - name: Pro Monthly unitAmount: 1000 currency: usd type: recurring recurring: interval: month intervalCount: 1 active: true metadata: plan_code: pro_monthly display_price: $10 nickname: Pro Monthly Plan provider: stripe productKey: pro - name: Pro Yearly unitAmount: 9600 currency: usd type: recurring recurring: interval: year intervalCount: 1 active: true metadata: plan_code: pro_yearly display_price: $96 nickname: Pro Yearly Plan provider: stripe productKey: pro</code></pre> </div> </div> <h2>Next Steps</h2> <ul> <li>Learn how to use the <a href="cli.html">Command-Line Interface</a></li> <li>Set up <a href="ci-cd.html">CI/CD Integration</a> for automated pricing updates</li> <li>Explore <a href="metadata.html">Working with Metadata</a> for enhanced flexibility</li> <li>Understand how to implement <a href="custom-providers.html">Custom Providers</a> beyond Stripe</li> </ul> </div> </main> <footer class="site-footer"> <div class="container"> <div class="footer-content"> <p>Copyright &copy; 2025 Nate Ross. Distributed by an <a href="https://github.com/wickdninja/prices-as-code/blob/main/LICENSE">MIT license.</a></p> <p><a href="#top" class="back-to-top">Back to top</a></p> </div> </div> </footer> <script src="../assets/js/main.js"></script> <script> function showTab(tabId) { // Find the tab section containing this tab const tabContent = document.getElementById(tabId + '-tab'); if (!tabContent) return; // Find the parent content area that holds these tabs const tabSection = tabContent.parentElement; // Hide all tab contents in this section const tabContents = tabSection.querySelectorAll('.tab-content'); tabContents.forEach(tab => { tab.style.display = 'none'; }); // Show the selected tab content tabContent.style.display = 'block'; // Update active tab styling // Find the tab nav that is in the same section const tabs = tabSection.querySelectorAll('.tab'); tabs.forEach(tab => { if (tab.getAttribute('onclick').includes(tabId)) { tab.classList.add('active'); } else { tab.classList.remove('active'); } }); } </script> </body> </html>