# Autenticación

Toda llamada que ejecuta un modelo o lee tus solicitudes necesita una clave de API. El catálogo (`GET /models`,
`GET /categories`), `POST /quote` y el documento OpenAPI son públicos.

## Claves de API

Crea y revoca claves en [https://doitong.com/developers/dashboard#keys](https://doitong.com/developers/dashboard#keys). Una clave tiene el
formato `doitong_` seguido de 64 caracteres hexadecimales y solo se muestra una vez, al crearla. Envíala en la
cabecera `Authorization`:

```bash
curl https://api.doitong.com/v1/account -H "Authorization: Bearer $DOITONG_API_KEY"
```

`X-API-Key: <key>` también funciona.

> [!WARNING]
> Guarda las claves en tu servidor: cualquiera que tenga una clave puede gastar los créditos de API que esta permite
> gastar. Si una clave se filtra, revócala y crea una nueva.

Una solicitud sin clave recibe `401` con el código `missing_api_key`; una clave desconocida, revocada o caducada
también recibe `401`.

## Ámbitos

Cada clave tiene ámbitos. La API de modelos comprueba estos:

| Acción | Ámbito necesario |
|---|---|
| Ejecutar un modelo, cancelar una solicitud, eliminar los archivos de una solicitud, cambiar el ajuste de almacenamiento | `models:run` (las claves con el antiguo `images:create` o `videos:create` también funcionan) |
| Crear una URL de carga | `models:run` o `media:upload` |
| Leer solicitudes y la cuenta | `models:read` (una clave que pueda ejecutar modelos también puede leer) |

Las claves nuevas obtienen `models:read` y `models:run` de forma predeterminada. Una llamada sin el ámbito adecuado
recibe `403` con el código `insufficient_scope`.

## Presupuestos de créditos

Una clave puede tener su propio presupuesto en créditos de API (1000 créditos de API = 1 $), establecido por el propietario de la
cuenta: un presupuesto total, un presupuesto diario (últimas 24 horas) o ambos. Antes de cobrar una ejecución, se
comprueba el coste frente a lo que la clave ya ha gastado mediante esta API (neto de reembolsos). Una ejecución que
superaría el límite se rechaza con `402 budget_exceeded` y no se cobra nada.

> [!IMPORTANT]
> El rechazo por presupuesto es definitivo: reintentarlo no servirá hasta que el propietario aumente el presupuesto.

 Una clave sin presupuesto puede
gastar hasta el saldo de API. Por separado, una ejecución que el saldo de API no pueda cubrir recibe `402
insufficient_credits` con un `top_up_url`.

`GET https://api.doitong.com/v1/account` muestra el saldo de API y el presupuesto restante de la clave (ambos en créditos de API):

```json 200 OK · account
{
  "object": "account",
  "credits": 125000,
  "balance": { "credits": 125000, "usd": "125.00" },
  "top_up_url": "https://doitong.com/developers/dashboard#balance",
  "key": {
    "name": "Production server",
    "prefix": "doitong_3fa9c1e...",
    "scopes": ["models:read", "models:run"],
    "budget_remaining": 50000,
    "rate_limit": 3600,
    "rate_limit_remaining": 3571
  },
  "webhook_signing_secret": "whsec_..."
}
```

`budget_remaining` es `null` cuando la clave no tiene un presupuesto propio.

## Límites de frecuencia

Cada clave puede realizar 3600 solicitudes por hora, salvo que su límite se haya establecido de otra forma. Toda
respuesta autenticada incluye el estado actual:

| Cabecera | Significado |
|---|---|
| `X-RateLimit-Limit` | Solicitudes permitidas en la ventana actual |
| `X-RateLimit-Remaining` | Solicitudes restantes en la ventana actual |
| `X-RateLimit-Reset` | Hora Unix en la que se reinicia la ventana |

Si superas el límite, recibes `429` con una cabecera `Retry-After` (segundos). La consulta prolongada con `?wait=`
cuenta como una solicitud por llamada, por lo que esperar es más barato que consultar rápidamente.

También hay un límite de 10 solicitudes en curso (`queued` o `running`) por cuenta. Iniciar una más devuelve `429
too_many_inflight`; vuelve a iniciarla cuando termine una.
