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

# Python

> Usa el SDK de Python de Dodo Payments, con clientes sync y async, para crear sesiones de checkout, clientes, suscripciones y eventos de uso desde Python 3.9+.

El SDK de Python proporciona a las aplicaciones de Python acceso tipado a la REST API de Dodo Payments. Incluye un cliente síncrono, `DodoPayments`, y un cliente asíncrono, `AsyncDodoPayments`, ambos basados en `httpx`. Los parámetros de solicitud anidados son diccionarios tipados y las respuestas son modelos de Pydantic.

## Instalación

Instala el SDK con pip:

```bash theme={null}
pip install dodopayments
```

Para usar aiohttp como backend HTTP para el cliente async, instala el extra `aiohttp`:

```bash theme={null}
pip install "dodopayments[aiohttp]"
```

Para verificar las firmas de los webhooks con `client.webhooks.unwrap()`, instala también el extra `webhooks`: `pip install "dodopayments[webhooks]"`.

<Info>
  El SDK requiere Python 3.9 o posterior. Usa la versión estable más reciente de Python para recibir actualizaciones de seguridad.
</Info>

## Inicio rápido

### Cliente síncrono

Crea un cliente y, después, crea una sesión de checkout:

```python theme={null}
import os
from dodopayments import DodoPayments

client = DodoPayments(
    bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),  # This is the default and can be omitted
    environment="test_mode",  # defaults to "live_mode"
)

checkout_session_response = client.checkout_sessions.create(
    product_cart=[
        {
            "product_id": "pdt_123",
            "quantity": 1
        }
    ],
)
print(checkout_session_response.session_id)
```

Si omites `bearer_token`, el cliente lee la variable de entorno `DODO_PAYMENTS_API_KEY`. Si omites `environment`, el cliente se conecta al modo live. Una clave de API del modo de prueba solo funciona con `environment="test_mode"`.

### Cliente asíncrono

`AsyncDodoPayments` tiene los mismos métodos que `DodoPayments`. Usa await en cada llamada:

```python theme={null}
import os
import asyncio
from dodopayments import AsyncDodoPayments

client = AsyncDodoPayments(
    bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
    environment="test_mode",
)

async def main() -> None:
    checkout_session_response = await client.checkout_sessions.create(
        product_cart=[
            {
                "product_id": "pdt_123",
                "quantity": 1,
            }
        ],
    )
    print(checkout_session_response.session_id)

asyncio.run(main())
```

<Warning>
  Guarda las claves de API en variables de entorno o en un gestor de secretos. Nunca las incluyas en el control de versiones.
</Warning>

## Funciones principales

<CardGroup cols={2}>
  <Card title="Pythonic Interface" icon="code">
    Argumentos de palabra clave para los parámetros, tipos `TypedDict` para objetos anidados y modelos de Pydantic para las respuestas.
  </Card>

  <Card title="Async/Await" icon="bolt">
    `AsyncDodoPayments` para asyncio, con aiohttp como backend HTTP opcional.
  </Card>

  <Card title="Type Hints" icon="check">
    Sugerencias de tipo en todos los métodos, para el autocompletado del editor y la comprobación de tipos con mypy.
  </Card>

  <Card title="Auto-Pagination" icon="arrows-rotate">
    Los métodos de listado devuelven iteradores que obtienen la página siguiente mientras recorres los resultados.
  </Card>
</CardGroup>

## Configuración

### Variables de entorno

Guarda tu clave de API en una variable de entorno:

```bash .env theme={null}
DODO_PAYMENTS_API_KEY=your_api_key_here
```

El cliente lee estas variables cuando no pasas el argumento correspondiente:

