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

# Facturación por uso

> Cobra a tus clientes automáticamente según su consumo — con importes calculados por ti o con métricas gestionadas por Onflay.

La facturación por uso te permite cobrar al final de un período de facturación en lugar de a un precio fijo.
Onflay soporta dos modelos complementarios que puedes usar por separado o en conjunto.

## Modelos disponibles

| Modelo                                | Cómo funciona                                                                                                                                         | Ideal para                                                 |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| **Push del desarrollador (Modelo A)** | Tu plataforma calcula el consumo y el importe total. Llamas a `onflay.invoices.create()` y Onflay cobra la tarjeta automáticamente.                   | APIs de IA, cómputo, métricas propias                      |
| **Medición de Onflay (Modelo B)**     | Defines un `Meter` y un precio `USAGE_BASED` o `TIERED`. Reportas eventos con `onflay.usage.report()`. Onflay agrega y factura al cierre del período. | Llamadas a API, almacenamiento en GB, billing por asientos |

***

## Requisito previo: colectar un método de pago

Para poder cobrar automáticamente, el cliente final debe tener una tarjeta guardada.

<Steps>
  <Step title="Crea el cliente">
    ```ts theme={"dark"}
    import { Onflay } from '@onflay/node';

    const onflay = new Onflay(process.env.ONFLAY_API_KEY!);

    const customer = await onflay.customers.create({
      email: 'alice@ejemplo.com',
      displayName: 'Alice Smith',
    });
    ```
  </Step>

  <Step title="Genera la página de tarjeta">
    ```ts theme={"dark"}
    const session = await onflay.invoices.createSetupIntent(customer.id, {
      returnUrl: 'https://tu-app.com/billing/listo',
    });

    // Redirige al cliente — ingresará su tarjeta en la página hospedada
    redirect(session.hostedUrl);
    ```

    Una vez que el cliente completa el formulario, Onflay registra la tarjeta como método de pago predeterminado para cobros futuros.

    <Note>
      Si prefieres insertar Stripe Elements en tu propia UI, usa `session.clientSecret` directamente con `stripe.confirmSetup()`.
    </Note>
  </Step>
</Steps>

***

## Modelo A — Push del desarrollador

Tu plataforma calcula el importe. Cuando quieras cobrar, envías las líneas a Onflay.

```ts theme={"dark"}
const invoice = await onflay.invoices.create(
  {
    customerId: customer.id,
    currency: 'usd',
    lineItems: [
      {
        description: 'Tokens GPT-4o — junio 2026',
        amountInCents: 3250,   // $32.50
      },
      {
        description: 'Generaciones de imagen — junio 2026',
        amountInCents: 1700,   // $17.00
      },
    ],
    // Informativo — queda guardado en la factura para auditoría
    periodStart: '2026-06-01',
    periodEnd:   '2026-07-01',
  },
  { idempotencyKey: `billing-junio-2026-${customer.id}` },
);

console.log(invoice.status); // 'paid' | 'open' | 'failed'
```

Onflay crea un ítem de factura por cada línea, finaliza la factura en Stripe y cobra la tarjeta guardada con `collection_method: 'charge_automatically'`.

Recibirás los webhooks `invoice.created`, `invoice.finalized`, `invoice.paid` (o `invoice.payment_failed`) en tu endpoint registrado.

<Warning>
  Si el cliente no tiene una tarjeta guardada, la API devuelve `400` con el mensaje *"Customer does not have a saved payment method"*. Completa el flujo de SetupIntent primero.
</Warning>

***

## Modelo B — Medición de Onflay

### 1. Crea un metro

```ts theme={"dark"}
const meter = await onflay.usage.createMeter({
  name: 'Llamadas a la API',
  eventName: 'api_call',
  aggregation: 'SUM',  // o MAX, LAST
});
```

### 2. Crea un precio por uso en un producto

```ts theme={"dark"}
const producto = await onflay.products.create({
  name: 'API para Desarrolladores',
  type: 'SERVICE',
});

const precio = await onflay.prices.create({
  productId: producto.id,
  billingScheme: 'usage_based',
  currency: 'usd',
  tiersMode: 'graduated',
  tiers: [
    { upTo: 100_000, unitAmountInCents: 0 },   // primeras 100k llamadas gratis
    { upTo: null,    unitAmountInCents: 1 },     // $0.01 por llamada adicional
  ],
  recurring: { interval: 'month' },
});
```

