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

# Saldo y facturación

> Consulta tu saldo de crédito y compra recargas de manera programática.

Utiliza los endpoints de facturación de usuario para leer el saldo de crédito de tu equipo y comprar recargas con un método de pago guardado. Ambos endpoints requieren autenticación con tu [clave API](/get-started/authentication). Las claves inválidas devuelven **402**.

## Consulta el saldo de crédito

`GET /user/credits/info` devuelve el saldo de crédito del equipo autenticado, un desglose por lote, detalles de la suscripción activa y si se permite el uso.

Usa este endpoint para alimentar widgets de facturación, tableros de uso o verificaciones previas antes de ejecutar trabajos grandes.

Para detalles de la API, consulta [Obtener información de crédito](/api-reference/billing/credits-info).

<CodeGroup>
  ```python Python theme={null}
  import requests

  response = requests.get(
      "https://api.olostep.com/user/credits/info",
      headers={"Authorization": "Bearer <API-TOKEN>"},
  )
  print(response.json())
  ```

  ```js Node theme={null}
  const res = await fetch("https://api.olostep.com/user/credits/info", {
    headers: { Authorization: "Bearer <API-TOKEN>" },
  })
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s "https://api.olostep.com/user/credits/info" \
    -H "Authorization: Bearer <API-TOKEN>"
  ```
</CodeGroup>

### Respuesta

```json theme={null}
{
  "credits": 12500,
  "breakdown": [
    {
      "purchase_kind": "Subscription",
      "allocated_units": 10000,
      "remaining_units": 8500,
      "expiry_date": 1735689600
    },
    {
      "purchase_kind": "Top-up",
      "allocated_units": 5000,
      "remaining_units": 4000,
      "expiry_date": 1743465600
    }
  ],
  "active_subscription": {
    "id": "SUB_PRO",
    "display_name": "Pro",
    "credits": 10000,
    "created_at": 1704067200
  },
  "allow_usage": true
}
```

| Campo                 | Descripción                                                         |
| --------------------- | ------------------------------------------------------------------- |
| `credits`             | Créditos totales restantes en todos los lotes no vencidos           |
| `breakdown`           | Detalle por lote: tipo, unidades asignadas y restantes, vencimiento |
| `active_subscription` | Plan actual (se usa `SUB_BASE` si ninguno está activo)              |
| `allow_usage`         | Si el equipo aún puede consumir créditos                            |

Cada lote en `breakdown` tiene un `purchase_kind` de `Subscription`, `Top-up`, `Manual`, `Setup` o `Pending`.

## Compra una recarga

`POST /user/purchase-topup` carga una tarjeta guardada en Stripe y compra créditos en un solo paso. No hay redirección a Checkout ni interfaz de pago incrustada.

Pasa la cantidad de créditos en el cuerpo de la solicitud:

```json theme={null}
{ "credits": 10000 }
```

| Campo     | Descripción                  |
| --------- | ---------------------------- |
| `credits` | Número de créditos a comprar |

Valores soportados: **10,000**, **20,000**, **80,000**, y **100,000**.

Para detalles de la API, consulta [Compra de recarga](/api-reference/billing/purchase-topup).

<CodeGroup>
  ```python Python theme={null}
  import requests

  response = requests.post(
      "https://api.olostep.com/user/purchase-topup",
      headers={
          "Authorization": "Bearer <API-TOKEN>",
          "Content-Type": "application/json",
      },
      json={"credits": 10000},
  )
  print(response.status_code)
  print(response.json())
  ```

  ```js Node theme={null}
  const res = await fetch("https://api.olostep.com/user/purchase-topup", {
    method: "POST",
    headers: {
      Authorization: "Bearer <API-TOKEN>",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ credits: 10000 }),
  })
  console.log(res.status)
  console.log(await res.json())
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/user/purchase-topup" \
    -H "Authorization: Bearer <API-TOKEN>" \
    -H "Content-Type: application/json" \
    -d '{"credits": 10000}'
  ```
</CodeGroup>

### Requisitos

* El equipo debe tener un cliente de Stripe con al menos una tarjeta guardada.
* Solo se permite un intento de compra cada **60 segundos** por equipo. Si alcanzas el tiempo de espera, la respuesta es **429** con un encabezado `Retry-After`.

### Respuestas

**200** — pago exitoso:

```json theme={null}
{
  "success": true,
  "payment_intent_id": "pi_xxx",
  "credits": 10000
}
```

**202** — el pago aún se está procesando. Los créditos se añaden una vez que Stripe confirma el pago:

```json theme={null}
{
  "success": true,
  "status": "processing",
  "payment_intent_id": "pi_xxx",
  "message": "El pago está en proceso. Los créditos se añadirán una vez que el pago sea confirmado.",
  "credits": 10000
}
```

<Note>
  Los créditos se emiten por el webhook de Stripe después de la confirmación del pago, no directamente desde la respuesta HTTP. Trata **200** como éxito de pago; consulta `GET /user/credits/info` si necesitas confirmar el saldo actualizado.
</Note>

### Errores comunes

| Estado | Error                     | Cuándo                                                |
| ------ | ------------------------- | ----------------------------------------------------- |
| 400    | `missing_topup_selector`  | `credits` no fue enviado                              |
| 400    | `invalid_credits`         | La cantidad de créditos no está en la lista permitida |
| 400    | `no_stripe_customer`      | El equipo no tiene un cliente de Stripe               |
| 400    | `no_payment_method`       | No hay tarjeta guardada en el archivo                 |
| 402    | `payment_failed`          | Ninguna tarjeta guardada completó el cargo            |
| 429    | `purchase_topup_cooldown` | Se intentó otra compra dentro de los 60 segundos      |
| 503    | `payment_status_unknown`  | Error ambiguo de Stripe; espera antes de reintentar   |
