# Gredio API — Documentación

> La API de Gredio permite subir audios, procesarlos con modelos de diarización y recuperar los resultados segmentados por interlocutor. El flujo es: crear job → subir audios → iniciar procesamiento → esperar → descargar resultados.

Base URL: `https://api.grediolabs.com/goia/v1`

Los ejemplos usan Bash y curl. Define GREDIO_API_KEY con tu clave real y sustituye job_abc123def456 por el job_id de la respuesta. En PowerShell, usa curl.exe y adapta las variables y los saltos de línea.
```bash
read -rsp "API key: " GREDIO_API_KEY; export GREDIO_API_KEY; echo
```

Espera a que status sea completed antes de descargar. Consulta el estado cada 15 segundos. Si /start devuelve 503, consulta el job: si sigue created, reintenta más tarde; si está failed, crea otro job. Si la respuesta de /start se pierde o agota el tiempo de espera, consulta primero el job antes de repetir la petición.

## Quick start

### 1. Crear un job
El nombre es obligatorio. `callback_url` es opcional.
```bash
curl -X POST https://api.grediolabs.com/goia/v1/jobs \
  -H "Authorization: Bearer $GREDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "mi job"}'
```

### 2. Subir audios
Formatos: WAV, MP3, OGG, FLAC, M4A, OPUS, WEBM. Máximo 500 MB y 4 h por archivo. Mínimo 30 s.
```bash
curl -X POST https://api.grediolabs.com/goia/v1/jobs/job_abc123def456/audios \
  -H "Authorization: Bearer $GREDIO_API_KEY" \
  -F "file=@audio.mp3"
```

### 3. Estimar coste (opcional)
```bash
curl "https://api.grediolabs.com/goia/v1/jobs/job_abc123def456/estimate?model=base" \
  -H "Authorization: Bearer $GREDIO_API_KEY"
```

### 4. Iniciar el procesamiento
```bash
curl -X POST https://api.grediolabs.com/goia/v1/jobs/job_abc123def456/start \
  -H "Authorization: Bearer $GREDIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "base"}'
```

### 5. Consultar estado
```bash
curl "https://api.grediolabs.com/goia/v1/jobs/job_abc123def456" \
  -H "Authorization: Bearer $GREDIO_API_KEY"
```

### 6. Descargar resultados
```bash
curl "https://api.grediolabs.com/goia/v1/jobs/job_abc123def456/results" \
  -H "Authorization: Bearer $GREDIO_API_KEY"
```

## Autenticación

Todas las llamadas requieren una API key en la cabecera `Authorization` con formato Bearer.
```
Authorization: Bearer sk_...
```
Puedes crear y gestionar tus API keys desde Ajustes → API Keys. Cada key se muestra solo una vez al crearla y puede tener fecha de caducidad opcional.

Los créditos son de tu **cuenta**, no de una key concreta. Puedes crear nuevas keys sin perder el saldo.

### Códigos de error comunes

| Código | Significado |
|---|---|
| `401` | API key inválida, revocada o expirada |
| `402` | Créditos insuficientes para iniciar el job |
| `413` | Archivo de audio demasiado grande (máx. 500 MB) |
| `422` | Datos inválidos — formato no permitido o duración < 30 s |
| `429` | Rate limit: 60 req/min general · 10 req/min en /start |
| `503` | Sin capacidad GPU. Consulta el estado: reintenta si sigue created; si está failed, crea un nuevo job. |

## Jobs

Un job es la unidad de trabajo. Puede contener hasta 1000 audios y se procesa de forma asíncrona.

| Método | Endpoint | Descripción |
|---|---|---|
| `GET` | `/jobs` | Listar jobs. Paginación cursor: ?limit y ?start_after |
| `POST` | `/jobs` | Crear job. Body: {name, callback_url?}. name es obligatorio. |
| `GET` | `/jobs/{job_id}` | Detalle de un job con sus audios |
| `POST` | `/jobs/{job_id}/audios` | Subir un audio (multipart/form-data, campo 'file') |
| `GET` | `/jobs/{job_id}/estimate` | Estimar coste. Query: ?model=base\|nano |
| `POST` | `/jobs/{job_id}/start` | Iniciar procesamiento. Reserva créditos y lanza VM. |
| `GET` | `/jobs/{job_id}/results` | Consultar resultados. Comprueba status=completed antes de usarlos. |

### Modelos disponibles

| Modelo | Precio | Descripción |
|---|---|---|
| `base` | 0,0006 €/min | Mayor precisión. Recomendado para producción. |
| `nano` | 0,00042 €/min | Más rápido y económico. Bueno para borradores. |

### Parámetros de /start
```json
{
  "model": "base",
  "use_hysteresis": true,
  "onset": 0.55,
  "offset": 0.35,
  "use_smoothing": true,
  "median_kernel": 5,
  "use_fill_gaps": true,
  "max_gap_seconds": 0.2,
  "use_remove_short": true,
  "min_segment_seconds": 0.2,
  "use_pad": false,
  "pad_seconds": 0,
  "use_suppress_pre": true,
  "suppress_inactive_pre_seconds": 1,
  "use_suppress_post": true,
  "suppress_inactive_post_seconds": 0.5
}
```
El webhook (`callback_url`) solo se puede fijar al crear el job — no es un parámetro de `/start`.

### Límites

| Límite | Valor |
|---|---|
| Tamaño máximo por archivo | `500 MB` |
| Duración mínima | `30 s` |
| Duración máxima | `4 h (14 400 s)` |
| Audios por job | `1000` |
| Jobs concurrentes | `3 simultáneos por defecto` |
| Retención de resultados | `30 días desde que completa` |
| Coste mínimo por job | `0.08 cr` |

