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

# Precios por Asiento con Complementos y Enlaces de Pago

> Aprende a crear complementos para precios por asiento y generar enlaces de pago con cantidades de complementos personalizadas utilizando Dodo Payments

En este tutorial, aprenderás a implementar precios por asiento utilizando los complementos de Dodo Payments. Crearemos un producto de suscripción con complementos para asientos adicionales y te mostraremos cómo generar enlaces de pago con cantidades de complementos personalizadas.

<Note>
  Este tutorial proporciona código de ejemplo para implementar una aplicación Node.js/Express. Puedes modificar este código para tu marco específico (Next.js, React, Vue, etc.) y personalizar la interfaz de usuario según las necesidades de tu aplicación.
</Note>

Al final de este tutorial, sabrás cómo:

* Crear productos de suscripción con precios por asiento
* Configurar complementos para asientos adicionales
* Generar enlaces de pago con cantidades de complementos personalizadas
* Manejar sesiones de pago con conteos de asientos dinámicos

## Lo que Estamos Construyendo

Vamos a crear un modelo de precios por asiento:

* **Plan Base**: \$49/mes para hasta 5 miembros del equipo
* **Complemento por Asiento**: \$2/mes por asiento adicional
* **Enlaces de Pago**: Pago dinámico con cantidades de asientos personalizadas

<Info>
  Antes de comenzar, asegúrate de tener:

  * Una cuenta de Dodo Payments
  * Conocimientos básicos de TypeScript/Node.js
</Info>

## Paso 1: Crea Tu Complemento de Asiento

Ahora necesitamos crear un complemento que represente asientos adicionales. Este complemento se adjuntará a nuestra suscripción base y permitirá a los clientes comprar asientos adicionales.

<Frame>
  <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-addons-creation.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=d2c17b4a9f2f9a1b19f537f0507656a4" alt="Creando producto de suscripción base" style={{ maxHeight: '500px', width: 'auto' }} width="2348" height="1606" data-path="images/cookbooks/seat-based/seat-based-addons-creation.png" />
</Frame>

<Tip>
  **Lo que construiremos**: Un complemento que cuesta \$2/mes por asiento y se puede agregar a cualquier suscripción base.
</Tip>

<Steps>
  <Step title="Navigate to Add-Ons">
    1. En el panel de Dodo Payments, permanece en la sección **Products**
    2. Haz clic en la pestaña **Add-Ons**
    3. Haz clic en **Create Add-On**

    Se abrirá el formulario de creación del complemento.
  </Step>

  <Step title="Enter add-on details">
    Rellena estos valores para nuestro complemento de asientos:

    **Add-On Name**: `Additional Team Seat`

    **Description**: `Add extra team members to your workspace with full access to all features`

    **Price**: Enter → `2.00`

    **Moneda**: Debe coincidir con la moneda de tu suscripción base

    **Categoría de Impuestos**: Selecciona la categoría apropiada para tu producto.
  </Step>

  <Step title="Save your add-on">
    1. Revisa todos tus ajustes:
       * Nombre: Additional Team Seat
       * Precio: \$2.00/mes
    2. Haz clic en **Create Add-On**

    <Check>
      **¡Complemento creado!** Tu complemento de asientos ya está disponible para adjuntarse a suscripciones.
    </Check>
  </Step>
</Steps>

## Paso 2: Crea Tu Producto de Suscripción Base

Comenzaremos creando un producto de suscripción base que incluya 5 miembros del equipo. Esta será la base de nuestro modelo de precios por asiento.

<Frame>
  <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-subscription.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=f17e96f3d106b88b6dc32a00be535620" alt="Creando producto de suscripción base" style={{ maxHeight: '500px', width: 'auto' }} width="2118" height="1580" data-path="images/cookbooks/seat-based/seat-based-subscription.png" />
</Frame>

<Steps>
  <Step title="Navigate to Products">
    1. Inicia sesión en el panel de Dodo Payments
    2. Haz clic en **Products** en la barra lateral izquierda
    3. Haz clic en el botón **Create Product**
    4. Selecciona **Subscription** como tipo de producto

    Deberías ver un formulario donde configuraremos nuestra suscripción base.
  </Step>

  <Step title="Fill in the subscription details">
    Ahora ingresaremos los detalles específicos para nuestro plan base:

    **Product Name**: `Motion`

    **Description**: `Where your team's documentation lives.`

    **Recurring Price**: Enter → `49.00`

    **Billing Cycle**: Select → `Monthly`

    **Currency**: Selecciona tu moneda preferida (p. ej., `USD`)
  </Step>
