> ## Documentation Index
> Fetch the complete documentation index at: https://scaleup-c34c4386.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Variantes de Produto

> Como criar variantes de produto com diferentes precos e intervalos de cobranca na Chargefy

Variantes permitem oferecer diferentes niveis de um mesmo produto — por exemplo, planos Basic, Pro e Enterprise — cada um com seus proprios precos e intervalos de cobranca. Na Chargefy, variantes sao representadas como multiplos precos dentro de um unico produto ou como produtos distintos agrupados por metadados.

## Estrategias de modelagem

| Estrategia | Quando usar | Exemplo |
| - | - | - |
| **Multiplos precos em um produto** | Mesmo recurso, intervalos diferentes | Plano Pro mensal (R$ 99,90) e anual (R$ 999,00) |
| **Produtos separados** | Recursos diferentes por nivel | Basic, Pro e Enterprise com funcionalidades distintas |

***

## Passo 1: Criar produto com multiplos precos

O jeito mais simples de criar variantes e adicionar varios precos ao mesmo produto — cada preco representa um intervalo ou valor diferente.

### Via SDK

```typescript theme={null}
const product = await chargefy.products.create({
  name: 'Plataforma SaaS',
  description: 'Ferramenta completa de gestao para empresas',
  prices: [
    // Basic - Mensal
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 4990, // R$ 49,90/mes
      priceCurrency: 'brl',
      recurringInterval: 'month',
      metadata: { tier: 'basic' },
    },
    // Basic - Anual
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 47900, // R$ 479,00/ano (~20% desconto)
      priceCurrency: 'brl',
      recurringInterval: 'year',
      metadata: { tier: 'basic' },
    },
    // Pro - Mensal
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 9990, // R$ 99,90/mes
      priceCurrency: 'brl',
      recurringInterval: 'month',
      metadata: { tier: 'pro' },
    },
    // Pro - Anual
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 95900, // R$ 959,00/ano (~20% desconto)
      priceCurrency: 'brl',
      recurringInterval: 'year',
      metadata: { tier: 'pro' },
    },
    // Enterprise - Mensal
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 29990, // R$ 299,90/mes
      priceCurrency: 'brl',
      recurringInterval: 'month',
      metadata: { tier: 'enterprise' },
    },
    // Enterprise - Anual
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 287900, // R$ 2.879,00/ano (~20% desconto)
      priceCurrency: 'brl',
      recurringInterval: 'year',
      metadata: { tier: 'enterprise' },
    },
  ],
})

console.log('Produto criado:', product.id)
console.log('Total de precos:', product.prices.length)
```

### Via cURL

```bash theme={null}
curl -X POST https://api.chargefy.io/v1/products \
  -H "Authorization: Bearer $CHARGEFY_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Plataforma SaaS",
    "description": "Ferramenta completa de gestao para empresas",
    "prices": [
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 4990,
        "priceCurrency": "brl",
        "recurringInterval": "month",
        "metadata": { "tier": "basic" }
      },
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 47900,
        "priceCurrency": "brl",
        "recurringInterval": "year",
        "metadata": { "tier": "basic" }
      },
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 9990,
        "priceCurrency": "brl",
        "recurringInterval": "month",
        "metadata": { "tier": "pro" }
      },
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 95900,
        "priceCurrency": "brl",
        "recurringInterval": "year",
        "metadata": { "tier": "pro" }
      },
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 29990,
        "priceCurrency": "brl",
        "recurringInterval": "month",
        "metadata": { "tier": "enterprise" }
      },
      {
        "type": "recurring",
        "amountType": "fixed",
        "priceAmount": 287900,
        "priceCurrency": "brl",
        "recurringInterval": "year",
        "metadata": { "tier": "enterprise" }
      }
    ]
  }'
```

***

## Passo 2: Listar variantes de um produto

Para exibir as opcoes ao cliente, busque o produto e agrupe os precos por tier e intervalo.

### Via SDK