### Webhook
Si pasas `callback_url` al crear el job, la API enviará un POST cuando complete o falle. La URL debe usar **HTTPS** y apuntar a un servidor público.
```json
{
  "job_id": "job_abc123def456",
  "status": "completed",
  "client_id": "client_xyz789",
  "processed_count": 2,
  "failed_count": 0,
  "error_message": null
}
```

## Estados de un job

Un job pasa por los siguientes estados desde que se crea hasta que finaliza.

- **created — Creado** — El job existe en el sistema y acepta audios. Puedes seguir subiendo archivos con POST /jobs/{id}/audios. Ningún recurso de cómputo está asignado todavía.
- **starting — Iniciando** — La API ha reservado los créditos y está preparando el procesamiento. El arranque puede tardar varios minutos; consulta el estado cada 15 segundos.
- **processing — Procesando** — La VM GPU está activa y diarizando los audios. El tiempo depende de la duración total del audio y el modelo elegido.
- **completed — Completado** — El job ha finalizado. Revisa processed_count y failed_count para detectar fallos parciales. Descarga los resultados antes de que expiren, a los 30 días.
- **failed — Fallido** — El procesamiento ha fallado. Los créditos reservados son liberados automáticamente — no se cobra nada. Puedes crear un nuevo job e intentarlo de nuevo.

Se puede llegar aquí desde **starting** (sin capacidad de GPU u otro error de lanzamiento), desde **processing** (falló el procesamiento), o por **timeout** (más de 2h sin avanzar). Los créditos reservados siempre se liberan — nunca se cobra un job fallido.

### Polling vs. Webhook
Puedes consultar el estado haciendo polling a `GET /jobs/{job_id}` cada pocos segundos, o configurar un `callback_url` al crear el job para recibir una notificación automática al finalizar. El webhook es más eficiente para producción.

## Resultados

Una vez el job está en `completed`, recupera los segmentos de diarización con `GET /jobs/{job_id}/results`.
```json
{
  "job_id": "job_abc123def456",
  "status": "completed",
  "total": 1,
  "results": [
    {
      "audio_id": "audio_xyz789",
      "original_filename": "audio.mp3",
      "result": {
        "num_speakers": 2,
        "segments": [
          { "speaker": "SPEAKER_00", "start": 0.0,  "end": 4.2  },
          { "speaker": "SPEAKER_01", "start": 4.5,  "end": 11.3 }
        ]
      }
    }
  ]
}
```

### Campos del resultado

| Campo | Tipo | Descripción |
|---|---|---|
| `num_speakers` | `int` | Número de interlocutores detectados |
| `segments` | `array` | Segmentos ordenados por tiempo de inicio |
| `speaker` | `string` | ID del interlocutor (SPEAKER_00, SPEAKER_01…) |
| `start` | `float` | Tiempo de inicio del segmento en segundos |
| `end` | `float` | Tiempo de fin del segmento en segundos |

> ⚠ Los resultados están disponibles durante **30 días** desde que el job completa. Descarga o persiste los datos antes de que expiren.

## Facturación

| Método | Endpoint | Descripción |
|---|---|---|
| `GET` | `/me` | Saldo actual, créditos reservados y consumidos |
| `GET` | `/me/api-keys` | Listar tus API keys con estado y caducidad |
| `POST` | `/me/api-keys` | Crear nueva API key. Body: {name, expires_at?} |
| `DELETE` | `/me/api-keys/{hash}` | Revocar una API key (no puedes revocar la última activa) |
| `GET` | `/me/transactions` | Historial de transacciones paginado |
| `GET` | `/usage` | Estadísticas: jobs completados, duración y consumo |

### 1 crédito = 1 EUR
Los créditos pertenecen a tu cuenta. El coste depende de la duración del audio y el modelo, con un mínimo de 0,08 créditos por job. Crear o revocar claves no cambia el saldo.

## Ciclo de vida de los créditos

Cada movimiento de créditos queda registrado en el historial de transacciones.

- **1. Recarga (topup)** (`topup`) — El administrador asigna créditos a tu cuenta. El saldo disponible aumenta.
- **2. Reserva (reserve)** (`reserve`) — Al iniciar un job se reservan los créditos estimados (duración × precio/segundo). El saldo baja pero los créditos están "congelados", no consumidos todavía.
- **3a. Cargo (charge)** (`charge`) — Cuando el job completa con éxito, se cobra exactamente lo reservado — el coste se basa en la duración del audio (fija desde que se subió), no en cuánto tardó la GPU en procesarlo.
- **3b. Liberación (release)** (`release`) — Si el job falla (por cualquier motivo), los créditos reservados se liberan completamente. No se cobra nada.

### Ejemplo numérico
```
Saldo inicial:  10.0000 cr
Job de 10 000 s con modelo base (1e-5 cr/s → 0.1000 cr):

  reserve:  -0.1000  →  disponible: 9.9000  (reservados: 0.1000)
  [el job completa con éxito]
  charge:   -0.1000  →  disponible: 9.9000  (se cobra exactamente lo reservado)
  lifetime  += 0.1000

Si el job hubiera fallado:
  release:  +0.1000  →  disponible: 10.0000  (sin cargo)

Nota: si duración × precio/s es menor que el mínimo por job (0.08 cr),
se reserva y cobra ese mínimo en su lugar (ver sección "Límites" en Jobs).
```