</Steps>

## Paso 3: Conectar el Complemento a la Suscripción

Ahora necesitamos asociar nuestro complemento de asiento con la suscripción base para que los clientes puedan comprar asientos adicionales durante el pago.

<Steps>
  <Step title="Attach the seat add-on">
    <Frame>
      <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-addons.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=ea4ce0d437201c92590eea6c31a14e80" alt="Adjuntar complemento a la suscripción" style={{ maxHeight: '500px', width: 'auto' }} width="2338" height="1196" data-path="images/cookbooks/seat-based/seat-based-addons.png" />
    </Frame>

    1. Desplázate hacia abajo hasta la sección **Complementos**
    2. Haz clic en **Agregar Complementos**
    3. Desde el menú desplegable, selecciona tu complemento de asiento
    4. Confirma que aparece en la configuración de tu suscripción
  </Step>

  <Step title="Save subscription changes">
    1. Revisa toda la configuración de tu suscripción:
       * Plan base: \$49/mes por 5 asientos
       * Complemento: \$2/mes por asiento adicional
       * Prueba gratuita: 14 días
    2. Haz clic en **Save Changes**

    <Check>
      **¡Precios por asiento configurados!** Los clientes ahora pueden adquirir tu plan base y agregar asientos extra según lo necesiten.
    </Check>
  </Step>
</Steps>

## Paso 4: Generar Enlaces de Pago con Cantidades de Complementos Personalizadas

Ahora vamos a crear una aplicación Express.js que genere enlaces de pago con cantidades de complementos personalizadas. Aquí es donde entra el verdadero poder de los precios por asiento: puedes crear dinámicamente sesiones de pago con cualquier número de asientos adicionales.