```typescript theme={null}
const product = await chargefy.products.get('prod_xxxx')

// Agrupar precos por tier
const tiers = product.prices.reduce((acc, price) => {
  const tier = price.metadata?.tier || 'default'
  if (!acc[tier]) acc[tier] = []
  acc[tier].push({
    id: price.id,
    amount: price.priceAmount,
    formatted: `R$ ${(price.priceAmount / 100).toFixed(2)}`,
    interval: price.recurringInterval,
  })
  return acc
}, {} as Record<string, any[]>)

console.log('Variantes:', JSON.stringify(tiers, null, 2))
// {
//   "basic": [
//     { "id": "price_xxx", "formatted": "R$ 49,90", "interval": "month" },
//     { "id": "price_yyy", "formatted": "R$ 479,00", "interval": "year" }
//   ],
//   "pro": [...],
//   "enterprise": [...]
// }
```

***

## Passo 3: Criar checkout para uma variante

O checkout e criado usando o `productPriceId` da variante escolhida pelo cliente.

```typescript theme={null}
// Cliente escolheu: Pro Anual
const checkout = await chargefy.checkouts.create({
  productPriceId: 'price_pro_anual_xxxx',
  customerEmail: 'cliente@empresa.com',
  successUrl: 'https://meuapp.com.br/assinatura/sucesso',
})

console.log('Checkout URL:', checkout.url)
```

***

## Exemplo completo: Tabela de precos React

```tsx src/components/PricingTable.tsx theme={null}
import { useState, useEffect } from 'react'

interface Price {
  id: string
  amount: number
  formatted: string
  interval: string
}

interface Tier {
  name: string
  key: string
  description: string
  features: string[]
  prices: Price[]
  highlighted?: boolean
}

const TIER_CONFIG: Record<string, Omit<Tier, 'prices'>> = {
  basic: {
    name: 'Basic',
    key: 'basic',
    description: 'Para profissionais autonomos',
    features: ['1 usuario', '1.000 transacoes/mes', 'Suporte por email', 'Relatorios basicos'],
  },
  pro: {
    name: 'Pro',
    key: 'pro',
    description: 'Para pequenas e medias empresas',
    features: ['Ate 10 usuarios', '10.000 transacoes/mes', 'Suporte prioritario', 'Relatorios avancados', 'API completa'],
    highlighted: true,
  },
  enterprise: {
    name: 'Enterprise',
    key: 'enterprise',
    description: 'Para grandes operacoes',
    features: ['Usuarios ilimitados', 'Transacoes ilimitadas', 'Suporte dedicado', 'SLA 99,9%', 'API completa', 'Webhooks customizados'],
  },
}

export function PricingTable() {
  const [tiers, setTiers] = useState<Tier[]>([])
  const [billingInterval, setBillingInterval] = useState<'month' | 'year'>('month')
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    fetch('/api/products/prod_xxxx')
      .then(r => r.json())
      .then(product => {
        // Agrupar precos por tier
        const grouped: Record<string, Price[]> = {}
        for (const price of product.prices) {
          const tier = price.metadata?.tier || 'default'
          if (!grouped[tier]) grouped[tier] = []
          grouped[tier].push({
            id: price.id,
            amount: price.priceAmount,
            formatted: `R$ ${(price.priceAmount / 100).toFixed(2)}`,
            interval: price.recurringInterval,
          })
        }

        const tierList = Object.entries(TIER_CONFIG).map(([key, config]) => ({
          ...config,
          prices: grouped[key] || [],
        }))

        setTiers(tierList)
        setLoading(false)
      })
  }, [])

  async function handleSubscribe(priceId: string) {
    const res = await fetch('/api/subscriptions/subscribe', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ priceId, customerEmail: 'user@email.com' }),
    })
    const { checkoutUrl } = await res.json()
    window.location.href = checkoutUrl
  }

  if (loading) return <div>Carregando planos...</div>

  return (
    <div>
      <h2 style={{ textAlign: 'center' }}>Escolha seu plano</h2>

      {/* Toggle mensal/anual */}
      <div style={{ display: 'flex', justifyContent: 'center', gap: '0.5rem', marginBottom: '2rem' }}>
        <button
          onClick={() => setBillingInterval('month')}
          style={{
            padding: '0.5rem 1rem',
            borderRadius: '4px',
            border: '1px solid #d1d5db',
            background: billingInterval === 'month' ? '#2563eb' : 'white',
            color: billingInterval === 'month' ? 'white' : '#374151',
            cursor: 'pointer',
          }}
        >
          Mensal
        </button>
        <button
          onClick={() => setBillingInterval('year')}
          style={{
            padding: '0.5rem 1rem',
            borderRadius: '4px',
            border: '1px solid #d1d5db',
            background: billingInterval === 'year' ? '#2563eb' : 'white',
            color: billingInterval === 'year' ? 'white' : '#374151',
            cursor: 'pointer',
          }}
        >
          Anual <span style={{ fontSize: '0.75rem' }}>(-20%)</span>
        </button>
      </div>

      {/* Cards de planos */}
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '1.5rem', maxWidth: '900px', margin: '0 auto' }}>
        {tiers.map(tier => {
          const price = tier.prices.find(p => p.interval === billingInterval)
          if (!price) return null

          return (
            <div
              key={tier.key}
              style={{
                border: tier.highlighted ? '2px solid #2563eb' : '1px solid #e5e7eb',
                borderRadius: '12px',
                padding: '2rem',
                position: 'relative',
              }}
            >
              {tier.highlighted && (
                <span style={{
                  position: 'absolute', top: '-12px', left: '50%', transform: 'translateX(-50%)',
                  background: '#2563eb', color: 'white', padding: '2px 12px', borderRadius: '12px', fontSize: '0.75rem',
                }}>
                  Mais popular
                </span>
              )}

              <h3>{tier.name}</h3>
              <p style={{ color: '#6b7280', fontSize: '0.875rem' }}>{tier.description}</p>

              <p style={{ fontSize: '2rem', fontWeight: 'bold', margin: '1rem 0' }}>
                {price.formatted}
                <span style={{ fontSize: '1rem', fontWeight: 'normal', color: '#6b7280' }}>
                  /{billingInterval === 'month' ? 'mes' : 'ano'}
                </span>
              </p>

              <button
                onClick={() => handleSubscribe(price.id)}
                style={{
                  width: '100%', padding: '0.75rem',
                  background: tier.highlighted ? '#2563eb' : 'white',
                  color: tier.highlighted ? 'white' : '#2563eb',
                  border: '1px solid #2563eb', borderRadius: '6px', cursor: 'pointer',
                }}
              >
                Assinar {tier.name}
              </button>

              <ul style={{ marginTop: '1.5rem', listStyle: 'none', padding: 0 }}>
                {tier.features.map(feature => (
                  <li key={feature} style={{ padding: '0.25rem 0', fontSize: '0.875rem' }}>
                    {feature}
                  </li>
                ))}
              </ul>
            </div>
          )
        })}
      </div>
    </div>
  )
}
```

