> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waffo.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Products

> One-time or recurring. Your revenue, your rules.

## Product = Billing Object

In Waffo Pancake, a **product** is the object used for checkout, taxation, and reporting. It is the commercial offer you charge for, not just a storefront card.

<Note>
  For professional use, think of products as billing entities:

  * a fixed-price offer
  * a subscription plan
  * or a base product used with dynamic pricing at checkout
</Note>

***

## Core Models

<CardGroup cols={3}>
  <Card title="One-Time" icon="cart-shopping">
    Customer pays once for a predefined offer.

    * Digital downloads
    * Lifetime licenses
    * Templates, courses, assets
  </Card>

  <Card title="Subscription" icon="repeat">
    Customer is billed on a recurring schedule.

    * SaaS plans
    * Memberships
    * Service retainers
  </Card>

  <Card title="Dynamic Pricing" icon="slider">
    Amount is calculated at checkout time.

    * Usage overage
    * Credit top-ups
    * Negotiated quotes
  </Card>
</CardGroup>

***

## Create a Product

Dashboard --> Products --> **Create Product**

```json theme={"system"}
{
  "storeId": "your-store-uuid",
  "name": "Pro Plan",
  "prices": {
    "USD": { "amount": "29.00", "taxIncluded": false, "taxCategory": "saas" }
  }
}
```

**Done.** You get a permanent purchase link for fixed-price selling, or a reusable billing object for programmatic checkout.

***

## Product Fields

### Required

| Field        | What It Is                          |
| ------------ | ----------------------------------- |
| Name         | What customers see                  |
| Price        | How much you charge                 |
| Currency     | USD, EUR, GBP, CNY, JPY, HKD, etc.  |
| Type         | One-time or Subscription            |
| Tax Category | SaaS, Digital Goods, Software, etc. |

### Optional

| Field        | Default | Purpose                                                                                                               |
| ------------ | ------- | --------------------------------------------------------------------------------------------------------------------- |
| Description  | —       | Markdown. Sell your product.                                                                                          |
| Image        | —       | 400x400px recommended                                                                                                 |
| Redirect URL | —       | Where the customer lands after checkout. Used for both successful and failed payments — only one URL is configurable. |

### Price Limits

Each currency has a minimum and maximum price you can set on a product. Values outside this range are rejected when you save the product.

| Currency |  Minimum |       Maximum |
| -------- | -------: | ------------: |
| USD      |   \$1.00 |    \$7,500.00 |
| EUR      |    €1.00 |     €7,400.00 |
| GBP      |    £1.00 |     £6,400.00 |
| JPY      |     ¥100 |    ¥1,250,000 |
| HKD      | HK\$8.00 | HK\$61,000.00 |

<Note>
  CNY is available for display in your dashboard analytics, but cannot currently be used as a product pricing currency.
</Note>

***

## Dynamic Pricing

Dynamic pricing is the right model when the final amount is not known until runtime.

Examples:

* usage-based overage billing
* prepaid credit packs with variable size
* contract-specific quotes
* temporary discounts calculated on your server

### How It Works

1. Create a **base one-time product** in Waffo Pancake
2. Calculate the final amount on your server
3. Pass `priceSnapshot` when creating the checkout session

```typescript theme={"system"}
const session = await client.checkout.createSession({
  storeId: "store_id",
  productId: "usage-overage-product-id",
  productType: "onetime",
  currency: "USD",
  priceSnapshot: {
    amount: calculatedAmount,
    taxIncluded: false,
    taxCategory: "saas",
  },
});
```

<Warning>
  `priceSnapshot` overrides the stored product price for that checkout session. Use it only from your server, never from untrusted client code.
</Warning>

<Tip>
  If the amount is event-based, keep it as a one-time charge even if the customer is already on a subscription.
</Tip>

***

## Free Trials

Let customers try subscription products before they buy.

### Trial Abuse Protection

Waffo Pancake automatically tracks consumer trial history at the platform level. When a consumer starts a new subscription, the platform calculates the maximum available trial days based on their history — preventing repeated trial abuse without any effort from the merchant.

Merchants can also pass `requested_trial_days` via the API to shorten or skip the trial for specific customers.

<Warning>
  Effective trial abuse prevention requires `buyerIdentity`. Use [authenticated checkout](/integrate/sdks#authenticated-checkout-recommended) to ensure each buyer can only claim one trial per product.
</Warning>

***

## Billing Intervals

| Interval  | When            | Best For            |
| --------- | --------------- | ------------------- |
| Weekly    | Every 7 days    | High-usage products |
| Monthly   | Every month     | Standard SaaS       |
| Quarterly | Every 3 months  | B2B software        |
| Yearly    | Every 12 months | Committed customers |

<Tip>
  Annual plans with 15-20% discount = lower churn + better cash flow.
</Tip>

***

## Product Purchase Links

Every product gets a permanent purchase link that never expires:

```
https://checkout.waffo.ai/{store-slug}/{product-slug}
```

Test mode:

```
https://checkout.waffo.ai/{store-slug}/{product-slug}/test
```

**Add to your website:**

* Website button
* Twitter bio
* Email signature
* Discord server

**Key benefits:**

* Link is permanent — it stays the same even when you update product details
* No session or token management needed
* A checkout session is created automatically when the customer opens the link

**Getting your link:**

* **Dashboard**: Click "Copy Link" on any product
* **API**: For advanced use cases, create a Checkout Session via API with custom parameters (dynamic link, 7-day TTL)

**Test vs Live:**

* Toggle Test Mode in Dashboard header to preview with test links
* Test links use the `/test` suffix

***

## Product Status

<CardGroup cols={2}>
  <Card title="Active" icon="check">
    Live. Customers can buy.
  </Card>

  <Card title="Inactive" icon="pause">
    Hidden. Existing subscriptions continue.
  </Card>
</CardGroup>

***

## Updating Products

Products use **immutable versioning**:

<Warning>
  Updates create new versions. Existing subscriptions keep their original version.
</Warning>

| Field            | Impact                       |
| ---------------- | ---------------------------- |
| Name/Description | Creates new version          |
| Image            | Creates new version          |
| Price            | New purchases only           |
| Interval         | Cannot change after creation |

### Environment Sync

Publish product versions from test to production:

```bash theme={"system"}
POST /v1/actions/onetime-product/publish-product
{
  "id": "product-id"
}
```

<Note>
  Publishing is one-way (test → prod) and only needed for the first publish.
</Note>

***

## Best Practices

<AccordionGroup>
  <Accordion title="Naming">
    Include billing period:

    * "Pro Plan - Monthly"
    * "Pro Plan - Annual (Save 20%)"
  </Accordion>

  <Accordion title="Pricing">
    * Round numbers ($29, not $28.73)
    * Annual discount (15-20%)
    * Research competitors
  </Accordion>

  <Accordion title="Images">
    * 400x400px minimum
    * PNG or JPG
    * Under 2MB
  </Accordion>
</AccordionGroup>