<Steps>
  <Step title="Set up your project">
    Crea un nuevo proyecto Node.js e instala las dependencias requeridas:

    ```bash theme={null}
    mkdir seat-based-pricing
    cd seat-based-pricing
    npm init -y
    npm install dodopayments express dotenv
    npm install -D @types/node @types/express typescript ts-node
    ```

    Crea un archivo `tsconfig.json`:

    ```json theme={null}
    {
      "compilerOptions": {
        "target": "ES2020",
        "module": "commonjs",
        "outDir": "./dist",
        "rootDir": "./src",
        "strict": true,
        "esModuleInterop": true,
        "skipLibCheck": true,
        "forceConsistentCasingInFileNames": true
      }
    }
    ```
  </Step>

  <Step title="Create your environment file">
    Crea un archivo `.env` con tu clave de API de Dodo Payments:

    ```bash theme={null}
    DODO_PAYMENTS_API_KEY=your_actual_dodo_api_key_here
    ```

    <Warning>
      Nunca subas tu clave de API al control de versiones. Agrega `.env` a tu archivo `.gitignore`.
    </Warning>
  </Step>

  <Step title="Implement the checkout session creation">
    Crea un archivo `src/server.ts` con el siguiente código:

    <CodeGroup>
      ```typescript server.ts expandable theme={null}
      // Add this new endpoint for dynamic seat quantities
      import 'dotenv/config';
      import DodoPayments from 'dodopayments';
      import express, { Request, Response } from 'express';

      const app = express();

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

      async function createCheckoutSession(seatCount: number) {
        try {
          const session = await client.checkoutSessions.create({
            // Products to sell - use IDs from your Dodo Payments dashboard
            product_cart: [
              {
                product_id: 'pdt_7Rl9OWT2Mz4wwUTKz74iZ', // Replace with your actual product ID
                quantity: 1,
                addons: [
                  {
                    addon_id: 'adn_eKQbNakKrivDpaxmI8wKI', // Replace with your actual addon ID
                    quantity: seatCount
                  }
                ]
              }
            ],
            
            // Pre-fill customer information to reduce friction
            customer: {
              email: 'steve@example.com',
              name: 'Steve Irwin',
            },
            // Where to redirect after successful payment
            return_url: 'https://example.com/checkout/success',
          });

          // Redirect your customer to this URL to complete payment
          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 usage in an Express.js route
      app.post('/create-checkout/:seatCount', async (req: Request, res: Response) => {
        try {
          const seatCount = parseInt(req.params.seatCount);
          const session = await createCheckoutSession(seatCount);
          res.json({ checkout_url: session.checkout_url });
        } catch (error) {
          res.status(500).json({ error: 'Failed to create checkout session' });
        }
      });

      // Add this line after your other middleware
      app.use(express.static('public'));

      // Add this route to serve the demo page
      app.get('/', (req, res) => {
        res.sendFile(__dirname + '/../public/index.html');
      });

      app.listen(3000, () => {
        console.log('Server is running on port 3000');
      });
      ```
    </CodeGroup>
  </Step>

  <Step title="Add a simple web interface">
    Crea un archivo `public/index.html` para pruebas sencillas:

    <CodeGroup>
      ```html index.html expandable theme={null}
      <!DOCTYPE html>
      <html>
      <head>
          <title>Seat-Based Pricing Demo</title>
          <style>
              body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
              .form-group { margin: 20px 0; }
              label { display: block; margin-bottom: 5px; font-weight: bold; }
              input { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
              button { background: #007bff; color: white; padding: 10px 20px; border: none; border-radius: 4px; cursor: pointer; }
              button:hover { background: #0056b3; }
              .result { margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 4px; }
          </style>
      </head>
      <body>
          <h1>Seat-Based Pricing Demo</h1>
          <p>Generate checkout links with custom seat quantities:</p>
          
          <div class="form-group">
              <label for="seatCount">Number of Additional Seats:</label>
              <input type="number" id="seatCount" value="3" min="0" max="50">
          </div>
          
          <button onclick="createCheckout()">Generate Checkout Link</button>
          
          <div id="result" class="result" style="display: none;">
              <h3>Checkout Link Generated!</h3>
              <p><strong>Seat Count:</strong> <span id="seatCountDisplay"></span></p>
              <p><strong>Total Cost:</strong> $<span id="totalCost"></span>/month</p>
              <p><strong>Checkout URL:</strong></p>
              <a id="checkoutUrl" href="#" target="_blank">Click here to checkout</a>
          </div>

          <script>
              async function createCheckout() {
                  const seatCount = document.getElementById('seatCount').value;
                  
                  try {
                      const response = await fetch(`/create-checkout/${seatCount}`, {
                          method: 'POST'
                      });
                      
                      const data = await response.json();
                      
                      if (response.ok) {
                          document.getElementById('seatCountDisplay').textContent = seatCount;
                          document.getElementById('totalCost').textContent = data.total_cost;
                          document.getElementById('checkoutUrl').href = data.checkout_url;
                          document.getElementById('result').style.display = 'block';
                      } else {
                          alert('Error: ' + data.error);
                      }
                  } catch (error) {
                      alert('Error creating checkout session');
                  }
              }
          </script>
      </body>
      </html>
      ```
    </CodeGroup>

    <Check>
      **¡Interfaz web creada!** Ahora tienes una UI simple para probar diferentes cantidades de asientos.
    </Check>
  </Step>

  <Step title="Serve static files">
    Agrega esto a tu `src/server.ts` para servir el archivo HTML:

    ```typescript theme={null}
    // Add this line after your other middleware
    app.use(express.static('public'));

    // Add this route to serve the demo page
    app.get('/', (req, res) => {
      res.sendFile(__dirname + '/../public/index.html');
    });
    ```

    <Check>
      **¡Archivos estáticos configurados!** Visita `http://localhost:3000` para ver tu interfaz de demostración.
    </Check>
  </Step>
</Steps>

## Paso 5: Prueba Tu Implementación

Probemos nuestra implementación de precios por asiento para asegurarnos de que todo funcione correctamente.

