Exportar detalles de uso
Guía de exportación de uso de LMU AI: inicia sesión para obtener un JWT, luego llama a /api/v1/usage con paginación, rango de fechas y filtrado por modelo, con ejemplos en tres lenguajes.
Inicia sesión con tu cuenta y contraseña para obtener un JWT, luego usa ese JWT para llamar a /api/v1/usage y obtener la tabla completa de detalles de uso de tokens, idéntica a la página /usage de la consola.
Ideal para scripts de larga duración que automatizan la exportación, la conciliación y la carga en un BI empresarial — sin necesidad de descargar un CSV manualmente cada vez.
¿Por qué no puedes obtenerlo directamente con una clave API sk-...? La clave solo sirve para llamadas de negocio a través del gateway (/v1/messages, etc.) y no expone consultas de detalle a nivel de cuenta — esto es un diseño de seguridad deliberado: si una clave se filtra, no querrás que se vuelque toda tu factura. Los datos a nivel de cuenta deben usar autenticación de cuenta (JWT).
1. Resumen de la API
| Elemento | Valor |
|---|---|
| URL base | https://api.lmuai.com |
| Autenticación | Authorization: Bearer <access_token> (el JWT del inicio de sesión de la cuenta) |
| Validez del access token | 86400 segundos (24 horas), renovable con refresh_token |
| Formato de respuesta | JSON; code: 0 significa éxito, en caso de fallo code != 0 con un campo message |
| Uso recomendado | Exportación automatizada de facturación, carga en un BI empresarial, scripts de conciliación |
2. Paso 1 — Inicia sesión para obtener un JWT
POST /api/v1/auth/login
POST /api/v1/auth/login HTTP/1.1
Content-Type: application/json
{
"email": "your@email.com",
"password": "your-password"
}Respuesta (extracto):
{
"code": 0,
"message": "success",
"data": {
"access_token": "eyJhbGc...",
"refresh_token": "rt_756a220ffa...",
"expires_in": 86400,
"token_type": "Bearer",
"user": { "id": 3, "email": "...", "balance": 1575.13 }
}
}Todas las solicitudes posteriores simplemente incluyen Authorization: Bearer <access_token>.
3. Paso 2 — Obtén los detalles de uso
GET /api/v1/usage
GET /api/v1/usage?page=1&page_size=200&start_date=2026-06-01&end_date=2026-06-23&timezone=Asia/Shanghai
Authorization: Bearer <access_token>Parámetros de consulta
| Parámetro | Tipo | Requerido | Predeterminado | Descripción |
|---|---|---|---|---|
page | int | No | 1 | Número de página, empezando desde 1 |
page_size | int | No | 20 | Filas por página, se recomienda 200 (los valores excesivos se truncan) |
start_date | string | No | — | Fecha de inicio YYYY-MM-DD, interpretada según timezone |
end_date | string | No | — | Fecha final (incluye ese día) |
timezone | string | No | UTC | Zona horaria para interpretar los parámetros de fecha, p. ej. Asia/Shanghai; muy recomendable, de lo contrario los límites no coincidirán con tu hora local |
api_key_id | int | No | — | Ver los detalles de una sola clave (debe pertenecer al usuario actual) |
model | string | No | — | Filtrar por ID de modelo (p. ej. claude-sonnet-5) |
stream | bool | No | — | true solo para streaming, false solo para no streaming |
billing_type | int | No | — | Enum de tipo de facturación (ver más abajo) |
sort_by | string | No | created_at | Campo de ordenamiento |
sort_order | string | No | desc | asc o desc |
Estructura de la respuesta
{
"code": 0,
"message": "success",
"data": {
"items": [ { /* UsageLog */ }, ... ],
"total": 30423,
"page": 1,
"page_size": 200,
"pages": 153
}
}Los campos de paginación están en el nivel superior de data, no en el envoltorio exterior. El arreglo de detalles está en data.items — data en sí no es un arreglo.
Mapeo de campos de un solo registro
Estos corresponden exactamente a cada columna de la página /usage de la consola:
| Columna de la consola | Campo JSON | Tipo | Descripción |
|---|---|---|---|
| Modelo | model | string | El ID del modelo realmente facturado |
| Esfuerzo de razonamiento | reasoning_effort | string | null | low / medium / high / xhigh / max |
| Endpoint de entrada | inbound_endpoint | string | null | La ruta que llamó el cliente, p. ej. /v1/messages |
| Endpoint upstream | upstream_endpoint | string | null | La ruta upstream normalizada |
| Tipo de solicitud | request_type | string | chat / stream / responses / messages, etc. |
| Streaming | stream | bool | Si fue streaming |
| Modo de facturación | billing_mode | string | token / per_request / image / subscription |
| Tipo de facturación | billing_type | int | Enum de tipo de facturación |
| Multiplicador | rate_multiplier | float | El multiplicador del canal aplicado a esta solicitud |
| Tokens de entrada | input_tokens | int | |
| Tokens de salida | output_tokens | int | |
| Creación de caché | cache_creation_tokens | int | Todas las escrituras de caché |
| Creación de caché 5m | cache_creation_5m_tokens | int | Nivel efímero de 5 minutos de Anthropic |
| Creación de caché 1h | cache_creation_1h_tokens | int | Nivel de 1 hora de Anthropic |
| Lectura de caché | cache_read_tokens | int | |
| Costo de entrada | input_cost | float | USD |
| Costo de salida | output_cost | float | USD |
| Costo de creación de caché | cache_creation_cost | float | USD |
| Costo de lectura de caché | cache_read_cost | float | USD |
| Total a precio de lista | total_cost | float | USD, antes del multiplicador |
| Cargo real | actual_cost | float | = total_cost × rate_multiplier, lo que realmente se descuenta de tu saldo |
| Latencia del primer token | first_token_ms | int | null | TTFT, válido para streaming |
| Duración total | duration_ms | int | null | |
| Hora | created_at | ISO8601 | Hora de escritura del lado del servidor |
| ID de solicitud | request_id | string | Para resolución de problemas y trazabilidad |
| Generación de imágenes | image_count / image_size / image_output_tokens / image_output_cost | — | Se completa solo para solicitudes multimodales |
| API Key | api_key_id + objeto anidado api_key | int + obj | |
| Grupo | group_id + objeto anidado group | int + obj |
Cada registro lleva objetos anidados user / api_key / group (unos +1KB por fila). El objeto api_key contiene el texto completo de la clave — asegúrate de redactarlo en los logs / capturas de pantalla / CSVs de tus scripts; para exportaciones masivas, si no necesitas los objetos anidados, usa jq o mapeo de campos en el cliente para conservar solo los campos que necesitas.
Enum de tipo de facturación (billing_type)
| Valor | Significado |
|---|---|
0 | Facturado por token (la gran mayoría de las solicitudes) |
1 | Descontado de la cuota de una suscripción |
El campo billing_mode es la versión en cadena de texto, que describe el modelo de precios específico (token / per_request / image / subscription, etc.); es más legible y se recomienda para la categorización.
4. Renovación del token
El access token expira después de 24 horas. Hay dos formas de renovarlo:
Renovar con refresh_token (recomendado para scripts)
POST /api/v1/auth/refresh
Content-Type: application/json
{
"refresh_token": "rt_756a220ffa..."
}Devuelve un nuevo access_token (y normalmente también rota el refresh_token). El refresh token es válido durante 30 días.
Iniciar sesión de nuevo
Rudimentario pero simple, adecuado para scripts de un solo uso: llama a /auth/login de nuevo antes de cada ejecución.
5. Ejemplos de código
Bash + curl + jq
#!/usr/bin/env bash
set -e
EMAIL="${EMAIL:?set EMAIL env}"
PASSWORD="${PASSWORD:?set PASSWORD env}"
BASE="https://api.lmuai.com"
JWT=$(curl -s -X POST "$BASE/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d "{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}" \
| jq -r '.data.access_token')
[ -n "$JWT" ] && [ "$JWT" != "null" ] || { echo "login failed" >&2; exit 1; }
START="2026-06-01"; END="2026-06-30"; TZ="Asia/Shanghai"; PAGE_SIZE=200
# Fetch page 1 to get total
META=$(curl -s "$BASE/api/v1/usage?page=1&page_size=$PAGE_SIZE&start_date=$START&end_date=$END&timezone=$TZ" \
-H "Authorization: Bearer $JWT")
PAGES=$(echo "$META" | jq -r '.data.pages')
# CSV header
echo "created_at,model,request_type,input_tokens,output_tokens,cache_read_tokens,total_cost,actual_cost,duration_ms" > usage.csv
# Write page 1
echo "$META" | jq -r '.data.items[] | [.created_at, .model, .request_type, .input_tokens, .output_tokens, .cache_read_tokens, .total_cost, .actual_cost, .duration_ms] | @csv' >> usage.csv
# Fetch remaining pages
for ((p=2; p<=PAGES; p++)); do
curl -s "$BASE/api/v1/usage?page=$p&page_size=$PAGE_SIZE&start_date=$START&end_date=$END&timezone=$TZ" \
-H "Authorization: Bearer $JWT" \
| jq -r '.data.items[] | [.created_at, .model, .request_type, .input_tokens, .output_tokens, .cache_read_tokens, .total_cost, .actual_cost, .duration_ms] | @csv' >> usage.csv
done
echo "saved $(wc -l < usage.csv) lines to usage.csv"Python
import os, csv, requests
BASE = "https://api.lmuai.com"
EMAIL = os.environ["EMAIL"]
PASSWORD = os.environ["PASSWORD"]
def login() -> str:
r = requests.post(f"{BASE}/api/v1/auth/login",
json={"email": EMAIL, "password": PASSWORD},
timeout=15)
r.raise_for_status()
data = r.json()
if data["code"] != 0:
raise RuntimeError(data.get("message", "login failed"))
return data["data"]["access_token"]
def fetch_usage(jwt: str, **params):
"""Yield each row from paginated /usage endpoint."""
page = 1
while True:
r = requests.get(f"{BASE}/api/v1/usage",
headers={"Authorization": f"Bearer {jwt}"},
params={**params, "page": page, "page_size": 200},
timeout=30)
r.raise_for_status()
d = r.json()["data"]
for row in d.get("items", []):
yield row
if page >= d.get("pages", 1):
return
page += 1
if __name__ == "__main__":
jwt = login()
cols = ["created_at","model","request_type","input_tokens","output_tokens",
"cache_read_tokens","total_cost","actual_cost","duration_ms"]
with open("usage.csv", "w", newline="") as f:
w = csv.writer(f); w.writerow(cols)
for row in fetch_usage(jwt, start_date="2026-06-01", end_date="2026-06-30",
timezone="Asia/Shanghai"):
w.writerow([row.get(c) for c in cols])
print("done")Node.js
import fs from 'node:fs'
const BASE = 'https://api.lmuai.com'
const { EMAIL, PASSWORD } = process.env
async function login() {
const r = await fetch(`${BASE}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: EMAIL, password: PASSWORD }),
})
const j = await r.json()
if (j.code !== 0) throw new Error(j.message || 'login failed')
return j.data.access_token
}
async function* fetchUsage(jwt, params) {
for (let page = 1; ; page++) {
const q = new URLSearchParams({ ...params, page, page_size: '200' })
const r = await fetch(`${BASE}/api/v1/usage?${q}`, {
headers: { Authorization: `Bearer ${jwt}` },
})
const j = await r.json()
for (const row of j.data.items) yield row
if (page >= j.data.pages) return
}
}
const jwt = await login()
const cols = ['created_at','model','request_type','input_tokens','output_tokens',
'cache_read_tokens','total_cost','actual_cost','duration_ms']
const out = fs.createWriteStream('usage.csv')
out.write(cols.join(',') + '\n')
for await (const row of fetchUsage(jwt, {
start_date: '2026-06-01', end_date: '2026-06-30', timezone: 'Asia/Shanghai',
})) {
out.write(cols.map(c => JSON.stringify(row[c] ?? '')).join(',') + '\n')
}
console.log('done')6. Notas prácticas
- Agrega un retraso entre cambios de página masivos — al paginar N páginas seguidas, se recomienda
sleep(0.1~0.3s)para evitar activar los límites de tasa. - No obtengas un rango de tiempo demasiado largo de una vez — abarcar varios meses y millones de filas es lento. Segmentar por mes es más estable.
- Se recomienda un
page_sizede 200 — el servidor trunca los valores excesivos. - Ahorra ancho de banda — los objetos anidados
user/api_key/groupson grandes; si solo quieres las filas de detalle, fíltralas conjqen el cliente. - Errores comunes:
401JWT expirado → renueva conrefresh_tokeno inicia sesión de nuevo403Acceso no autorizado (p. ej. consultar la clave de otra persona víaapi_key_id) → verifica que la clave pertenezca al usuario actual400Parámetro incorrecto (p. ej. formato destart_date) → verifica queYYYY-MM-DD+timezonesean válidos
7. Recomendaciones de seguridad (lectura obligatoria)
Tu contraseña de cuenta + JWT equivalen a acceso completo a la cuenta. Antes de scriptear una exportación, asegúrate de:
| Elemento | Recomendación |
|---|---|
| Gestión de credenciales | Nunca comprometas la contraseña / access_token / refresh_token en git o en los logs de CI; usa variables de entorno, un gestor de secretos o .env (con .gitignore) |
| Seguridad de la cuenta | Se recomienda encarecidamente habilitar la autenticación de dos factores TOTP (habilítala en la configuración de la cuenta). Esta API admite la verificación TOTP durante el inicio de sesión |
| Rotación periódica | Cambia tu contraseña de cuenta regularmente; rota el refresh_token inmediatamente después de que expire |
| Monitoreo de anomalías | Vigila el "último inicio de sesión / IP" de la cuenta; cambia tu contraseña de inmediato si detectas un dispositivo desconocido |
| Redacción de campos | El api_key.key anidado (texto completo sk-...), user.email y refresh_token en la respuesta son todos campos sensibles — redáctalos antes de la salida / logs / CSV |
| Privilegio mínimo | Si puedes separarlas, usa una subcuenta dedicada para el script de exportación (si tu organización tiene una estructura multicuenta) para evitar la exposición prolongada de la cuenta principal |
| Reintentos ante errores | No reintentes indefinidamente ante un fallo de inicio de sesión — es fácil que active los controles de riesgo; se recomienda backoff exponencial |
8. Referencia rápida de campos
Útil para el mapeo de columnas de CSV:
| Etiqueta | Campo | Unidad |
|---|---|---|
| Modelo | model | — |
| Esfuerzo de razonamiento | reasoning_effort | — |
| Endpoint de entrada | inbound_endpoint | ruta |
| Endpoint upstream | upstream_endpoint | ruta |
| Tipo de solicitud | request_type | enum |
| Streaming | stream | bool |
| Modo de facturación | billing_mode | enum |
| Tipo de facturación | billing_type | int |
| Multiplicador | rate_multiplier | float |
| Tokens de entrada | input_tokens | int |
| Tokens de salida | output_tokens | int |
| Tokens de lectura de caché | cache_read_tokens | int |
| Tokens de escritura de caché | cache_creation_tokens | int |
| Escritura de caché 5m | cache_creation_5m_tokens | int |
| Escritura de caché 1h | cache_creation_1h_tokens | int |
| Costo de entrada | input_cost | USD |
| Costo de salida | output_cost | USD |
| Costo de creación de caché | cache_creation_cost | USD |
| Costo de lectura de caché | cache_read_cost | USD |
| Total a precio de lista | total_cost | USD |
| Cargo real | actual_cost | USD |
| Primer token | first_token_ms | ms |
| Duración total | duration_ms | ms |
| Hora | created_at | ISO8601 |
| ID de solicitud | request_id | string |
| Grupo | group_id / group.name | int / string |
| API Key | api_key_id / api_key.name | int / string |
Última actualización:
Consigue una clave de API de LMU AI y empieza a usar Claude, Codex y más
Registro gratuito y planes flexibles. Una sola clave API para Claude Code, Codex CLI, Cursor, la extensión de VS Code, OpenCode, Cherry Studio y otras herramientas de IA.
RegistrarseGemini Batch Image API
API de imágenes por lotes asíncrono de LMU AI: envía muchas tareas de imágenes Gemini a la vez, consulta el estado y los detalles, descarga imágenes o un ZIP, con idempotencia y estimaciones de costo.
Enterprise
Planes de API empresarial de LMU AI para Claude / GPT / Gemini: 6 SKU (Enterprise Standard + Flagship) en Anthropic y OpenAI, con contratos, facturas y soporte.