Skip to main content
Dynamic pricing allows you to offer variable pricing for your products without creating multiple product entries. By enabling Pay What You Want (PWYW) on a single product, you can set minimum and maximum price bounds, then pass dynamic amounts when creating checkout session links. This approach is ideal when you need:
  • Variable pricing without managing multiple products
  • Customer-driven pricing where buyers choose their amount
  • Programmatic price control where you set the amount dynamically via API
  • Flexible pricing models for digital products, donations, or experimental launches
Pay What You Want is only available for Single Payment (one-time) products. It cannot be used with subscription products.

How It Works

With Pay What You Want enabled, you can:
  1. Set price bounds: Define a minimum price (required) and optionally a maximum price
  2. Pass dynamic amounts: Include an amount field in the product cart when creating checkout sessions
  3. Let customers choose: If no amount is provided, customers can enter their own price (within your bounds)
When you pass an amount in the product cart, that amount is used for the checkout. If you omit the amount field, customers can select their own price during checkout (subject to your minimum/maximum settings).

Step 1: Create a Product with Pay What You Want

First, create a one-time product in your Dodo Payments dashboard and enable Pay What You Want pricing.
1

Create a new product

Navigate to Products in your Dodo Payments dashboard and click Add Product.
2

Configure product details

Fill in the required product information:
  • Product Name: Display name for your product
  • Product Description: Clear description of what customers are purchasing
  • Product Image: Upload an image (PNG/JPG/WebP, up to 3 MB)
  • Tax Category: Select the appropriate tax category
3

Set pricing type

Select Pricing Type as Single Payment (one-time payment).
4

Enable Pay What You Want

In the Pricing section, enable the Pay What You Want toggle.
5

Set minimum price

Enter the Minimum Price that customers must pay. This is required and ensures you maintain a revenue floor.Example: If your minimum is $5.00, enter 5.00 (or 500 cents).
6

Set maximum price (optional)

Optionally, set a Maximum Price to cap the amount customers can pay.
7

Set suggested price (optional)

Optionally, enter a Suggested Price that will be displayed to guide customers. This helps anchor expectations and can improve average order value.
8

Save the product

Click Add Product to save. Note your product ID (e.g., pdt_123abc456def) for use in checkout sessions.
You can find your product ID in the dashboard under ProductsView Details, or by using the List Products API.

Step 2: Create Checkout Sessions with Dynamic Pricing

Once your product is configured with Pay What You Want, you can create checkout sessions with dynamic amounts. The amount field in the product cart allows you to set the price programmatically for each checkout session.

Understanding the Amount Field

When creating a checkout session, you can include an amount field in each product cart item:
  • If amount is provided: The checkout uses this exact amount (must be within your minimum/maximum bounds)
  • If amount is omitted: Customers can enter their own price during checkout (within your bounds)
The amount field is only applicable for Pay What You Want products. For regular products, this field is ignored.

Code Examples

import DodoPayments from 'dodopayments';

// Initialize the Dodo Payments client
const client = new DodoPayments({
  bearerToken: process.env.DODO_PAYMENTS_API_KEY,
});

async function createDynamicPricingCheckout(
  productId: string,
  amountInCents: number,
  returnUrl: string
) {
  try {
    const session = await client.checkoutSessions.create({
      product_cart: [
        {
          product_id: productId,
          quantity: 1,
          // Dynamic amount in cents (e.g., 1500 = $15.00)
          amount: amountInCents
        }
      ],
      return_url: returnUrl,
      // Optional: Pre-fill customer information
      customer: {
        email: 'customer@example.com',
        name: 'John Doe'
      },
      // Optional: Add metadata for tracking
      metadata: {
        order_id: 'order_123',
        pricing_tier: 'custom'
      }
    });

    console.log('Checkout URL:', session.checkout_url);
    console.log('Session ID:', session.session_id);
    
    return session;
  } catch (error) {
    console.error('Failed to create checkout session:', error);
    throw error;
  }
}

// Example: Create checkout with $25.00 (2500 cents)
const session = await createDynamicPricingCheckout(
  'prod_123abc456def',
  2500, // $25.00 in cents
  'https://yoursite.com/checkout/success'
);

// Example: Create checkout with $10.00 (1000 cents)
const session2 = await createDynamicPricingCheckout(
  'prod_123abc456def',
  1000, // $10.00 in cents
  'https://yoursite.com/checkout/success'
);
Amount Format: The amount field must be in the lowest denomination of the currency. For USD, this means cents (e.g., $25.00 = 2500). For other currencies, use the smallest unit (e.g., paise for INR).

Step 3: Let Customers Choose Their Price