***

## Adicionar novas variantes a um produto existente

```typescript theme={null}
// Adicionar um preco trimestral ao produto existente
const updatedProduct = await chargefy.products.update('prod_xxxx', {
  prices: [
    // Manter precos existentes (pelo ID)
    { id: 'price_basic_mensal_xxxx' },
    { id: 'price_basic_anual_xxxx' },
    // Adicionar novo preco
    {
      type: 'recurring',
      amountType: 'fixed',
      priceAmount: 12990, // R$ 129,90/trimestre
      priceCurrency: 'brl',
      recurringInterval: 'quarter',
      metadata: { tier: 'basic' },
    },
  ],
})
```

> [!WARNING]
>
> Ao atualizar precos de um produto, sempre inclua os IDs dos precos existentes que deseja manter. Precos nao listados serao arquivados.

***

## Boas praticas

* **Use metadata** para categorizar precos por tier, facilitando a filtragem no frontend
* **Ofereça desconto anual** de 15-20% para incentivar compromissos mais longos
* **Destaque o plano mais popular** visualmente para guiar a decisao do cliente
* **Mantenha no maximo 3-4 tiers** para evitar paralisia de escolha

***

## Proximos passos

> [card] [Upgrade de Assinatura](https://scaleup-c34c4386.mintlify.site/guides/subscription-upgrades.md)
>
> Permita que clientes troquem entre variantes.

> [card] [Precificacao por Assento](https://scaleup-c34c4386.mintlify.site/guides/seat-based-pricing.md)
>
> Combine variantes com cobranca por assento.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.