<Steps>
  <Step title="Start your server">
    1. Asegúrate de tener tu archivo `.env` con la clave de API correcta
    2. Actualiza los IDs del producto y del complemento en tu código con los valores reales de tu panel de Dodo Payments
    3. Inicia tu servidor:

    ```bash theme={null}
    npm run dev
    ```

    <Check>
      Tu servidor debería iniciarse correctamente y mostrar "Server running on [http://localhost:3000](http://localhost:3000)"
    </Check>
  </Step>

  <Step title="Test the web interface">
    <Frame>
      <img src="https://mintcdn.com/dodopayments/ajOhO6Du1yNsg0hy/images/cookbooks/seat-based/seat-based-billing-ui.png?fit=max&auto=format&n=ajOhO6Du1yNsg0hy&q=85&s=37d166d8e76b0bfbb4959bc9a3eff1f8" alt="Creando producto de suscripción base" style={{ maxHeight: '500px', width: 'auto' }} width="1806" height="1416" data-path="images/cookbooks/seat-based/seat-based-billing-ui.png" />
    </Frame>

    1. Abre tu navegador y ve a `http://localhost:3000`
    2. Deberías ver la interfaz de demostración de precios por asiento
    3. Prueba diferentes cantidades de asientos (0, 3, 10, etc.)
    4. Haz clic en "Generate Checkout Link" para cada cantidad
    5. Verifica que se generen correctamente las URL de pago
  </Step>

  <Step title="Test a checkout session">
    1. Genera un enlace de pago con 3 asientos adicionales
    2. Haz clic en la URL de checkout para abrir el pago de Dodo Payments
    3. Verifica que el checkout muestre:
       * Plan base: \$49/mes
       * Asientos adicionales: 3 × 2 dólares = \$6/mes
    4. Completa la compra de prueba

    <Check>
      El checkout debe mostrar el desglose correcto de precios y permitir completar la compra.
    </Check>
  </Step>

  <Step title="Listen for webhooks and update your DB">
    Para mantener tu base de datos sincronizada con los cambios en suscripciones y asientos, necesitas escuchar los eventos webhook de Dodo Payments. Los webhooks notifican a tu backend cuando un cliente completa un pago, actualiza su suscripción o cambia la cantidad de asientos.

    Sigue la guía oficial de webhooks de Dodo Payments para obtener instrucciones paso a paso sobre cómo configurar los puntos finales de webhook y manejar eventos:

    <Card title="Dodo Payments Webhooks Documentation" icon="bell" href="/developer-resources/webhooks">
      Aprende cómo recibir y procesar de forma segura los eventos webhook para administrar suscripciones y asientos.
    </Card>
  </Step>
</Steps>

## Solución de Problemas

Problemas comunes y sus soluciones:

<AccordionGroup>
  <Accordion title="Checkout creation failing">
    **Causas posibles:**

    * ID de producto o complemento inválido
    * La clave de API no tiene permisos suficientes
    * El complemento no está asociado correctamente con la suscripción
    * Problemas de conectividad de red

    **Soluciones:**

    1. Verifica que los IDs de producto y complemento existan en tu panel de Dodo Payments
    2. Comprueba que el complemento esté correctamente adjunto a la suscripción
    3. Asegúrate de que la clave de API tenga permisos para crear sesiones de checkout
    4. Prueba la conectividad de la API con una solicitud GET sencilla
  </Accordion>
</AccordionGroup>

## ¡Felicidades! Has Implementado Precios por Asiento

¡Has creado con éxito un sistema de precios por asiento con Dodo Payments! Esto es lo que lograste:

<CardGroup cols={2}>
  <Card title="Base Subscription">
    Creaste un producto de suscripción con 5 asientos incluidos a \$49/mes
  </Card>

  <Card title="Seat Add-ons">
    Configuraste complementos para asientos adicionales a \$2/mes por asiento
  </Card>

  <Card title="Checkout">
    Construiste una API que genera sesiones de checkout con cantidades personalizadas de asientos
  </Card>

  <Card title="Web Interface">
    Creaste una interfaz web sencilla para probar diferentes cantidades de asientos
  </Card>
</CardGroup>

<Info>
  Este ejemplo solo muestra una implementación mínima de precios basados en asientos. Para un entorno de producción, deberías añadir un manejo de errores robusto, autenticación, validación de datos, medidas de seguridad y adaptar la lógica a los requisitos de tu aplicación.
</Info>