| Variable | Argumento del cliente | Propósito |
| - | - | - |
| `DODO_PAYMENTS_API_KEY` | `bearer_token` | Tu clave de API. El cliente genera un error si no se establece ninguna de las dos. |
| `DODO_PAYMENTS_WEBHOOK_KEY` | `webhook_key` | Tu secreto de firma de webhook, utilizado para verificar webhooks. |
| `DODO_PAYMENTS_BASE_URL` | `base_url` | Una URL de API personalizada que reemplaza la URL `environment`. |
| `DODO_PAYMENTS_LOG` | Sin argumento correspondiente | El nivel de registro. Consulta [Registro](#logging). |

Si se establece `DODO_PAYMENTS_BASE_URL` y también pasas `environment`, el constructor genera un error de "URL ambigua". Para usar `environment` en ese caso, pasa `base_url=None`.

Para verificar un webhook, pasa el cuerpo sin procesar de la solicitud y los encabezados a `client.webhooks.unwrap(payload, headers=headers)`. Comprueba la firma con tu clave de webhook y devuelve el evento analizado. `client.webhooks.unsafe_unwrap(payload)` analiza el cuerpo sin verificarlo, así que úsalo solo para pruebas. Consulta [Webhooks](/developer-resources/webhooks).

### Tiempos de espera

Las solicitudes agotan el tiempo de espera después de 1 minuto de forma predeterminada, con un tiempo de espera de conexión de 5 segundos. Pasa `timeout` en segundos o un `httpx.Timeout` para establecer límites independientes de lectura, escritura y conexión:

```python theme={null}
import httpx
from dodopayments import DodoPayments

# Configure default for all requests (default is 1 minute)
client = DodoPayments(
    timeout=20.0,  # 20 seconds
)

# More granular control
client = DodoPayments(
    timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),
)

# Override per-request
client.with_options(timeout=5.0).checkout_sessions.create(
    product_cart=[
        {
            "product_id": "pdt_123",
            "quantity": 1,
        }
    ],
)
```

Cuando una solicitud agota el tiempo de espera, el SDK genera `APITimeoutError`. Las solicitudes cuyo tiempo de espera se agotó se reintentan, por lo que una llamada puede tardar más que `timeout` antes de fallar.

### Reintentos

Establece `max_retries` en el cliente o en una sola solicitud con `with_options()`:

```python theme={null}
from dodopayments import DodoPayments

# Configure default for all requests (default is 2)
client = DodoPayments(
    max_retries=0,  # disable retries
)

# Override per-request
client.with_options(max_retries=5).checkout_sessions.create(
    product_cart=[
        {
            "product_id": "pdt_123",
            "quantity": 1,
        }
    ],
)
```

El SDK reintenta los errores de conexión y las respuestas con estado 408, 409, 429 o 500 y superiores. De forma predeterminada, realiza dos reintentos con un retroceso exponencial. Cuando una solicitud sigue fallando, el SDK genera una subclase de `dodopayments.APIError`:

| Estado | Excepción |
| - | - |
| 400 | `BadRequestError` |
| 401 | `AuthenticationError` |
| 403 | `PermissionDeniedError` |
| 404 | `NotFoundError` |
| 409 | `ConflictError` |
| 422 | `UnprocessableEntityError` |
| 429 | `RateLimitError` |
| 500 y superiores | `InternalServerError` |
| Sin respuesta | `APIConnectionError` |

Las excepciones de estado heredan de `dodopayments.APIStatusError`, que tiene los atributos `status_code` y `response`. `APITimeoutError` es una subclase de `APIConnectionError`.

## Operaciones comunes

Los ejemplos de esta sección usan el `client` de [Inicio rápido](#quick-start).

### Crear una sesión de Checkout

Crea una sesión de checkout y, después, redirige al cliente a la `checkout_url` devuelta:

```python theme={null}
session = client.checkout_sessions.create(
    product_cart=[
        {
            "product_id": "pdt_123",
            "quantity": 1
        }
    ],
    return_url="https://yourdomain.com/return"
)

print(f"Checkout URL: {session.checkout_url}")
```

Cada `checkout_url` funciona una vez y caduca después de 24 horas. Para consultar todas las opciones de la sesión, visita [Sesiones de Checkout](/developer-resources/checkout-session).

### Gestionar clientes

Crea un cliente con una dirección de correo electrónico y un nombre y, después, recupéralo por ID:

```python theme={null}
# Create a customer
customer = client.customers.create(
    email="customer@example.com",
    name="John Doe",
    metadata={
        "user_id": "12345"
    }
)

# Retrieve customer
customer = client.customers.retrieve("cus_123")
print(f"Customer: {customer.name} ({customer.email})")
```

### Gestionar suscripciones

Crea una suscripción, cobra una suscripción on-demand y consulta el historial de uso de una suscripción.

<Warning>
  `POST /subscriptions` (el método `subscriptions.create` del SDK) está **obsoleto**. Sigue funcionando para integraciones existentes, pero las integraciones nuevas deben crear suscripciones mediante una [Sesión de Checkout](/developer-resources/checkout-session).
</Warning>

```python expandable theme={null}
# Create a subscription
subscription = client.subscriptions.create(
    billing={
        "country": "US",
        "city": "San Francisco",
        "state": "CA",
        "street": "1 Market St",
        "zipcode": "94105",
    },
    customer={"customer_id": "cus_123"},  # or {"email": "...", "name": "..."} for a new customer
    product_id="pdt_456",
    quantity=1,
)

# Charge an on-demand subscription
# product_price is in the lowest currency denomination (e.g., 2500 = $25.00 USD)
charge_response = client.subscriptions.charge(
    subscription_id=subscription.subscription_id,
    product_price=2500,
)

# Retrieve usage history (for metered subscriptions)
usage_history = client.subscriptions.retrieve_usage_history(
    subscription_id=subscription.subscription_id,
    start_date="2024-01-01T00:00:00Z",
)
```

<Info>
  `billing` solo requiere `country`, un código de país ISO de dos letras. `customer` acepta `{"customer_id": ...}` para asociar un cliente existente o `{"email": ..., "name": ...}` para crear uno. `charge` es para [suscripciones on-demand](/developer-resources/ondemand-subscriptions), e `product_price` está expresado en la unidad monetaria más pequeña. `retrieve_usage_history` devuelve una lista paginada que puedes recorrer como se muestra en [Paginación](#pagination).
</Info>

## Facturación basada en el uso

### Ingerir eventos de uso

Envía eventos de uso para un cliente:

```python theme={null}
from datetime import datetime, timezone

response = client.usage_events.ingest(
    events=[
        {
            "event_id": "api_call_12345",
            "customer_id": "cus_abc123",
            "event_name": "api_request",
            "timestamp": datetime.now(timezone.utc),
            "metadata": {
                "endpoint": "/api/v1/users",
                "method": "GET",
                "tokens_used": "150"
            }
        }
    ]
)
```

<Info>
  `event_id` es la clave de idempotencia, así que asigna un valor único a cada evento. Si el mismo `event_id` aparece dos veces en una solicitud, se rechaza toda la solicitud. Si un `event_id` ya se había ingerido, el evento nuevo se ignora. Una solicitud acepta hasta 1.000 eventos. `timestamp` utiliza de forma predeterminada la hora actual y se rechaza si es de hace más de 1 hora o si está más de 5 minutos en el futuro.
</Info>

### Enumerar y recuperar eventos

Recupera un evento individual por su `event_id` o enumera los eventos filtrados por cliente y nombre del evento:

```python theme={null}
# Get a specific event
event = client.usage_events.retrieve("api_call_12345")

# List events with filtering
events = client.usage_events.list(
    customer_id="cus_abc123",
    event_name="api_request",
    page_size=20
)

for event in events.items:
    print(f"Event: {event.event_id} at {event.timestamp}")
```

`usage_events.list` también acepta los filtros `meter_id`, `start` y `end`.

## Paginación

### Paginación automática

Los métodos de listado devuelven un iterador que obtiene la página siguiente mientras recorres los resultados:

```python theme={null}
from dodopayments import DodoPayments

client = DodoPayments()
all_payments = []

# Automatically fetches more pages as needed
for payment in client.payments.list():
    all_payments.append(payment)
print(all_payments)
```

### Paginación asíncrona

Con el cliente async, recorre los resultados con `async for`:

```python theme={null}
import asyncio
from dodopayments import AsyncDodoPayments

client = AsyncDodoPayments()

async def main() -> None:
    all_payments = []
    # Iterate through items across all pages
    async for payment in client.payments.list():
        all_payments.append(payment)
    print(all_payments)

asyncio.run(main())
```

### Paginación manual

Para trabajar con una página a la vez, lee `items` y llama a `has_next_page()` y `get_next_page()`. `next_page_info()` devuelve los parámetros para la siguiente solicitud:

```python theme={null}
# Access items from current page
first_page = client.payments.list()
for payment in first_page.items:
    print(payment.brand_id)

# Check for more pages
if first_page.has_next_page():
    next_page = first_page.get_next_page()
    print(f"Fetched {len(next_page.items)} more items")
```

## Configuración del cliente HTTP

Para añadir un proxy, un transporte personalizado u otra configuración de `httpx`, pasa tu propio `http_client`. `DefaultHttpxClient` conserva los límites de conexión, el tiempo de espera y la configuración de redirecciones predeterminados del SDK:

```python theme={null}
import httpx
from dodopayments import DodoPayments, DefaultHttpxClient

client = DodoPayments(
    base_url="http://my.test.server.example.com:8083",
    http_client=DefaultHttpxClient(
        proxy="http://my.test.proxy.example.com",
        transport=httpx.HTTPTransport(local_address="0.0.0.0"),
    ),
)
```

Para usar un cliente HTTP diferente en una solicitud, llama a `client.with_options(http_client=...)`.

## Async con AIOHTTP

De forma predeterminada, el cliente async envía solicitudes con `httpx`. Para obtener una mejor concurrencia, instala el extra `aiohttp` y pasa `DefaultAioHttpClient()` como `http_client`:

```python theme={null}
import os
import asyncio
from dodopayments import DefaultAioHttpClient
from dodopayments import AsyncDodoPayments

async def main() -> None:
    async with AsyncDodoPayments(
        bearer_token=os.environ.get("DODO_PAYMENTS_API_KEY"),
        http_client=DefaultAioHttpClient(),
    ) as client:
        checkout_session_response = await client.checkout_sessions.create(
            product_cart=[
                {
                    "product_id": "pdt_123",
                    "quantity": 1,
                }
            ],
        )
        print(checkout_session_response.session_id)

asyncio.run(main())
```

## Registro

El SDK registra eventos mediante el módulo `logging` de la biblioteca estándar. Para activar el registro, establece `DODO_PAYMENTS_LOG` en `info`:

```bash theme={null}
export DODO_PAYMENTS_LOG=info
```

Para obtener más detalles, establécelo en `debug`:

```bash theme={null}
export DODO_PAYMENTS_LOG=debug
```

## Integración con frameworks

Estos ejemplos crean una sesión de checkout desde un endpoint web y devuelven su URL.

### FastAPI

Este endpoint usa el cliente async:

```python theme={null}
from fastapi import FastAPI, HTTPException
from dodopayments import AsyncDodoPayments
from pydantic import BaseModel
import os

app = FastAPI()
dodo = AsyncDodoPayments(bearer_token=os.getenv("DODO_PAYMENTS_API_KEY"))

class CheckoutRequest(BaseModel):
    product_id: str
    quantity: int

@app.post("/create-checkout")
async def create_checkout(request: CheckoutRequest):
    try:
        session = await dodo.checkout_sessions.create(
            product_cart=[{
                "product_id": request.product_id,
                "quantity": request.quantity
            }],
            return_url="https://yourdomain.com/return"
        )
        return {"checkout_url": session.checkout_url}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))
```

### Django

Esta vista usa el cliente sync:

```python theme={null}
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt
from dodopayments import DodoPayments
import os
import json

client = DodoPayments(bearer_token=os.getenv("DODO_PAYMENTS_API_KEY"))

@csrf_exempt
@require_POST
def create_checkout(request):
    try:
        data = json.loads(request.body)
        session = client.checkout_sessions.create(
            product_cart=[{
                "product_id": data.get("product_id"),
                "quantity": data.get("quantity", 1)
            }],
            return_url="https://yourdomain.com/return"
        )
        return JsonResponse({
            "status": "success",
            "checkout_url": session.checkout_url,
            "session_id": session.session_id
        })
    except Exception as e:
        return JsonResponse({
            "status": "error",
            "message": str(e)
        }, status=400)
```

## Recursos

<CardGroup cols={2}>
  <Card title="GitHub Repository" icon="github" href="https://github.com/dodopayments/dodopayments-python">
    Código fuente, versiones y lista completa de métodos.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Cada endpoint, parámetro y respuesta.
  </Card>

  <Card title="Discord Community" icon="discord" href="https://discord.gg/bYqAp4ayYh">
    Haz preguntas y conversa con otros desarrolladores.
  </Card>

  <Card title="Report Issues" icon="bug" href="https://github.com/dodopayments/dodopayments-python/issues">
    Informa de errores o solicita funciones.
  </Card>
</CardGroup>

## Soporte

Para obtener ayuda con el SDK de Python:

* **Discord**: Únete al [servidor de la comunidad](https://discord.gg/bYqAp4ayYh) para recibir ayuda en tiempo real.
* **Correo electrónico**: Contacta con [support@dodopayments.com](mailto:support@dodopayments.com).
* **GitHub**: Abre un issue en el [repositorio](https://github.com/dodopayments/dodopayments-python).

## Contribuciones

Para contribuir, lee las [directrices de contribución](https://github.com/dodopayments/dodopayments-python/blob/main/CONTRIBUTING.md).


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