### 3. Adjunta un plan de facturación a la suscripción

Después de que el cliente se suscriba vía checkout, adjunta un `UsageBillingPlan` para que el scheduler sepa cuándo y cómo facturar:

```ts theme={"dark"}
// POST /v1/usage/billing-plans
await fetch(`${baseUrl}/v1/usage/billing-plans`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${apiKey}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    subscriptionId: suscripcion.id,
    meterId: meter.id,
    priceId: precio.id,
    billingInterval: 'month',
  }),
});
```

### 4. Reporta consumo

```ts theme={"dark"}
// Llama esto cada vez que ocurre un evento en tu plataforma
await onflay.usage.report({
  subscriptionId: suscripcion.id,
  meter: 'api_call',
  quantity: 1,
  idempotencyKey: crypto.randomUUID(),
});
```

Los eventos se almacenan en Redis y se persisten en la base de datos cada minuto. Al cierre de cada período, Onflay agrega los registros de uso, aplica el precio escalonado y crea la factura en Stripe automáticamente.

***

## Webhooks de facturación

Suscríbete a los eventos de facturación desde el dashboard de webhooks o vía SDK:

```ts theme={"dark"}
await onflay.webhookEndpoints.create({
  url: 'https://tu-app.com/webhooks/onflay',
  events: ['invoice.*'],
  // o explícito: ['invoice.paid', 'invoice.payment_failed']
});
```

### Manejo de eventos

```ts theme={"dark"}
import { createNextWebhookHandler } from '@onflay/webhooks/next';

export const POST = createNextWebhookHandler({
  secret: process.env.ONFLAY_WEBHOOK_SECRET!,
  onEvent: async (event) => {
    switch (event.type) {
      case 'invoice.paid': {
        const { customerId, totalInCents, currency, periodStart, periodEnd } = event.data;
        // Activa acceso, registra el cobro en tu base de datos, etc.
        break;
      }
      case 'invoice.payment_failed': {
        const { customerId } = event.data;
        // Notifica al cliente o activa lógica de reintento.
        break;
      }
    }
  },
});
```

***

## Pruebas en sandbox

<Steps>
  <Step title="Agrega una tarjeta de prueba">
    En sandbox, cuando el cliente accede a la página de `hostedUrl`, usa la tarjeta de prueba de Stripe `4242 4242 4242 4242` con cualquier fecha futura y CVC.
  </Step>

  <Step title="Envía una factura de prueba">
    ```ts theme={"dark"}
    const onflay = new Onflay('sk_test_...');

    const invoice = await onflay.invoices.create({
      customerId: idClienteSandbox,
      currency: 'usd',
      lineItems: [{ description: 'Cargo de prueba por uso', amountInCents: 100 }],
    });

    console.log(invoice.status); // 'paid'
    ```
  </Step>

  <Step title="Prueba los webhooks localmente">
    ```bash theme={"dark"}
    npx onflay listen --forward-to http://localhost:3000/api/webhooks/onflay
    ```

    Para simular un evento específico:

    ```bash theme={"dark"}
    npx onflay trigger invoice.paid
    npx onflay trigger invoice.payment_failed
    ```
  </Step>
</Steps>

***

## Referencia de errores

| Error                         | Causa                                    | Solución                                                         |
| ----------------------------- | ---------------------------------------- | ---------------------------------------------------------------- |
| `400` — sin método de pago    | El cliente no tiene tarjeta guardada     | Completa el flujo de SetupIntent primero                         |
| `404` — cliente no encontrado | El `customerId` no pertenece a tu cuenta | Verifica el ID o crea el cliente con `onflay.customers.create()` |
| `409` — idempotencia          | Ya existe una factura con esa key        | Seguro ignorar — devuelve la factura original                    |
| `402` — pago fallido          | Stripe rechazó el cobro                  | Notifica al cliente y espera `invoice.payment_failed`            |
