> ## 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.

# Subscription Integration Guide

> This guide will help you integrate the Dodo Payments Subscription Product into your website.

## Prerequisites

To integrate the Dodo Payments API, you'll need:

* A Dodo Payments merchant account
* API credentials (API key and webhook secret key) from the dashboard

For a more detailed guide on the prerequisites, check this [section](/developer-resources/integration-guide#dashboard-setup).

## API Integration

### Checkout Sessions

Use Checkout Sessions to sell subscription products with a secure, hosted checkout. Pass your subscription product in `product_cart` and redirect customers to the returned `checkout_url`.

<Tip>
  **Mixed Checkout**: You can combine subscription products with one-time products in the same checkout session. This enables use cases like setup fees with subscriptions, hardware bundles with SaaS, and more. See the [Checkout Sessions guide](/developer-resources/checkout-session) for examples.
</Tip>

<Tabs>
  <Tab title="Node.js SDK">
    ```javascript theme={null}
    import DodoPayments from 'dodopayments';

    const client = new DodoPayments({
      bearerToken: process.env.DODO_PAYMENTS_API_KEY,
      environment: 'test_mode', // defaults to 'live_mode'
    });

    async function main() {
      const session = await client.checkoutSessions.create({
        product_cart: [
          { product_id: 'prod_subscription_monthly', quantity: 1 }
        ],
        // Optional: configure trials for subscription products
        subscription_data: { trial_period_days: 14 },
        customer: {
          email: 'subscriber@example.com',
          name: 'Jane Doe',
        },
        return_url: 'https://example.com/success',
      });

      console.log(session.checkout_url);
    }

    main();
    ```
  </Tab>

  <Tab title="Python SDK">
    ```python theme={null}
    import os
    from dodopayments import DodoPayments

    client = DodoPayments(
        bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
        environment="test_mode",  # defaults to "live_mode"
    )

    session = client.checkout_sessions.create(
        product_cart=[
            {"product_id": "prod_subscription_monthly", "quantity": 1}
        ],
        subscription_data={"trial_period_days": 14},  # optional
        customer={
            "email": "subscriber@example.com",
            "name": "Jane Doe",
        },
        return_url="https://example.com/success",
    )

    print(session.checkout_url)
    ```
  </Tab>

  <Tab title="REST API">
    ```javascript theme={null}
    const response = await fetch('https://test.dodopayments.com/checkouts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${process.env.DODO_PAYMENTS_API_KEY}`
      },
      body: JSON.stringify({
        product_cart: [
          { product_id: 'prod_subscription_monthly', quantity: 1 }
        ],
        subscription_data: { trial_period_days: 14 }, // optional
        customer: {
          email: 'subscriber@example.com',
          name: 'Jane Doe'
        },
        return_url: 'https://example.com/success'
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const session = await response.json();
    console.log(session.checkout_url);
    ```
  </Tab>
</Tabs>

### API Response

The following is an example of the response:

```json theme={null}
{
  "session_id": "cks_Gi6KGJ2zFJo9rq9Ukifwa",
  "checkout_url": "https://test.checkout.dodopayments.com/session/cks_Gi6KGJ2zFJo9rq9Ukifwa"
}
```

Redirige al cliente a `checkout_url`.

### Webhooks

Al integrar suscripciones, recibirás webhooks para rastrear el ciclo de vida de la suscripción. Estos webhooks te ayudan a gestionar los estados de suscripción y escenarios de pago de manera efectiva.

Para configurar tu endpoint de webhook, sigue nuestra [Guía de Integración Detallada](/developer-resources/integration-guide#implementing-webhooks).

#### Tipos de Eventos de Suscripción

Los siguientes eventos de webhook rastrean los cambios de estado de la suscripción:

1. **`subscription.active`** - La suscripción se activa con éxito.
2. **`subscription.updated`** - El objeto de la suscripción fue actualizado (se dispara con cualquier cambio de campo).
3. **`subscription.on_hold`** - La suscripción se pone en espera debido a una renovación fallida.
4. **`subscription.failed`** - La creación de la suscripción falló durante la creación del mandato.
5. **`subscription.renewed`** - La suscripción se renueva para el siguiente período de facturación.

Para una gestión confiable del ciclo de vida de la suscripción, recomendamos rastrear estos eventos de suscripción.

<Tip>
  Usa `subscription.updated` para obtener notificaciones en tiempo real sobre cualquier cambio de suscripción, manteniendo el estado de tu aplicación sincronizado sin sondeo de la API.
</Tip>

#### Escenarios de Pago

**Flujo de Pago Exitoso**

Cuando un pago tiene éxito, recibirás los siguientes webhooks:

1. `subscription.active` - Indica activación de la suscripción
2. `payment.succeeded` - Confirma el pago inicial:
   * Para facturación inmediata (0 días de prueba): Espera dentro de 2-10 minutos
   * Para días de prueba: cuando eso termine
3. `subscription.renewed` - Indica deducción de pago y renovación para el próximo ciclo. (Básicamente, cada vez que se deduce el pago por productos de suscripción, recibirás el webhook `subscription.renewed` junto con `payment.succeeded`)

**Escenarios de Fallo de Pago**

1. Fallo de la Suscripción

* `subscription.failed` - La creación de la suscripción falló debido a un fallo en la creación de un mandato.
* `payment.failed` - Indica un fallo de pago.

2. Suscripción en Espera

* `subscription.on_hold` - La suscripción se pone en espera debido a un fallo en el pago de renovación o un fallo al cambiar el plan.
* Cuando una suscripción está en espera, no se renovará automáticamente hasta que se actualice el método de pago.

<Info>**Mejor Práctica**: Para simplificar la implementación, recomendamos principalmente rastrear eventos de suscripción para gestionar el ciclo de vida de la suscripción.</Info>

<Tip>
  Para una guía completa sobre cómo leer `error_code`/`error_message`, decidir cuándo reintentar y visibilizar los fallos a los clientes, consulta [Manejo de Fallos de Pago](/developer-resources/handle-payment-failures).
</Tip>

#### `subscription.failed` vs. `subscription.on_hold`

Estos dos eventos son fáciles de confundir, pero requieren manejos muy diferentes:

| Evento                 | Cuándo se dispara                                                                            | Estado    | ¿Recuperable?     | Qué hacer                                                                                                                       |
| ---------------------- | -------------------------------------------------------------------------------------------- | --------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `subscription.failed`  | El mandato **inicial** no pudo ser creado en la **creación** de la suscripción               | `failed`  | **No — terminal** | No conceder acceso. Pedir al cliente que inicie una **nueva** suscripción con un método de pago diferente.                      |
| `subscription.on_hold` | Un pago de **renovación** (o un cargo por cambio de plan) falló en una suscripción ya activa | `on_hold` | **Sí**            | Recuperar actualizando el método de pago; ver [Manejo de Suscripción en Espera](#handling-subscription-on-hold) a continuación. |

<Warning>
  `subscription.failed` es terminal: la suscripción no puede reactivarse. El cliente debe crear una nueva suscripción. Nunca conceder derechos cuando se dispara este evento.
</Warning>

### Manejo de Suscripción en Espera

Cuando una suscripción entra en el estado `on_hold`, necesitas actualizar el método de pago para reactivarla. Esta sección explica cuándo las suscripciones se ponen en espera y cómo manejarlas.

#### Cuándo las Suscripciones se Ponen en Espera

Una suscripción se coloca en espera cuando:

* **Falló el pago de renovación**: El cargo automático de renovación falla debido a fondos insuficientes, tarjeta expirada o rechazo del banco
* **Falla el cargo por cambio de plan**: Un cargo inmediato durante la actualización/degradación del plan falla
* **Falla la autorización del método de pago**: El método de pago no puede ser autorizado para cargos recurrentes

<Warning>
  Las suscripciones en estado `on_hold` no se renovarán automáticamente. Debes actualizar el método de pago para reactivar la suscripción.
</Warning>

#### Reactivación de Suscripciones desde en Espera

Para reactivar una suscripción desde el estado `on_hold`, usa la API de Actualización de Método de Pago. Esto automáticamente:

1. Crea un cargo por deudas pendientes
2. Genera una factura por el cargo
3. Procesa el pago usando el nuevo método de pago
4. Reactiva la suscripción al estado `active` tras el pago exitoso

<Steps>
  <Step title="Handle subscription.on_hold webhook">
    Cuando recibes un webhook `subscription.on_hold`, actualiza el estado de tu aplicación y notifica al cliente:

    ```javascript theme={null}
    // Webhook handler
    app.post('/webhooks/dodo', async (req, res) => {
      const event = req.body;
      
      if (event.type === 'subscription.on_hold') {
        const subscription = event.data;
        
        // Update subscription status in your database
        await updateSubscriptionStatus(subscription.subscription_id, 'on_hold');
        
        // Notify customer to update payment method
        await sendEmailToCustomer(subscription.customer_id, {
          subject: 'Payment Required - Subscription On Hold',
          message: 'Your subscription is on hold. Please update your payment method to continue service.'
        });
      }
      
      res.json({ received: true });
    });
    ```
  </Step>

  <Step title="Update payment method">
    Cuando el cliente esté listo para actualizar su método de pago, llama a la API de Actualización de Método de Pago:

    <CodeGroup>
      ```javascript Node.js theme={null}
      // Update with new payment method
      const response = await client.subscriptions.updatePaymentMethod(subscriptionId, {
        type: 'new',
        return_url: 'https://example.com/return'
      });

      // For on_hold subscriptions, a charge is automatically created
      if (response.payment_id) {
        console.log('Charge created for remaining dues:', response.payment_id);
        // Redirect customer to response.payment_link to complete payment
      }
      ```

      ```python Python theme={null}
      # Update with new payment method
      response = client.subscriptions.update_payment_method(
          subscription_id=subscription_id,
          type="new",
          return_url="https://example.com/return"
      )

      # For on_hold subscriptions, a charge is automatically created
      if response.payment_id:
          print("Charge created for remaining dues:", response.payment_id)
          # Redirect customer to response.payment_link to complete payment
      ```
    </CodeGroup>

    <Info>
      También puedes usar una ID de método de pago existente si el cliente ha guardado métodos de pago:

      ```javascript theme={null}
      await client.subscriptions.updatePaymentMethod(subscriptionId, {
        type: 'existing',
        payment_method_id: 'pm_abc123'
      });
      ```
    </Info>
  </Step>

  <Step title="Monitor webhook events">
    Después de actualizar el método de pago, monitorea estos eventos de webhook:

    1. **`payment.succeeded`** - El cargo por deudas pendientes fue exitoso
    2. **`subscription.active`** - La suscripción ha sido reactivada

    ```javascript theme={null}
    if (event.type === 'payment.succeeded') {
      const payment = event.data;
      
      // Check if this payment is for an on_hold subscription
      if (payment.subscription_id) {
        // Wait for subscription.active webhook to confirm reactivation
      }
    }

    if (event.type === 'subscription.active') {
      const subscription = event.data;
      
      // Update subscription status in your database
      await updateSubscriptionStatus(subscription.subscription_id, 'active');
      
      // Restore customer access
      await restoreCustomerAccess(subscription.customer_id);
      
      // Notify customer of successful reactivation
      await sendEmailToCustomer(subscription.customer_id, {
        subject: 'Subscription Reactivated',
        message: 'Your subscription has been reactivated successfully.'
      });
    }
    ```
  </Step>
</Steps>

### Ejemplo de Payload de Evento de Suscripción

***

| Propiedad     | Tipo   | Obligatorio | Descripción                                                                                  |
| ------------- | ------ | ----------- | -------------------------------------------------------------------------------------------- |
| `business_id` | string | Sí          | El identificador único para el negocio                                                       |
| `timestamp`   | string | Sí          | La marca de tiempo de cuando ocurrió el evento (no necesariamente igual a cuando se entregó) |
| `type`        | string | Sí          | El tipo de evento. Ver [Tipos de Evento](#event-types)                                       |
| `data`        | object | Sí          | La carga útil principal de datos. Ver [Objeto de Datos](#data-object)                        |

## Cambiar Planes de Suscripción

Puedes mejorar o degradar un plan de suscripción usando el endpoint API de cambio de plan. Esto te permite modificar el producto de la suscripción, la cantidad y manejar la prorrata.

<Card title="Change Plan API Reference" icon="arrows-rotate" href="/api-reference/subscriptions/change-plan">
  Para obtener información detallada sobre el cambio de planes de suscripción, consulta nuestra documentación de la API de Cambio de Plan.
</Card>

### Opciones de Prorrata

Al cambiar planes de suscripción, tienes dos opciones para manejar el cargo inmediato:

#### 1. `prorated_immediately`

* Calcula el monto prorrateado basado en el tiempo restante en el ciclo de facturación actual
* Cobra al cliente solo la diferencia entre el plan antiguo y el nuevo
* Durante un período de prueba, esto cambiará inmediatamente al usuario al nuevo plan, cobrando al cliente de inmediato

#### 2. `full_immediately`

* Cobra al cliente el monto completo de la suscripción para el nuevo plan
* Ignora cualquier tiempo restante o créditos del plan anterior
* Útil cuando deseas restablecer el ciclo de facturación o cobrar el monto completo sin importar la prorrata

#### 3. `difference_immediately`

* Al mejorar, el cliente se cobra de inmediato la diferencia entre los dos montos de los planes.
* Por ejemplo, si el plan actual es de 30 Dólares y el cliente mejora a uno de 80 Dólares, se le cobran \$50 instantáneamente.
* Al degradar, la cantidad no utilizada del plan actual se añade como crédito interno y se aplica automáticamente a renovaciones futuras de suscripción.
* Por ejemplo, si el plan actual es de 50 Dólares y el cliente cambia a un plan de 20 Dólares, los \$30 restantes se acreditan y se usan para el siguiente ciclo de facturación.

### Comportamiento

* Cuando invocas esta API, Dodo Payments inicia inmediatamente un cargo basado en tu opción de prorrata seleccionada
* Si el cambio de plan es una degradación y usas `prorated_immediately`, se calcularán automáticamente los créditos y se añadirán al saldo de crédito de la suscripción. Estos créditos son específicos de esa suscripción y solo se usarán para compensar futuros pagos recurrentes de la misma suscripción
* La opción `full_immediately` omite los cálculos de crédito y cobra el monto completo del nuevo plan

<Tip>
  **Elige tu opción de prorrata cuidadosamente**: Usa `prorated_immediately` para una facturación justa que tenga en cuenta el tiempo no utilizado, o `full_immediately` cuando desees cobrar el monto completo del nuevo plan sin importar el ciclo de facturación actual.
</Tip>

### Procesamiento del Cargo

* El cargo inmediato iniciado al cambiar el plan usualmente completa el procesamiento en menos de 2 minutos
* Si este cargo inmediato falla por alguna razón, la suscripción se coloca automáticamente en espera hasta que se resuelva el problema

## Suscripciones Bajo Demanda

<Info>
  Las suscripciones bajo demanda te permiten cobrar a los clientes de manera flexible, no solo en un horario fijo. Esta función está disponible para todas las cuentas.
</Info>

**Para crear una suscripción bajo demanda:**

Para crear una suscripción bajo demanda, utiliza el endpoint API [POST /subscriptions](/api-reference/subscriptions/post-subscriptions) e incluye el campo `on_demand` en el cuerpo de tu solicitud. Esto te permite autorizar un método de pago sin un cargo inmediato o establecer un precio inicial personalizado.

**Para cobrar una suscripción bajo demanda:**

Para cargos posteriores, utiliza el endpoint [POST /subscriptions/{subscription_id}/charge](/api-reference/subscriptions/create-charge) y especifica la cantidad a cobrar al cliente por esa transacción.

<Note>
  Para obtener una guía completa, paso a paso, incluyendo ejemplos de solicitudes/respuestas, políticas de reintento seguro y manejo de webhooks, consulta la <a href="/developer-resources/ondemand-subscriptions">Guía de Suscripciones Bajo Demanda</a>.
</Note>

## Referencia de API Relacionada

<CardGroup cols={2}>
  <Card title="Create Subscription" icon="code" href="/api-reference/subscriptions/post-subscriptions">
    Referencia de API para crear productos de suscripción y gestionar el ciclo de vida de la suscripción
  </Card>

  <Card title="Change Subscription Plan" icon="arrows-rotate" href="/api-reference/subscriptions/change-plan">
    Referencia de API para mejorar, degradar o cambiar planes de suscripción con opciones de prorrata
  </Card>

  <Card title="Update Payment Method" icon="credit-card" href="/api-reference/subscriptions/update-payment-method">
    Referencia de API para actualizar métodos de pago y reactivar suscripciones en espera
  </Card>

  <Card title="Patch Subscription" icon="pen" href="/api-reference/subscriptions/patch-subscriptions">
    Referencia de API para actualizar los detalles y la configuración de suscripciones
  </Card>
</CardGroup>