If you want customers to select their own price during checkout, simply omit the amount field from the product cart. The checkout page will display an input field where customers can enter any amount within your minimum and maximum bounds.
async function createCustomerChoiceCheckout(
  productId: string,
  returnUrl: string
) {
  try {
    const session = await client.checkoutSessions.create({
      product_cart: [
        {
          product_id: productId,
          quantity: 1
          // No amount field - customer will choose their price
        }
      ],
      return_url: returnUrl,
      customer: {
        email: 'customer@example.com',
        name: 'John Doe'
      }
    });

    return session;
  } catch (error) {
    console.error('Failed to create checkout session:', error);
    throw error;
  }
}

Common Use Cases

Use Case 1: Tiered Pricing Based on User Type

Offer different prices to different customer segments using the same product:
// Student discount: $10.00
const studentSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  1000, // $10.00
  'https://yoursite.com/success'
);

// Regular price: $25.00
const regularSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  2500, // $25.00
  'https://yoursite.com/success'
);

// Premium price: $50.00
const premiumSession = await createDynamicPricingCheckout(
  'prod_123abc456def',
  5000, // $50.00
  'https://yoursite.com/success'
);

Use Case 2: Dynamic Pricing Based on Quantity

Adjust price based on quantity purchased:
async function createQuantityBasedCheckout(
  productId: string,
  quantity: number
) {
  // Base price: $20.00 per unit
  // Discount: 10% for 2+ items, 20% for 5+ items
  const basePrice = 2000; // $20.00 in cents
  let discount = 0;
  
  if (quantity >= 5) {
    discount = 0.20; // 20% off
  } else if (quantity >= 2) {
    discount = 0.10; // 10% off
  }
  
  const totalAmount = Math.round(basePrice * quantity * (1 - discount));
  
  const session = await client.checkoutSessions.create({
    product_cart: [
      {
        product_id: productId,
        quantity: quantity,
        amount: totalAmount
      }
    ],
    return_url: 'https://yoursite.com/success'
  });
  
  return session;
}

Use Case 3: Time-Based or Promotional Pricing

Apply promotional pricing during specific periods:
async function createPromotionalCheckout(productId: string) {
  const isPromoActive = checkIfPromotionActive(); // Your logic
  const regularPrice = 3000; // $30.00
  const promoPrice = 2000; // $20.00
  
  const amount = isPromoActive ? promoPrice : regularPrice;
  
  const session = await client.checkoutSessions.create({
    product_cart: [
      {
        product_id: productId,
        quantity: 1,
        amount: amount
      }
    ],
    return_url: 'https://yoursite.com/success',
    metadata: {
      pricing_type: isPromoActive ? 'promotional' : 'regular'
    }
  });
  
  return session;
}

Best Practices

Set Reasonable Bounds

Choose a minimum price that covers your costs while remaining accessible. Use a suggested price to guide customer expectations.

Validate Amounts

Always validate that dynamic amounts fall within your product’s minimum and maximum bounds before creating checkout sessions.

Track Pricing Decisions

Use metadata to track why specific amounts were chosen (e.g., pricing_tier, discount_code, user_segment).

Handle Edge Cases

Ensure your application handles cases where amounts exceed maximum bounds or fall below minimums gracefully.

Validation and Error Handling

Always validate amounts against your product’s minimum and maximum settings:
async function createValidatedCheckout(
  productId: string,
  amountInCents: number,
  minAmount: number,
  maxAmount: number | null
) {
  // Validate minimum
  if (amountInCents < minAmount) {
    throw new Error(
      `Amount ${amountInCents} is below minimum ${minAmount}`
    );
  }
  
  // Validate maximum (if set)
  if (maxAmount !== null && amountInCents > maxAmount) {
    throw new Error(
      `Amount ${amountInCents} exceeds maximum ${maxAmount}`
    );
  }
  
  // Create checkout session
  return await client.checkoutSessions.create({
    product_cart: [
      {
        product_id: productId,
        quantity: 1,
        amount: amountInCents
      }
    ],
    return_url: 'https://yoursite.com/success'
  });
}

API Reference

Troubleshooting

If your amount field is being ignored, verify that:
  • The product has Pay What You Want enabled in the dashboard
  • The product is a Single Payment (one-time) product, not a subscription
  • The amount is in the correct format (lowest currency denomination, e.g., cents for USD)
The API will reject checkout sessions where the amount violates your product’s price bounds. Always validate amounts before creating checkout sessions, or let customers choose their price by omitting the amount field.
If customers aren’t seeing the price input field, ensure you’ve omitted the amount field from the product cart. When amount is provided, the checkout uses that exact amount.